C++实现图的遍历和最短路径
摘自:https://blog.csdn.net/qq_45694646/article/details/106764026
C++实现图的基本操作
数据结构之图(存储,遍历,最短路径)
图是一种比线性表和树更为复杂的数据结构,它是“多对多”的关系。图(Graph)G是由两个集合V和E组成,记为G=(V,E)。
一、图的邻接矩阵存储
邻接矩阵法来表示图,需要用一个二维数组来存储邻接矩阵,一个一维数组来存储顶点信息。用邻接矩阵来存储图有它的优点也有它的缺点:
优点:容易实现图的操作,如:求某顶点的度、判断顶点之间是否有边、找顶点的邻接点等等。
缺点:n个顶点需要n*n个单元存储边;空间效率为O(n2)。 对稀疏图而言尤其浪费空间。
代码实现
#define MaxInt 32767 //表示极大值 即无穷大 #define MVNum 100 //最大顶点数 typedef string VerTexType; //设顶点的数据类型为string,需#include<string> typedef int ArcType; //设权值类型为整型 typedef struct { VerTexType vexs[MVNum]; //顶点表 ArcType arcs[MVNum][MVNum]; //邻接矩阵 int vexnum, arcnum; //图的当前点数和边数 }AMGraph;
二、用邻接矩阵来创建无向网
【算法思想】:
1.输入总顶点数和总边数
2.依次输入点的信息存入顶点表中
3.初始化邻接矩阵,使每个权值初始化为极大值
4.构造邻接矩阵
代码实现
bool CreateUDN(AMGraph& G) //采用邻接矩阵表示法,创建无向网 { int i, j, k ; VerTexType v1, v2; ArcType w; cout << "请输入图的顶点总数和边的总数:"; cin >> G.vexnum >> G.arcnum; //输入总顶点数,总边数 cout << "请依次输入顶点信息:" << endl; for (i = 0; i < G.vexnum; ++i) cin >> G.vexs[i]; //依次输入顶点信息 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大 cout << "请输入边的信息,格式:头,尾,权值" << endl; for (k = 0; k < G.arcnum; ++k) { cin >> v1 >> v2 >> w; //输入一条边依附的顶点及权值 i = LocateVex(G, v1);j= LocateVex(G, v2); //确定v1,v2在G中的位置,即顶点数组的下标 G.arcs[i][j] = w; //边<v1,v2>的权值为w G.arcs[j][i] = G.arcs[i][j]; //对称边 } return true; }
LocateVex()函数:查询顶点是否在顶点表中,若在则返回顶点表中的下标;否则返回-1
int LocateVex(AMGraph G, VerTexType u) {//存在则返回u在顶点表中的下标;否则返回-1 int i; for (i = 0; i < G.vexnum; ++i) if (u == G.vexs[i]) return i; return -1; }
输出无向网的信息
void PrintGraph(AMGraph G) { int i, j; cout << "图的邻接矩阵存储信息:" << endl; cout << "顶点信息:" << endl; for (i = 0; i < G.vexnum; i++) cout << i << ":" << G.vexs[i] << endl; //输出顶点信息 cout << "邻接矩阵数据:" << endl; for (i = 0; i < G.vexnum; i++) { for (j = 0; j < G.vexnum; j++) { if (G.arcs[i][j] == MaxInt) cout << left<<setw(6)<<"∞"; else cout << left<<setw(6) << G.arcs[i][j]; } cout << endl; } }
三、图的遍历
遍历的定义:从已给的连通图中某一顶点出发,沿着一些边访遍图中所有的顶点,且使每个顶点仅被访问一次,就叫做图的遍历,它是图的基本运算
遍历的实质:找每个顶点的邻接点的过程
1.深度优先遍历
简单归纳:
(1) 访问起始点v;
(2) 若v的第1个邻接点没访问过,深度遍历此邻接点;
(3) 若当前邻接点已访问过,再找v的第2个邻接点重新遍历
辅助数组:
避免重复访问,bool visited[MVNum];初值为false,若i被访问,则改visited[i]=true;
代码实现:
void DFS_AM(AMGraph G, int v) //深度优先搜索遍历,从第v个顶点开始 { cout <<setw(8)<< G.vexs[v]; visited[v] = true; //访问第v个顶点,并置visited数组对应的值为true for (int w = 0; w < G.vexnum; w++) if ((G.arcs[v][w] != 0) && (!visited[w])) DFS_AM(G,w); //G.arcs[v][w] != 0表示w是v的邻接点,如果w未访问,则递归调用DFS_AM }
DFS算法效率分析:
(1)用邻接矩阵来表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度为O(n2)。
(2)用邻接表来表示图,虽然有 2e 个表结点,但只需扫描 e 个结点即可完成遍历,加上访问 n个头结点的时间,时间复杂度为O(n+e)
(3)结论:稠密图适于在邻接矩阵上进行深度遍历;稀疏图适于在邻接表上进行深度遍历。
2.广度优先遍历
简单归纳:
(1)在访问了起始点v之后,依次访问 v的邻接点
(2)然后再依次访问这些顶点中未被访问过的邻接点
(3)直到所有顶点都被访问过为止
辅助队列:
这里用的是链队列,用顺序队列(循环队列)也可以。
//队列的DAT// typedef int Elemtype; //BFS中队列存放的是图元素下标 typedef int Status; typedef struct QNode { Elemtype data; struct QNode* next; }*QueuePrt; typedef struct { QueuePrt front, rear; //指针形式的对头和队尾指针 }*LinkQueue;
要写出队列的基本操作函数: 初始化 Status InitQuene(LinkQueue q) ; 判空操作 bool QueueEmpty(LinkQueue Q) ; 入队操作 Status EnQueue(LinkQueue q, Elemtype e); 出队操作Status DeQueue(LinkQueue q, Elemtype* e); Status InitQuene(LinkQueue q) { if (NULL == q) { return -1; } q->front = NULL; q->rear = NULL; return 0; } bool QueueEmpty(LinkQueue Q) { if (NULL == Q) { return true; } if (NULL == Q->front) { return true; } return false; } Status EnQueue(LinkQueue q, Elemtype e) { QueuePrt QP = NULL; if (NULL == q) { return -1; } QP = (QueuePrt)calloc(1, sizeof(struct QNode)); QP->data = e; QP->next = NULL; if (NULL == q->front) { q->front = QP; q->rear = QP; } else { q->rear->next = QP; q->rear = QP; } return 0; } Status DeQueue(LinkQueue q, Elemtype *e) { QueuePrt QP = NULL; QueuePrt QP_prev = NULL; QueuePrt front = NULL; if (NULL == q || NULL == e) { return -1; } if (QueueEmpty(q)) { return 0; } if (NULL == q->front->next) { q->rear = NULL; } front = q->front; q->front = q->front->next; *e = front->data; free(front); return 0; }
void BFS(AMGraph G, int v) //广度优先遍历 { int i, j; LinkQueue Q; Q =(LinkQueue)malloc(sizeof(LinkQueue)); InitQuene(Q);//采用的是链队列 for (i = 0; i < G.vexnum; i++) visited[i] = false; for (i = 0; i < G.vexnum; i++) { if (visited[i] == false) { cout << setw(8) << G.vexs[v]; visited[v] = true; //访问第v个顶点,并置visited数组对应值为true EnQueue(Q, v); //v进队 while (!QueueEmpty(Q)) //队列非空 { DeQueue(Q, &i);//队头元素出队,并置为i for (j = 0; j < G.vexnum; j++) { if ((G.arcs[i][j] = !MaxInt || G.arcs[i][j] != 0) && visited[j] == false) {//检查i的所有邻接点 visited[j] = true; cout << setw(8) << G.vexs[j];//访问j EnQueue(Q, j);//j入队 } } } } } }
BFS算法效率分析:
(1)如果使用邻接矩阵,则BFS对于每一个被访问到的顶点,都要循环检测矩阵中的整整一行( n 个元素),总的时间代价为O(n2)。
(2)用邻接表来表示图,虽然有 2e 个表结点,但只需扫描 e 个结点即可完成遍历,加上访问 n个头结点的时间,时间复杂度为O(n+e)。
3.DFS与BFS算法效率比较
(1)空间复杂度相同,都是O(n)(借用了堆栈或队列);
(2)时间复杂度只与存储结构(邻接矩阵或邻接表)有关,而与搜索路径无关。
四、最短路径算法(Dijkstra算法)
最短路径:在带权有向图中A点(源点)到达B点(终点)的多条路径中,寻找一条各边权值之和最小的路径,即最短路径。
辅助结构:
数组S[n]:记录相应顶点是否已被确定最短距离
数组Dist[n]:记录源点到相应顶点路径长度
数组Path[n]:记录相应顶点的前驱顶点
【Dijkstra算法思想】
(1) 初始化:
● 将源点v0加到S中,即S[v0]=true
● 将v0到各个终点的最短路径长度初始化为权值,即Dist[i]=G.arcs[v0][vi]
● 如果v0和顶点vi之间有弧,则将vi的前驱置为v0,即Path[i]=v0,否则Path[i]=-1
(2) 循环n-1次执行以下操作:
● 选择下一条最短路径的终点vk,使得Dist[k]=Min{Dist[i]|vi∈V-S}
● 将vk加入到S中,即S[vk]=true
● 根据条件更新从v0出发到集合V-S上任一顶点的最短路径的长度,若条件Dist[k]+G.arcs[k][i]<Dist[i]成立,则更新Dist[i]=Dist[k]+G.arcs[k][i],同时更改vi的前驱为vk;Path[i]=k
算法思想:
算法流程图
Dijkstra算法代码实现:
int Dist[MVNum];//Dist存当前找到的最短路径长度 int Path[MVNum];//当前找到的最短路径最后一个中转顶点 bool S[MVNum];//标记当前是否已求出最短路径 void ShortestPath_DIJ(AMGraph G, int v0)//求有向网G的v0顶点到其余顶点的最短路径 { int n, v, i, w, min; n = G.vexnum;//顶点数 for (v = 0; v < n; v++) //n个顶点依次初始化 { S[v] = false;//S初始为空集 Dist[v] = G.arcs[v0][v];//将v0到各个终点的最短路径长度初始化为弧上的权值 if (Dist[v] < MaxInt) Path[v] = v0;//如果v0与v之间有弧,则将v的前驱置为v0 else Path[v] = -1;//无弧,置为-1 } S[v0] = true;//将v0加入S Dist[v0] = 0;//原点到原点 的距离为0 //******初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加入到S集 for (i = 1; i < n; i++)//n-1个顶点 { min = MaxInt; for (w = 0; w < n; w++) if (!S[w] && Dist[w] < min)//选择一条当前的最短路径,终点为v { v = w; min = Dist[w]; } S[v] = true;//将v加入S for (w = 0; w < n; ++w)//更新从v0出发到集合V-S上所有的最短路径长度 if (!S[w] && (Dist[v] + G.arcs[v][w]) < Dist[w]) { Dist[w] = Dist[v] + G.arcs[v][w];//更新D[w] Path[w] = v;//更改w的前驱为v } } }
显示函数1:输入起点和终点,输出最短路径
void DisplayPath(AMGraph G, int begin, int temp) { if (Path[temp] != -1) { DisplayPath(G, begin, Path[temp]); cout << G.vexs[Path[temp]] << "-->"; } }
显示函数2:输入源点,输出源点到其他各个顶点的最短路径
void PrintPath(AMGraph G, int v) { int i, j, w; int road[MVNum];//用于存储最短路径顶点的下标 for (i = 0; i < MVNum; i++)road[i] = -1; for (i = 0; i < G.vexnum; i++) { if ((S[i] == true) && (i != v)) { cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "的最短路径为:" << "\t\t"<<Dist[i] <<"\t\t"; cout << G.vexs[v] << "->"; w = Path[i];//最短路径途径的顶点 j = 0;//为实现逆转标记途径顶点数 while (w != v)//回溯途径顶点 { road[j] = w; j++; w = Path[w]; } for (j=j-1; j >= 0; j--)//输出最短路径 { cout << G.vexs[road[j]] << "->"; road[j] = -1; } cout << G.vexs[i] << endl; } else cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "不存在路径" << endl; } }
五、具体实验
main函数
int main() { AMGraph G; VerTexType start, destination; //声明起点和终点 int num_start, num_destination; //起点和终点在顶点表中的位置 VerTexType v; int num_v; int choose = -1; cout << "**********************************" << endl; cout << "* 1.创建图" << endl; cout << "* 2.显示图的信息" << endl; cout << "* 3.图的深度优先遍历" << endl; cout << "* 4.图的广度优先遍历" << endl; cout << "* 5.输入起点和终点,显示最短路径" << endl; cout << "* 6.显示源点到各个顶点的最短路径" << endl; cout << "* 7.退出" << endl; cout << "**********************************" << endl; while (choose != 0) { cout << "\n----------------------- \n"; cout<<"\n请输入操作序号:"; cin >> choose; cout << endl; switch (choose) { case 1: CreateUDN(G); break; case 2: PrintGraph(G); break; case 3: cout << "深度优先遍历:" << endl; DFS_AM(G, 0); break; case 4: cout << "广度优先遍历:" << endl; BFS(G); break; case 5: cout << "请依次输入起始点、终点名称:"; cin >> start >> destination; //计算起点与终点编号 num_start = LocateVex(G, start); num_destination = LocateVex(G, destination); ShortestPath_DIJ(G, num_start); cout << endl << "最短路径为:"; DisplayPath(G, num_start, num_destination); cout << G.vexs[num_destination] << endl; break; case 6: cout << "请输入源点:"; cin >> v; num_v = LocateVex(G, v); ShortestPath_DIJ(G, num_v); PrintPath(G, num_v); break; case 7: exit_1(); break; } } return 0; }
注:本文部分算法源自《数据结构(C语言版)》第二版 严蔚敏 人民邮电出版社
完整代码,测试通过。
// https://blog.csdn.net/qq_45694646/article/details/106764026 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include <sstream> #include <iostream> #include <iomanip> using namespace std; #define MaxInt 32767 //表示极大值 即无穷大 #define MVNum 100 //最大顶点数 typedef string VerTexType; //设顶点的数据类型为string,需#include<string> typedef int ArcType; //设权值类型为整型 typedef struct { VerTexType vexs[MVNum]; //顶点表 ArcType arcs[MVNum][MVNum]; //邻接矩阵 int vexnum, arcnum; //图的当前点数和边数 }AMGraph; int LocateVex(AMGraph G, VerTexType u); bool CreateUDN(AMGraph& G) //采用邻接矩阵表示法,创建无向网 { int i, j, k ; VerTexType v1, v2; ArcType w; cout << "请输入图的顶点总数和边的总数:"; cin >> G.vexnum >> G.arcnum; //输入总顶点数,总边数 cout << "请依次输入顶点信息:" << endl; for (i = 0; i < G.vexnum; ++i) cin >> G.vexs[i]; //依次输入顶点信息 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大 cout << "请输入边的信息,格式:头,尾,权值" << endl; for (k = 0; k < G.arcnum; ++k) { cin >> v1 >> v2 >> w; //输入一条边依附的顶点及权值 i = LocateVex(G, v1);j= LocateVex(G, v2); //确定v1,v2在G中的位置,即顶点数组的下标 G.arcs[i][j] = w; //边<v1,v2>的权值为w G.arcs[j][i] = G.arcs[i][j]; //对称边 } return true; } int LocateVex(AMGraph G, VerTexType u) {//存在则返回u在顶点表中的下标;否则返回-1 int i; for (i = 0; i < G.vexnum; ++i) if (u == G.vexs[i]) return i; return -1; } void PrintGraph(AMGraph G) { int i, j; cout << "图的邻接矩阵存储信息:" << endl; cout << "顶点信息:" << endl; for (i = 0; i < G.vexnum; i++) cout << i << ":" << G.vexs[i] << endl; //输出顶点信息 cout << "邻接矩阵数据:" << endl; for (i = 0; i < G.vexnum; i++) { for (j = 0; j < G.vexnum; j++) { if (G.arcs[i][j] == MaxInt) cout << left<<setw(6)<<"∞"; else cout << left<<setw(6) << G.arcs[i][j]; } cout << endl; } } bool visited[MVNum] = {false}; //顶点表 void DFS_AM(AMGraph G, int v) //深度优先搜索遍历,从第v个顶点开始 { cout <<setw(8)<< G.vexs[v]; visited[v] = true; //访问第v个顶点,并置visited数组对应的值为true for (int w = 0; w < G.vexnum; w++) if ((G.arcs[v][w] != 0) && (!visited[w])) DFS_AM(G,w); //G.arcs[v][w] != 0表示w是v的邻接点,如果w未访问,则递归调用DFS_AM } #if 1 //队列的DAT// typedef int Elemtype; //BFS中队列存放的是图元素下标 typedef int Status; typedef struct QNode { Elemtype data; struct QNode* next; }*QueuePrt; typedef struct { QueuePrt front, rear; //指针形式的对头和队尾指针 }LinkQueue_T; typedef struct LinkQueue_t{ QueuePrt front, rear; //指针形式的对头和队尾指针 }*LinkQueue; Status InitQuene(LinkQueue q) { if (NULL == q) { return -1; } q->front = NULL; q->rear = NULL; return 0; } bool QueueEmpty(LinkQueue Q) { if (NULL == Q) { return true; } if (NULL == Q->front) { return true; } return false; } Status EnQueue(LinkQueue q, Elemtype e) { QueuePrt QP = NULL; if (NULL == q) { return -1; } QP = (QueuePrt)calloc(1, sizeof(struct QNode)); QP->data = e; QP->next = NULL; if (NULL == q->front) { q->front = QP; q->rear = QP; } else { q->rear->next = QP; q->rear = QP; } return 0; } Status DeQueue(LinkQueue q, Elemtype *e) { QueuePrt QP = NULL; QueuePrt QP_prev = NULL; QueuePrt front = NULL; if (NULL == q || NULL == e) { return -1; } if (QueueEmpty(q)) { return 0; } if (NULL == q->front->next) { q->rear = NULL; } front = q->front; q->front = q->front->next; *e = front->data; free(front); return 0; } void BFS(AMGraph G, int v) //广度优先遍历 { int i = 0; int j = 0; LinkQueue Q = NULL; Q = (LinkQueue)calloc(1, sizeof(struct LinkQueue_t)); InitQuene(Q); // 采用的是链队列 for (i = 0; i < G.vexnum; i++) { visited[i] = false; } for (i = 0; i < G.vexnum; i++) { if (visited[i] == false) { cout << setw(8) << G.vexs[v]; visited[v] = true; //访问第v个顶点,并置visited数组对应值为true // cout << v << endl; EnQueue(Q, v); //v进队 while (!QueueEmpty(Q)) //队列非空 { DeQueue(Q, &i);//队头元素出队,并置为i // cout << "222" << endl; for (j = 0; j < G.vexnum; j++) { if ((G.arcs[i][j] != MaxInt && G.arcs[i][j] != 0) && visited[j] == false) {//检查i的所有邻接点 visited[j] = true; cout << setw(8) << G.vexs[j];//访问j EnQueue(Q, j);//j入队 } //cout << "231" << endl; } } } } } #endif int Dist[MVNum];//Dist存当前找到的最短路径长度 int Path[MVNum];//当前找到的最短路径最后一个中转顶点 bool S[MVNum];//标记当前是否已求出最短路径 void ShortestPath_DIJ(AMGraph G, int v0)//求有向网G的v0顶点到其余顶点的最短路径 { int n, v, i, w, min; n = G.vexnum;//顶点数 for (v = 0; v < n; v++) //n个顶点依次初始化 { S[v] = false;//S初始为空集 Dist[v] = G.arcs[v0][v];//将v0到各个终点的最短路径长度初始化为弧上的权值 if (Dist[v] < MaxInt) Path[v] = v0;//如果v0与v之间有弧,则将v的前驱置为v0 else Path[v] = -1;//无弧,置为-1 } S[v0] = true;//将v0加入S Dist[v0] = 0;//原点到原点 的距离为0 //******初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加入到S集 for (i = 1; i < n; i++)//n-1个顶点 { min = MaxInt; for (w = 0; w < n; w++) if (!S[w] && Dist[w] < min)//选择一条当前的最短路径,终点为v { v = w; min = Dist[w]; } S[v] = true;//将v加入S for (w = 0; w < n; ++w)//更新从v0出发到集合V-S上所有的最短路径长度 if (!S[w] && (Dist[v] + G.arcs[v][w]) < Dist[w]) { Dist[w] = Dist[v] + G.arcs[v][w];//更新D[w] Path[w] = v;//更改w的前驱为v } } } void DisplayPath(AMGraph G, int begin, int temp) { if (Path[temp] != -1) { DisplayPath(G, begin, Path[temp]); cout << G.vexs[Path[temp]] << "-->"; } } void PrintPath(AMGraph G, int v) { int i, j, w; int road[MVNum];//用于存储最短路径顶点的下标 for (i = 0; i < MVNum; i++)road[i] = -1; for (i = 0; i < G.vexnum; i++) { if ((S[i] == true) && (i != v)) { cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "的最短路径为:" << "\t\t"<<Dist[i] <<"\t\t"; cout << G.vexs[v] << "->"; w = Path[i];//最短路径途径的顶点 j = 0;//为实现逆转标记途径顶点数 while (w != v)//回溯途径顶点 { road[j] = w; j++; w = Path[w]; } for (j=j-1; j >= 0; j--)//输出最短路径 { cout << G.vexs[road[j]] << "->"; road[j] = -1; } cout << G.vexs[i] << endl; } else cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "不存在路径" << endl; } } Status add_edge(AMGraph &G, VerTexType v1, VerTexType v2, ArcType w) { int i = 0; int j = 0; i = LocateVex(G, v1);j= LocateVex(G, v2); //确定v1,v2在G中的位置,即顶点数组的下标 G.arcs[i][j] = w; //边<v1,v2>的权值为w G.arcs[j][i] = G.arcs[i][j]; //对称边 return 0; } bool CreateUDN_test(AMGraph& G) //采用邻接矩阵表示法,创建无向网 { int i, j ; //cout << "请输入图的顶点总数和边的总数:"; G.vexnum = 10; G.arcnum = 12; //输入总顶点数,总边数 //cout << "请依次输入顶点信息:" << endl; G.vexs[0] = "昆明"; G.vexs[1] = "成都"; G.vexs[2] = "西安"; G.vexs[3] = "郑州"; G.vexs[4] = "徐州"; G.vexs[5] = "上海"; G.vexs[6] = "南昌"; G.vexs[7] = "株洲"; G.vexs[8] = "贵阳"; G.vexs[9] = "武汉"; //依次输入顶点信息 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大 //cout << "请输入边的信息,格式:头,尾,权值" << endl; add_edge(G, "昆明", "成都", 1100); //输入一条边依附的顶点及权值 add_edge(G, "成都", "西安", 842 ); //输入一条边依附的顶点及权值 add_edge(G, "西安", "郑州", 511 ); //输入一条边依附的顶点及权值 add_edge(G, "郑州", "徐州", 349 ); //输入一条边依附的顶点及权值 add_edge(G, "徐州", "上海", 651 ); //输入一条边依附的顶点及权值 add_edge(G, "上海", "南昌", 825 ); //输入一条边依附的顶点及权值 add_edge(G, "南昌", "株洲", 367 ); //输入一条边依附的顶点及权值 add_edge(G, "株洲", "贵阳", 902 ); //输入一条边依附的顶点及权值 add_edge(G, "贵阳", "昆明", 639 ); //输入一条边依附的顶点及权值 add_edge(G, "成都", "贵阳", 967 ); //输入一条边依附的顶点及权值 add_edge(G, "郑州", "武汉", 534 ); //输入一条边依附的顶点及权值 add_edge(G, "武汉", "株洲", 409 ); //输入一条边依附的顶点及权值 return true; } bool CreateUDN_test2(AMGraph& G) //采用邻接矩阵表示法,创建无向网 { int i, j ; //cout << "请输入图的顶点总数和边的总数:"; G.vexnum = 10; G.arcnum = 12; //输入总顶点数,总边数 //cout << "请依次输入顶点信息:" << endl; G.vexs[0] = "西安"; G.vexs[1] = "郑州"; G.vexs[2] = "徐州"; G.vexs[3] = "上海"; G.vexs[4] = "南昌"; G.vexs[5] = "株洲"; G.vexs[6] = "贵阳"; G.vexs[7] = "昆明"; G.vexs[8] = "成都"; G.vexs[9] = "武汉"; //依次输入顶点信息 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大 //cout << "请输入边的信息,格式:头,尾,权值" << endl; add_edge(G, "西安", "郑州", 511 ); //输入一条边依附的顶点及权值 add_edge(G, "郑州", "徐州", 349 ); //输入一条边依附的顶点及权值 add_edge(G, "郑州", "武汉", 534 ); //输入一条边依附的顶点及权值 add_edge(G, "徐州", "上海", 651 ); //输入一条边依附的顶点及权值 add_edge(G, "上海", "南昌", 825 ); //输入一条边依附的顶点及权值 add_edge(G, "南昌", "株洲", 367 ); //输入一条边依附的顶点及权值 add_edge(G, "武汉", "株洲", 409 ); //输入一条边依附的顶点及权值 add_edge(G, "株洲", "贵阳", 902 ); //输入一条边依附的顶点及权值 add_edge(G, "贵阳", "昆明", 639 ); //输入一条边依附的顶点及权值 add_edge(G, "成都", "贵阳", 967 ); //输入一条边依附的顶点及权值 add_edge(G, "昆明", "成都", 1100); //输入一条边依附的顶点及权值 add_edge(G, "成都", "西安", 842 ); //输入一条边依附的顶点及权值 return true; } bool CreateUDN_test3(AMGraph& G) //采用邻接矩阵表示法,创建无向网 { int i, j ; //cout << "请输入图的顶点总数和边的总数:"; G.vexnum = 7; //输入总 顶点数 G.arcnum = 6; //输入总 边数 //cout << "请依次输入顶点信息:" << endl; G.vexs[0] = "A"; G.vexs[1] = "B"; G.vexs[2] = "C"; G.vexs[3] = "D"; G.vexs[4] = "E"; G.vexs[5] = "F"; G.vexs[6] = "C.1"; //依次输入顶点信息 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大 //cout << "请输入边的信息,格式:头,尾,权值" << endl; add_edge(G, "A", "B", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "B", "C", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "C", "D", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "D", "E", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "E", "F", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "C", "C.1", 1 ); //输入一条边依附的顶点及权值 return true; } bool CreateUDN_test4(AMGraph& G) //采用邻接矩阵表示法,创建无向网 { int i, j ; //cout << "请输入图的顶点总数和边的总数:"; G.vexnum = 10; //输入总 顶点数 G.arcnum = 9; //输入总 边数 //cout << "请依次输入顶点信息:" << endl; G.vexs[0] = "A"; G.vexs[1] = "B"; G.vexs[2] = "C"; G.vexs[3] = "D"; G.vexs[4] = "E"; G.vexs[5] = "F"; G.vexs[6] = "C.1"; G.vexs[7] = "C.2"; G.vexs[8] = "C.3"; G.vexs[9] = "C.1.1"; //依次输入顶点信息 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大 //cout << "请输入边的信息,格式:头,尾,权值" << endl; add_edge(G, "A", "B", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "B", "C", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "C", "D", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "D", "E", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "E", "F", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "C", "C.1", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "C.1", "C.2", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "C.2", "C.3", 1 ); //输入一条边依附的顶点及权值 add_edge(G, "C.1", "C.1.1", 1 ); //输入一条边依附的顶点及权值 return true; } int main(int argc, char *argv[]) { AMGraph G; VerTexType start, destination; //声明起点和终点 int num_start, num_destination; //起点和终点在顶点表中的位置 VerTexType v; int num_v; int choose = -1; cout << "**********************************" << endl; cout << "* 1.创建图" << endl; cout << "* 2.显示图的信息" << endl; cout << "* 3.图的深度优先遍历" << endl; cout << "* 4.图的广度优先遍历" << endl; cout << "* 5.输入起点和终点,显示最短路径" << endl; cout << "* 6.显示源点到各个顶点的最短路径" << endl; cout << "* 7.退出" << endl; cout << "**********************************" << endl; CreateUDN_test4(G); while (choose != 0) { cout << "\n----------------------- \n"; cout<<"\n请输入操作序号:"; cin >> choose; cout << endl; switch (choose) { case 1: CreateUDN(G); break; case 2: PrintGraph(G); break; case 3: cout << "深度优先遍历:" << endl; DFS_AM(G, 0); break; case 4: cout << "广度优先遍历:" << endl; BFS(G, 0); break; case 5: cout << "请依次输入起始点、终点名称:"; cin >> start >> destination; //计算起点与终点编号 num_start = LocateVex(G, start); num_destination = LocateVex(G, destination); ShortestPath_DIJ(G, num_start); cout << endl << "最短路径为:"; DisplayPath(G, num_start, num_destination); cout << G.vexs[num_destination] << endl; break; case 6: cout << "请输入源点:"; cin >> v; num_v = LocateVex(G, v); ShortestPath_DIJ(G, num_v); PrintPath(G, num_v); break; case 7: exit(0); break; } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2021-05-27 案例参考手册-第四章 Curses字符界面.docx
2021-05-27 读取键盘输入流改为原始模式
2016-05-27 打包静态库.a文件的方法(ar,ranlib,nm命令介绍)
2016-05-27 当下流行的分布式文件系统大阅兵