是大二上學期的數據結構與算法實驗題,代碼架構是老師給出的,具體實現是自己做的。當時用的教材是嚴蔚敏教授的《數據結構》。後面兩個代碼(stack.cpp,CirQueue.cpp)是老師給的,爲了調試方便也給貼一下。
主要實現瞭如下操作:
cout<<" 1---------無向圖的創建 2----------有向圖的創建"<<endl;
cout<<" 3---------無向圖的廣度與深度遍歷 4----------有向圖的廣度與深度遍歷"<<endl;
cout<<" 5---------無向圖判斷是否爲樹 8----------有向圖判斷路徑是否連通 "<<endl;
cout<<" 7---------無向圖判斷路徑是否連通 "<<endl;
#include <string>
#include <iostream>
#include "stack.cpp"
#include "CirQueue.cpp"
#define MAX 20
using namespace std;
struct ArcNode//邊數據
{
int adjvex;//該弧指向結點的位置 用於有向圖
int weight;//權值
struct ArcNode *nextarc;//指向下一條邊
};
template <class T>
struct VNode{//節點數據
T data;//節點值
ArcNode *firstarc;//指向邊
};
template <class T>
class ALGraph{
private:
VNode<T> vertices[MAX];//節點數組
int vexNum, arcNum;//存儲節點數與邊數
int visited[MAX];//訪問標誌位
int graph_type ; //圖的標誌 ( 0爲無向圖 1爲有向圖 )
int vex_degree[MAX];//記錄每個節點的度+1 爲判斷路徑作準備
public:
ALGraph() //構造函數
{
}
~ALGraph(){} //析構函數,釋放鄰接表中各邊表結點的存儲空間
void createDG(); //無向圖的創建操作算法
int locateVex(T v);
int firstAdjVex(int v);//找某頂點的第1個鄰接頂點
int nextAdjVex(int v, int w);//頂點相對於一鄰接頂點的下一鄰接頂點操作
void DFS(int v);//從下標爲v的頂點出發對圖進行深度優先遍歷
void DFSTraverse(); //深度優先遍歷圖
void BFS(int v,CirQueue<int> & que);//從下標爲v的頂點出發對圖進行廣度優先遍歷
void BFSTraverse();//廣度優先遍歷圖的算法
void createHDG(); //有向圖的創建操作算法
bool IsTree();//判斷一個無向圖G是否爲一棵樹
bool DFStree(int& v,int &);//輔助判斷
bool hasPath(T v, T w);// 判斷有向圖是否存在由頂點vi到vj的路徑
void hPath(int v, int w,int &);// 判斷有向圖是否存在由頂點vi到vj的路徑
};
template <class T>
void ALGraph<T>::createHDG() //有向圖的創建操作算法
{
//...
this->graph_type=0;//有向圖
T v1,v2;//元素數據
int i,j;//計數器
ArcNode *p;//邊數據
int flag=1;//必要時的標示位
cout<<"請輸入有向圖的節點數與邊數:"<<endl;
cin>>this->vexNum>>this->arcNum;
for(i=0;i<this->vexNum ;i++)//節點輸入
{
cout<<"請輸入第 "<<i+1<<" 個節點數據:"<<endl;
cin>>this->vertices[i].data;
this->vertices[i].firstarc=NULL;
}
for(i=0;i<this->arcNum ;i++)
{
if(flag==0)
{
cout<<"請確認輸入邊的起始點正確!"<<endl;
system("pause");
cout<<"請重輸!"<<endl;
i--;
}
cout<<"請輸入第 "<<i+1<<" 條邊:"<<endl;
cout<<"請輸入起點";
cin>>v1;
cout<<"請輸入終點";
cin>>v2;
p=new ArcNode ;
p->adjvex=this->locateVex(v2);//存儲下標位置
flag=0;
for(j=0;j<this->vexNum;j++)//搜索
{
if(v1==this->vertices[j].data)//掛鏈 注意判斷條件不要錯了 是v1啊啊啊啊
{
flag=1;
p->nextarc=this->vertices[j].firstarc;
this->vertices[j].firstarc=p;
break;
}
}
if(flag==0 && i>0)
{
cout<<"請確認輸入邊的起始點正確!"<<endl;
system("pause");
cout<<"請重輸!"<<endl;
i--;
}
}
cout<<"輸入完畢!"<<endl;
}
template <class T>
bool ALGraph<T>::IsTree()//判斷一個無向圖G是否爲一棵樹
{
//基於迴路指向的判斷
//原理 判斷任意一個節點是否有到其他所有節點的連通路徑 若不滿足則判斷這不是一棵樹
//若滿足則進一步利用類握手定理(假設 節點數:m 邊數:n 在簡單無向圖中有:m=n 簡單有向圖:m=n 這是樹與圖的臨界點 )判斷節點與邊的關係而得到其是否爲一棵樹
//可利用該原理進行進一步的判斷若其爲圖含有有幾個子圖
//連通情況下 在無向圖種若滿足 2m>n則爲樹 有向圖中若滿足m>n 則爲樹
//int m=this->vertices[]
int begin=0;//判斷該節點是否與其他所有節點都連通(此處選擇第一個節點進行判斷)
int i;
for(i=0;i<this->vexNum;i++)
{
if(!this->hasPath(this->vertices[begin].data,this->vertices[i].data))//若有一個不連通則可判斷這不是一棵樹
{
return false;
}
}
cout<<"都連通!"<<endl;
if(this->vexNum>this->arcNum )
{
return true;
}
else
{
return false;
}
}
template <class T>
void ALGraph<T>::hPath(int v, int w,int &flag)// 判斷有向圖是否存在由頂點vi到vj的路徑 輔助函數
{
if(v==w)
{
flag=1;
return ;
}
else
{
visited[v]=1;
ArcNode *p=vertices[v].firstarc;
if(p)
{
while(p)
{
if(!visited[p->adjvex] & !flag)
{
hPath(p->adjvex , w,flag);
}
p=p->nextarc;
}
}
}
}
template <class T>
bool ALGraph<T>::hasPath(T a, T b)// 判斷有向圖是否存在由頂點vi到vj的路徑
{
//...
int v,w;
int flag=0;
v=locateVex(a);
w=locateVex(b);
if(v<0||w<0 )
{
cout<<"沒有該路徑!"<<endl;
return false;
}
for(int i=0;i<this->vexNum ;i++)
{
this->visited[i]=0;
}
hPath(v , w,flag);
if(flag)
{
return true;
}
else
{
return false;
}
}
template <class T>
void ALGraph<T>::createDG() //無向圖的創建操作算法
{
this->graph_type=0;//無向圖
T v1, v2;
int i, j, k;
ArcNode *p;
cout << "輸入結點的總數:";
cin >> vexNum;
cout << "輸入邊的總數:";
cin >> arcNum;
for (i = 0; i<vexNum; ++i)
{
cout << "輸入第" << i + 1 << "個結點的數據:";
cin >> vertices[i].data;
vertices[i].firstarc = NULL;
}
for (k = 0; k<arcNum; ++k)
{
cout << "輸入第" << k + 1 << "邊:";
cout << "輸入起始結點:";
cin >> v1;
cout << " 輸入終止結點:";
cin >> v2;
if ((i = locateVex(v1)) == -1){ cout << "Error!"; return; }
if ((j = locateVex(v2)) == -1){ cout << "Error!"; return; }
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j;
p->nextarc = vertices[i].firstarc;
vertices[i].firstarc = p;
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = i;
p->nextarc = vertices[j].firstarc;
vertices[j].firstarc = p;
}
}
template <class T>
int ALGraph< T>::locateVex(T v)
{
int i;
for (i = 0; i < vexNum; i++)
{
if (vertices[i].data == v)
return i;
}
return -1;
}
template <class T>
int ALGraph< T>::firstAdjVex(int v)//找某頂點的第1個鄰接頂點
{
ArcNode *p;
p = vertices[v].firstarc;
if (p)
return p->adjvex;
else
return -1;
}
template <class T>
int ALGraph< T>::nextAdjVex(int v, int w)//頂點相對於一鄰接頂點的下一鄰接頂點操作
{
ArcNode *p;
p = vertices[v].firstarc;
while (p&&p->adjvex != w)
p = p->nextarc;
if (p&&p->nextarc)
return p->nextarc->adjvex;
else return -1;
}
template <class T>
void ALGraph< T>::DFS(int v)//從下標爲v的頂點出發對圖進行深度優先遍歷
{
cout << vertices[v].data;
cout << " ";
visited[v] = 1;
ArcNode *p=this->vertices[v].firstarc;
if(!p)
return;
while(p)
{
if (!visited[v])
{
DFS(p->adjvex );
}
p=p->nextarc ;
}
}
template <class T>
void ALGraph< T>::DFSTraverse() //深度優先遍歷圖
{
int i;
for (i = 0; i<vexNum; i++)
visited[i] = 0;
for (i = 0; i < vexNum; i++)
{
if (!visited[i])
DFS(i);
}
}
template <class T>
void ALGraph< T>::BFS(int v,CirQueue<int>& que)//從下標爲v的頂點出發對圖進行廣度優先遍歷
{
int u, w;
if(!visited[v])
{
cout << vertices[v].data;
cout << " ";
visited[v] = 1;
}
ArcNode *p=this->vertices[v].firstarc;
if(!p)
return;
while (p)
{
w=p->adjvex ;
if(!visited[w])
{
cout << vertices[w].data;
cout << " ";
visited[w] = 1;
}
que.EnQueue(w);
p=p->nextarc ;
}
w=que.DeQueue ();
if(!visited[w])
{
BFS(w, que);
}
}
template <class T>
void ALGraph< T>::BFSTraverse()//廣度優先遍歷圖的算法
{
int v;
CirQueue<int> que;
for (v = 0; v<vexNum; v++)
visited[v] = 0;
for (v = 0; v<vexNum; v++)
if (!visited[v])
BFS(v,que);
}
void manu_choice(ALGraph<char> &hgraph,ALGraph<char> &graph)
{
cout<<" 歡迎來到圖的操作"<<endl;
cout<<" 1---------無向圖的創建 2----------有向圖的創建"<<endl;
cout<<" 3---------無向圖的廣度與深度遍歷 4----------有向圖的廣度與深度遍歷"<<endl;
cout<<" 5---------無向圖判斷是否爲樹 8----------有向圖判斷路徑是否連通 "<<endl;
cout<<" 7---------無向圖判斷路徑是否連通 9---------清屏"<<endl;
cout<<" 10---------退出 "<<endl;
int choice;
char a,b;
while(1)
{
fflush(stdin);
cout<<" 請輸入菜單:";
cin>>choice;
if(!cin)//異常輸入處理
{
cin.clear();
while(cin.get()!='\n')
continue;
}
switch(choice)
{
case 1:
cout<<"無向圖的創建"<<endl;
graph.createDG();
break;
case 2:
cout<<"有向圖的創建"<<endl;
hgraph.createHDG ();
break;
case 3:
cout << "深度優先遍歷圖的結果爲:";
graph.DFSTraverse(); //遞歸深度優先遍歷
cout << "\n廣度優先遍歷圖的結果爲:" ;
graph.BFSTraverse();//廣度優先遍歷圖的算法
cout << endl;
break;
case 4:
cout << "深度優先遍歷圖的結果爲:";
hgraph.DFSTraverse(); //遞歸深度優先遍歷
cout << "\n廣度優先遍歷圖的結果爲:" ;
hgraph.BFSTraverse();//廣度優先遍歷圖的算法
cout << endl;
break;
case 5:
if(graph.IsTree ())
{
cout<<"這是一顆樹"<<endl;
}
else
{
cout<<"這不是一棵樹"<<endl;
}
break;
case 7:
cout << "輸入兩個元素判斷其是否連通:"<< endl ;
cin>>a>>b;
if(graph.hasPath (a,b))
{
cout<<a<<" "<<b<<" 間有路徑!"<<endl;
}
else
{
cout<<a<<" "<<b<<" 間沒有路徑!"<<endl;
}
break;
case 8:
cout << "輸入兩個元素判斷其是否連通:"<< endl ;
cin>>a>>b;
if(hgraph.hasPath (a,b))
{
cout<<a<<" "<<b<<" 間有路徑!"<<endl;
}
else
{
cout<<a<<" "<<b<<" 間沒有路徑!"<<endl;
}
break;
case 9:
system("cls");
manu_choice(hgraph,graph);
break;
case 10:
exit(0);
default:cout<<"錯誤輸入!"<<endl;
}
//system("pause");
}
}
void main()
{
ALGraph<char> graph;
ALGraph<char> hgraph;
manu_choice(hgraph ,graph);
}
CirQueue.cpp
//CirQueue.h
const int QueueSize = 100; //定義存儲隊列元素的數組的最大長度
template <class T> //定義模板類CirQueue
class CirQueue
{
public:
CirQueue(); //構造函數,置空隊
~CirQueue(); //析構函數
void EnQueue(T x); //將元素x入隊
T DeQueue(); //將隊頭元素出隊
T GetQueue(); //取隊頭元素(並不刪除)
bool Empty(); //判斷隊列是否爲空
private:
T data[QueueSize]; //存放隊列元素的數組
int front, rear; //隊頭和隊尾指針,分別指向隊頭元素的前一個位置和隊尾元素的位置
};
template <class T>
CirQueue<T>::CirQueue()
{
front = rear = 0;
}
/*
* 前置條件:隊列已存在
* 輸 入:無
* 功 能:銷燬隊列
* 輸 出:無
* 後置條件:釋放隊列所佔用的存儲空間
*/
template <class T>
CirQueue<T>::~CirQueue()
{
}
/*
* 前置條件:隊列已存在
* 輸 入:元素值x
* 功 能:在隊尾插入一個元素
* 輸 出:如果插入不成功,拋出異常
* 後置條件:如果插入成功,隊尾增加了一個元素
*/
template <class T>
void CirQueue<T>::EnQueue(T x)
{
if ((rear + 1) % QueueSize == front) throw "上溢";
rear = (rear + 1) % QueueSize; //隊尾指針在循環意義下加1
data[rear] = x; //在隊尾處插入元素
}
/*
* 前置條件:隊列已存在
* 輸 入:無
* 功 能:刪除隊頭元素
* 輸 出:如果刪除成功,返回被刪元素值,否則,拋出刪除異常
* 後置條件:如果刪除成功,隊頭減少了一個元素
*/
template <class T>
T CirQueue<T>::DeQueue()
{
if (rear == front) throw "下溢";
front = (front + 1) % QueueSize; //隊頭指針在循環意義下加1
return data[front]; //讀取並返回出隊前的隊頭元素,注意隊頭指針
}
//指向隊頭元素的前一個位置
/*
* 前置條件:隊列已存在
* 輸 入:無
* 功 能:讀取隊頭元素
* 輸 出:若隊列不空,返回隊頭元素
* 後置條件:隊列不變
*/
template <class T>
T CirQueue<T>::GetQueue()
{
int i;
if (rear == front) throw "下溢";
i = (front + 1) % QueueSize; //注意不要給隊頭指針賦值
return data[i];
}
/*
* 前置條件:隊列已存在
* 輸 入:無
* 功 能:判斷隊列是否爲空
* 輸 出:如果隊列爲空,返回1,否則,返回0
* 後置條件:隊列不變
*/
template <class T>
bool CirQueue<T>::Empty()
{
if (front == rear)
return 1;
else
return 0;
}
stack.cpp
template<class T>
class Stack
{
private:
T *base;
int top;
int size;
public:
//棧初始化
bool InitStack(int i)
{
size = i;
base = new T[size];
if (!base)
return false;
top = 0;
return true;
}
//判斷是否爲空
bool IsEmpty()
{
return(top == 0);
}
//判斷是否滿
bool IsFull()
{
return(top == size);
}
//雙倍擴容函數
bool DoubleSpace()
{
T *oldBase = base;
base = new T[size *= 2];
if (!base)
return false;
for (int i = 0; i<top; i++)
{
base[i] = oldBase[i];
}
delete[]oldBase;
return true;
}
//入棧
bool Push(T e)
{
if (IsFull())
{
if (!DoubleSpace())
return false;
}
base[top++] = e;
return true;
}
//出棧
bool Pop(T &e)
{
if (IsEmpty())
return false;
e = base[--top];
return true;
}
//取棧頂元素
T getTop()
{
return base[top-1];
}
int stack_search(T data)
{
for(int i=0;i<top;i++)
{
if(data==this->base[i])
{
return i;
}
}
return o;
}
};