有向网的邻接矩阵存储结构的设计与实现,要求:
(1)实现图的基本运算;求各个顶点的入度和出度;
(2)完成最短路径(Dijkstra和Floyd)和关键路径算法的实现。
主要代码如下:
#ifndef ADJMATRIXDIRGRAPH_H #define ADJMATRIXDIRGRAPH_H #include "Assistance.h" #include "LinkStack.h" #include "LinkQueue.h" #define infinity 10000 //有向图的邻接矩阵表示 template <class ElemType> class AdjMatrixDirGraph { protected: // 邻接矩阵的数据成员: int vexNum, vexMaxNum, arcNum; // 顶点数目、允许的顶点最大数目和边数 int **arcs; // 存放边信息邻接矩阵 ElemType *vertexes; // 存放顶点信息的数组 mutable Status *tag; // 标志数组 public: AdjMatrixDirGraph(ElemType es[], int vertexNum, int vertexMaxNum = DEFAULT_SIZE); // 以数组es[]为顶点,顶点个数为vertexNum,允许的顶点最大数目为vertexMaxNum,边数为0的有向图 AdjMatrixDirGraph(int vertexMaxNum = DEFAULT_SIZE); // 构造允许的顶点最大数目为vertexMaxNum,边数为0的无向图 ~AdjMatrixDirGraph(); //析构函数 void Clear(); // 清空图 bool IsEmpty(); // 判断无向图是否为空 int GetOrder(ElemType &d) const; // 求顶点的序号 Status GetElem(int i, ElemType &d) const; // 求顶点的元素值 Status SetElem(int i, const ElemType &d); // 设置顶点的元素值 int GetVexNum() const; // 返回顶点个数 int GetArcNum() const; // 返回边数 int FirstAdjVex(int i) const; // 返回顶点v的第一个邻接点 int NextAdjVex(int v1, int v2) const; // 返回顶点v1的相对于v2的下一个邻接点 int GetWeight(int v1, int v2) const; // 返回边的权值 void InsertVex(const ElemType &d); // 插入元素值为d的顶点 void InsertArc(int v1, int v2, int weight); // 插入顶点为v1和v2的边 void DeleteVex(const ElemType &d); // 删除元素值为d的顶点 void DeleteArc(int v1, int v2); // 删除顶点为v1和v2的边 Status GetTag(int v) const; // 返回顶点v的标志 void SetTag(int v, Status val) const; // 设置顶点v的标志为val AdjMatrixDirGraph(const AdjMatrixDirGraph<ElemType> &g); // 复制构造函数 AdjMatrixDirGraph<ElemType> &operator =(const AdjMatrixDirGraph<ElemType> &g); // 赋值语句重载 void Display(); // 显示邻接矩阵有向图 int InDegree(const ElemType &d); //求某一顶点的入度 int OutDegree(const ElemType &d); //求某一顶点的出度 void ShortestPathDij(const ElemType &d); //Dijkstra最短路径算法 void ShortesPathFloyed(); //Floyed算法求最短路径算法 void CriticalPath(); //求关键路径 }; // 有向图的邻接矩阵类的实现部分 template <class ElemType> AdjMatrixDirGraph<ElemType>::AdjMatrixDirGraph(ElemType es[], int vertexNum, int vertexMaxNum) { if(vertexNum < 0) throw Error("最大顶点数不能为负数!!!"); //抛出异常 if(vertexMaxNum < vertexNum) throw Error("输入的顶点数超过最大顶点数!!!"); vexNum = vertexNum; vexMaxNum = vertexMaxNum; arcNum = 0; vertexes = new ElemType[vexMaxNum]; tag = new Status[vexMaxNum]; arcs = new int *[vexMaxNum]; for(int i = 0; i < vexMaxNum; i++) arcs[i] = new int[vexMaxNum]; for (int i = 0; i < vexNum; i++) { vertexes[i] = es[i]; tag[i] = UNVISITED; for (int j = 0; j < vexNum; j++) { arcs[i][j] = infinity; //给定无穷值,表示两顶点之间无边相连 if(i == j) arcs[i][j] = 0; //对角线的值赋值为0,我们不考虑环,方便后续处理 } } } template <class ElemType> AdjMatrixDirGraph<ElemType>::AdjMatrixDirGraph(int vertexMaxNum) { if(vertexMaxNum < 0) throw Error("最大顶点数不能为负数!!!"); vexNum = 0; vexMaxNum = vertexMaxNum; arcNum = 0; vertexes = new ElemType[vexMaxNum]; tag = new Status[vexMaxNum]; arcs = new int*[vexMaxNum]; for(int i = 0; i < vexMaxNum; i++) { arcs[i] = new int[vexMaxNum]; } } template <class ElemType> void AdjMatrixDirGraph<ElemType>::Clear() { vexNum = 0; arcNum = 0; } template <class ElemType> bool AdjMatrixDirGraph<ElemType>::IsEmpty() //判断是否为空 { return vexNum = 0; } template <class ElemType> AdjMatrixDirGraph<ElemType>::~AdjMatrixDirGraph() //析构函数 { delete []vertexes; delete []tag; for(int i = 0; i < vexMaxNum; i++) { delete []arcs[i]; } delete []arcs; } template <class ElemType> int AdjMatrixDirGraph<ElemType>::GetOrder(ElemType &d) const //已知元素找序号 //求顶点序号,顶点信息在vertexes数组中,从中即可获得顶点的信息 { for(int i = 0; i < vexNum; i++) { if(vertexes[i] == d) return i; } return -1; } template <class ElemType> Status AdjMatrixDirGraph<ElemType>::GetElem(int i, ElemType &d) const //已知序号找元素 //求顶点的元素值,根据i的序号值,来找到对应元素 { if(i < 0 || i > vexNum) return NOT_PRESENT; //范围错误,返回元素不存在 else { d = vertexes[i]; return ENTRY_FOUND; } } template <class ElemType> Status AdjMatrixDirGraph<ElemType>::SetElem(int i, const ElemType &d) //根据顶点的序号,来重新设置该顶点的值 { if( i < 0 || i > vexNum) return RANGE_ERROR; else { vertexes[i] = d; return SUCCESS; } } template <class ElemType> int AdjMatrixDirGraph<ElemType>::GetVexNum() const //返回顶点数 { return vexNum; } template <class ElemType> int AdjMatrixDirGraph<ElemType>::GetArcNum() const //返回边数 { return arcNum; } template <class ElemType> int AdjMatrixDirGraph<ElemType>::FirstAdjVex(int i) const //返回顶点的第1个邻接点的序号 { if(i < 0 || i > vexNum) throw Error("输入不合法"); for(int j = 0; j < vexNum; i++) { if (arcs[i][j] != 0 && arcs[i][j] != infinity) { return j; } } } template <class ElemType> int AdjMatrixDirGraph<ElemType>::NextAdjVex(int v1, int v2) const //返回顶点v1相对于v2的下一个邻接点 { if(v1 < 0 || v1 >= vexNum) throw Error("v1不合法"); if(v2 < 0 || v2 >= vexNum) throw Error("v2不合法"); if(v1 == v2) throw Error("v1不能等于v2"); for(int i = v2 + 1; i < vexNum; i++) { if (arcs[v1][i] != 0 && arcs[v1][i] != infinity) { return i; } } return -1; } //返回边的权值 template <class ElemType> int AdjMatrixDirGraph<ElemType>::GetWeight(int v1, int v2) const { if(v1 < 0 || v1 >= vexNum) throw Error("v1不合法"); if(v2 < 0 || v2 >= vexNum) throw Error("v2不合法"); return arcs[v1][v2]; } template <class ElemType> void AdjMatrixDirGraph<ElemType>::InsertVex(const ElemType &d) //插入顶点d { if(vexNum == vexMaxNum) throw Error("顶点数已经达到最大值,无法继续插入元素"); vertexes[vexNum] = d; //这里将顶点信息记录到vertexes中 tag[vexNum] = UNVISITED; for(int i = 0; i < vexNum; i++) { arcs[vexNum][i] = infinity; arcs[i][vexNum] = infinity; } cout << " " << vexNum << endl; vexNum++; } template <class ElemType> void AdjMatrixDirGraph<ElemType>::InsertArc(int v1, int v2, int weight) //插入依附于顶点的边 { if (v1 < 0 || v1 >= vexNum) throw Error("v1不合法!!!"); if (v2 < 0 || v2 >= vexNum) throw Error("v2不合法!!!"); if (v1 == v2) throw Error("v1不能等于v2!!!"); if(arcs[v1][v2] == infinity) //原图中没有改变,则添加该边 { arcNum++; arcs[v1][v2] = weight; } } template <class ElemType> void AdjMatrixDirGraph<ElemType>::DeleteVex(const ElemType &d) //删除元素为d的顶点 { int i; for(i = 0; i < vexNum; i++) //遍历查询该点 { if(vertexes[i] == d) break; } if(i == vexNum) throw Error("不存在该点!!!"); for(int j = 0; j < vexNum; j++) { if(arcs[i][j] != infinity && i != j) { arcNum--; arcs[i][j] = infinity; arcs[j][i] = infinity; } } vexNum--; //用最后一行将空白行填充 if(i < vexNum) { vertexes[i] = vertexes[vexNum]; tag[i] = tag[vexNum]; for(int j = 0; j <= vexNum; j++) { arcs[i][j] = arcs[vexNum][j]; arcs[j][i] = arcs[j][vexNum]; } } } template <class ElemType> void AdjMatrixDirGraph<ElemType>::DeleteArc(int v1, int v2) //删除依附于顶点的边 { if (v1 < 0 || v1 >= vexNum) throw Error("v1不合法!"); if (v2 < 0 || v2 >= vexNum) throw Error("v2不合法!"); if (v1 == v2) throw Error("v1不能等于v2!"); if(arcs[v1][v2] != infinity && arcs[v1][v2] != 0) { arcNum--; arcs[v1][v2] = infinity; } } template <class ElemType> Status AdjMatrixDirGraph<ElemType>::GetTag(int v) const //返回顶点的标志 { if(v < 0 || v >= vexNum) throw Error("v不合法"); return tag[v]; } template <class ElemType> void AdjMatrixDirGraph<ElemType>::SetTag(int v, Status val) const { if(v < 0 || v >= vexNum) throw Error("v不合法"); tag[v] = val; } template <class ElemType> AdjMatrixDirGraph<ElemType>::AdjMatrixDirGraph(const AdjMatrixDirGraph<ElemType> &g) //赋值构造函数 { vexNum = g.vexNum; vexMaxNum = g.vexMaxNum; arcNum = g.arcNum; vertexes = new ElemType[vexMaxNum]; tag = new Status[vexMaxNum]; arcs = new int *[vexMaxNum]; for(int i = 0; i < vexMaxNum; i++) arcs[i] = new int[vexMaxNum]; for(int i = 0; i < vexNum; i++) { vertexes[i] = g.vertexes[i]; tag[i] = g.tag[i]; for(int j = 0; j < vexNum; j++) arcs[i][j] = g.arcs[i][j]; } } template <class ElemType> AdjMatrixDirGraph<ElemType> &AdjMatrixDirGraph<ElemType>::operator=(const AdjMatrixDirGraph<ElemType> &g) //赋值语句重载 { if(&g != this) { delete []vertexes; delete []tag; for(int i = 0; i < vexMaxNum; i++) delete []arcs[i]; delete []arcs; vexNum = g.vexNum; vexMaxNum = g.vexMaxNum; arcNum = g.arcNum; vertexes = new ElemType[vexMaxNum]; tag = new Status[vexMaxNum]; arcs = new int* [vexMaxNum]; for(int i = 0; i < vexMaxNum; i++) arcs[i] = new int[vexMaxNum]; for(int i = 0; i<vexNum; i++) //复制数据 { vertexes[i] = g.vertexes[i]; tag[i] = g.tag[i]; for(int j = 0; j < vexNum; j++) arcs[i][j] = g.arcs[i][j]; } } return *this; } template <class ElemType> void AdjMatrixDirGraph<ElemType>::Display() { cout << " " << "该有向图的邻接矩阵如下所示" << endl; for (int v = 0; v < vexNum; v++) cout << " " << vertexes[v]; cout << endl; for (int v = 0; v < vexNum; v++) { cout << vertexes[v]; for (int u = 0; u < vexNum; u++) { if(arcs[v][u] != infinity) cout << " " << arcs[v][u]; else cout << " " << "∞"; } cout << endl; } } //求图某点的入度 template <class ElemType> int AdjMatrixDirGraph<ElemType>::InDegree(const ElemType &d) { int i = -1; int count = 0; for(int j = 0; j < vexNum; j++) { if(vertexes[j] == d) i = j; } if(i == -1) return -1; for(int j = 0; j < vexNum; j++) if(i != j && arcs[j][i] != infinity) count++; return count; } //求图某点的出度 template <class ElemType> int AdjMatrixDirGraph<ElemType>::OutDegree(const ElemType &d) { int i = -1; int count = 0; for(int j = 0; j < vexNum; j++) { if(vertexes[j] == d) i = j; } if(i == -1) return -1; for(int j = 0; j < vexNum; j++) if(i != j && arcs[i][j] != infinity) count++; return count; } //求某一点最短路径 template <class ElemType> void AdjMatrixDirGraph<ElemType>::ShortestPathDij(const ElemType &d) { int v0 = -1; int count = 0; for(int j = 0; j < vexNum; j++) { if(vertexes[j] == d) v0 = j; } if(v0 == -1) { cout << "该点不存在,无法求出"; return ; } int path[vexNum];//设置path数组来存储前驱 int dist[vexNum];//设置dist数组来存储权值 int i, j, minVal; for(i = 0; i < vexNum; i++) { dist[i] = arcs[v0][i]; if(dist[i] == infinity || i == v0) path[i] = -1; else path[i] = v0; SetTag(i, UNVISITED); //将顶点标志设为未访问 } SetTag(v0, VISITED); //将v0点设置为未访问 for(int v = 0; v < vexNum; v++) { minVal = infinity; j = v0; for(i = 0; i < vexNum; i++) { if(GetTag(i) == UNVISITED && dist[i] < minVal)//根据顶点状态和权值大小判断是否执行 { j = i; minVal = dist[i]; } } SetTag(j, VISITED); for(i = 0; i < vexNum; i++) { if(GetTag(i) == UNVISITED && minVal + arcs[j][i] < dist[i]) { dist[i] = minVal + arcs[j][i]; path[i] = j; } } } //输出最大路径值 LinkStack<int> stack; int num; for(i = 0; i < vexNum; i++) { num = path[i]; if(i != v0) { while(i != v0 && num != -1) { stack.Push(num); num = path[num]; } if(dist[i] != infinity) cout << vertexes[v0] << "到" << vertexes[i] << "的最短路径为" << dist[i] << ",路径为"; else cout << vertexes[v0] << "到" << vertexes[i] << "的最短路径不存在"; while(!stack.IsEmpty()) { stack.Pop(num); cout << vertexes[num] << "->"; } cout << vertexes[i]; cout << endl; } } } //求全部顶点的最短路径 template <class ElemType> void AdjMatrixDirGraph<ElemType>::ShortesPathFloyed() { int path[vexNum][vexNum]; int dist[vexNum][vexNum]; for(int i = 0; i < vexNum; i++) { for(int j =0; j < vexNum; j++) { dist[i][j] = arcs[i][j]; if(i != j && dist[i][j] < infinity) path[i][j] = i; else path[i][j] = -1; } } for(int i = 0; i < vexNum; i++) for(int j = 0; j < vexNum; j++) for(int k =0; k <vexNum; k++) { if(dist[j][i] + dist[i][k] < dist[j][k]) { path[j][k] = i; dist[j][k] = dist[j][i] + dist[i][k]; } } cout << "各点的最短路径如下(∞表示不存在最短路径)" << endl; for(int i =0; i < vexNum; i++) cout << " " << vertexes[i]; cout << endl; for(int i =0; i < vexNum; i++) { cout << vertexes[i]; for(int j = 0; j < vexNum; j++) { if(dist[i][j] != infinity) cout << " " << dist[i][j]; else cout << " ∞"; } cout << endl; } } //求关键路径 template <class ElemType> void AdjMatrixDirGraph<ElemType>::CriticalPath() { int ve[vexNum], vl[vexNum]; int InDegree[vexNum]; //存储每个顶点的度数 LinkStack<int> stack; LinkQueue<int> queue; int count = 0; int temp, ae, al; //判断图中入度为 0 的顶点数,在求关键路径时,不能存在多个入度为 0 的顶点 for(int i = 0; i < vexNum; i++) { InDegree[i] = 0; //初始化 ve[i] = 0; for(int j =0; j < vexNum; j++) { if(arcs[j][i] != infinity && i != j) { InDegree[i]++; } } } for(int i = 0; i < vexNum; i++) { if(InDegree[i] == 0) { count++; queue.EnQueue(i); } } if(count != 1) { cout << "无法求关键路径,该图中有多条入度为 0 或者不存在入度为 0 的顶点" << endl;; return ; } count = 0; while(!queue.IsEmpty()) { queue.DelQueue(temp); stack.Push(temp); count++; for(int i = 0; i < vexNum; i++) { if(arcs[temp][i] != infinity && arcs[temp][i] && --InDegree[i] == 0) { queue.EnQueue(i); } if(arcs[temp][i] != infinity && arcs[temp][i] && ve[temp] + arcs[temp][i] > ve[i]) ve[i] = ve[temp] + arcs[temp][i]; } } if(count < vexNum) { cout << "该图中存在回路,无法求关键路径" << endl; return ; } stack.Top(temp); //这一步算是关键点,假想空的这个数组里面的元素无限大,后面进来的元素才能进入 for(int i = 0; i < vexNum; i++)//****初始化,将所有值赋为最大值**** vl[i] = ve[temp]; while(!stack.IsEmpty()) { stack.Pop(temp); for(int i = 0; i < vexNum; i++) { if(arcs[temp][i] != infinity && vl[i] - arcs[temp][i] < vl[temp]) //注意判断不能出错 { vl[temp] = vl[i] - arcs[temp][i]; } } } for(int i = 0; i < vexNum; i++) { for(int j = 0; j < vexNum; j++)//遍历寻找i的下一结点,并构成边 { if(arcs[i][j] != infinity && i != j) { ae = ve[i]; al = vl[j] - arcs[i][j]; if(ae == al) { cout << "<" << vertexes[i] << "," << vertexes[j] << "> "; } } } } cout << endl; } #endif
测试文件:
#include "AdjMatrixDirGraph.h" #include <iostream> using namespace std; int main() { try { int flag = 1; char item; char items[7] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int weight[7][7]= { { 0, 3, 2, 6, infinity, infinity, infinity}, {infinity, 0, infinity, 2, 4, infinity, infinity}, {infinity, infinity, 0, 1, infinity, 3, infinity}, {infinity, infinity, infinity, 0, 1, infinity, infinity}, {infinity, infinity, infinity, infinity, 0, infinity, 3}, {infinity, infinity, infinity, infinity, infinity, 0, 4}, {infinity, infinity, infinity, infinity, infinity, infinity, 0} }; AdjMatrixDirGraph<char> g(items, 7, 7); for(int i = 0; i < 7; i++) for(int j = 0; j < 7; j++) { if(i != j && weight[i][j] != infinity) g.InsertArc(i, j, weight[i][j]); } g.Display(); system("pause"); cout << endl; while(flag) { cout << "请输入一个顶点元素,以求其出入度(注意大小写): "; cin >> item; if(g.InDegree(item) != -1) { cout << "该点的入度为:" << g.InDegree(item) << endl; cout << "该点的出度为:" << g.OutDegree(item) << endl; flag = 0; } else cout << "该顶点不存在!!!请重新输入!!!" << endl; } system("pause"); cout << endl; cout << "输入一个顶点,求该顶点到其他顶点的最短路径(注意大小写):"; cin >> item; g.ShortestPathDij(item); system("pause"); cout << endl; g.ShortesPathFloyed(); system("pause"); cout << endl; cout << "该图的关键路径为" << endl; g.CriticalPath(); system("pause"); } catch (Error err) // 捕捉并处理异常 { err.Show(); // 显示异常信息 } return 0; }