
第六章 图 —— 邻接矩阵/邻接表构造图实现BFS/DFS/Dijkstra算法
发布日期:2021-05-06 10:56:22
浏览次数:22
分类:精选文章
本文共 7969 字,大约阅读时间需要 26 分钟。
第六章 图 —— 邻接矩阵/邻接表构造图实现BFS/DFS/Dijkstra算法
要求:
(1)采用邻接矩阵/邻接表建立图; (2)采用深度优先/广度优先搜索方式遍历图; (3)编程实现Dijkstra最短路径算法。此处均以无向图为例
邻接矩阵:
代码如下:
#include#include #include #include #define MaxVerNum 100 //顶点最大数目值#define VexType char //顶点数据类型#define EdgeType int //边数据类型,无向图时邻接矩阵对称,有权值时表示权值,没有时1连0不连#define INF 0x3f3f3f3f//作为最大值using namespace std;//图的数据结构typedef struct Graph{ VexType Vex[MaxVerNum];//顶点表 EdgeType Edge[MaxVerNum][MaxVerNum];//边表 int vexnum, arcnum;//顶点数、边数} Graph;//迪杰斯特拉算法全局变量bool S[MaxVerNum]; //顶点集int D[MaxVerNum]; //到各个顶点的最短路径int Pr[MaxVerNum]; //记录前驱//初始化函数void InitGraph(Graph& G){ memset(G.Vex, '#', sizeof(G.Vex));//初始化顶点表 //初始化边表 for (int i = 0; i < MaxVerNum; i++) for (int j = 0; j < MaxVerNum; j++) G.Edge[i][j] = INF; G.arcnum = G.vexnum = 0; //初始化顶点数、边数}//插入顶点函数bool InsertNode(Graph& G, VexType v){ if (G.vexnum < MaxVerNum) { G.Vex[G.vexnum++] = v; return true; } return false;}//插入边函数bool InsertEdge(Graph& G, VexType v, VexType w, int weight){ int p1, p2;//v,w两点下标 p1 = p2 = -1;//初始化 for (int i = 0; i < G.vexnum; i++)//寻找顶点下标 { if (G.Vex[i] == v) p1 = i; if (G.Vex[i] == w) p2 = i; } if (-1 != p1 && -1 != p2)//两点均可在图中找到 { G.Edge[p1][p2] = G.Edge[p2][p1] = weight;//无向图邻接矩阵对称 G.arcnum++; return true; } return false;}//判断是否存在边(v,w)函数bool Adjancent(Graph G, VexType v, VexType w){ int p1, p2;//v,w两点下标 p1 = p2 = -1;//初始化 for (int i = 0; i < G.vexnum; i++)//寻找顶点下标 { if (G.Vex[i] == v) p1 = i; if (G.Vex[i] == w) p2 = i; } if (-1 != p1 && -1 != p2)//两点均可在图中找到 { if (G.Edge[p1][p2] == 1)//存在边 { return true; } return false; } return false;}bool visited[MaxVerNum];//访问标记数组,用于遍历时的标记//广度遍历函数void BFS(Graph G, int start){ queue Q;//辅助队列 cout << G.Vex[start];//访问结点 visited[start] = true; Q.push(start);//入队 while (!Q.empty())//队列非空 { int v = Q.front();//得到队头元素 Q.pop();//出队 for (int j = 0; j < G.vexnum; j++)//邻接点 { if (G.Edge[v][j] < INF && !visited[j])//是邻接点且未访问 { cout << "->"; cout << G.Vex[j];//访问结点 visited[j] = true; Q.push(j);//入队 } } }//while cout << endl;}//深度遍历函数(递归形式)void DFS(Graph G, int start){ cout << G.Vex[start];//访问 visited[start] = true; for (int j = 0; j < G.vexnum; j++) { if (G.Edge[start][j] < INF && !visited[j])//是邻接点且未访问 { cout << "->"; DFS(G, j);//递归深度遍历 } }}//最短路径 - Dijkstra算法 参数:图G、源点vvoid Dijkstra(Graph G, int v){ //初始化 int n = G.vexnum;//n为图的顶点个数 for (int i = 0; i < n; i++) { S[i] = false; D[i] = G.Edge[v][i]; if (D[i] < INF) Pr[i] = v; //v与i连接,v为前驱 else Pr[i] = -1; } S[v] = true; D[v] = 0; //初始化结束,求最短路径,并加入S集 for (int i = 1; i < n; i++) { int min = INF; int temp; for (int w = 0; w < n; w++) if (!S[w] && D[w] < min) //某点temp未加入s集,且为当前最短路径 { temp = w; min = D[w]; } S[temp] = true; //更新从源点出发至其余点的最短路径 通过temp for (int w = 0; w < n; w++) if (!S[w] && D[temp] + G.Edge[temp][w] < D[w]) { D[w] = D[temp] + G.Edge[temp][w]; Pr[w] = temp; } }}//输出最短路径void Path(Graph G, int v){ if (Pr[v] == -1) return; Path(G, Pr[v]); cout << G.Vex[Pr[v]] << "->";}//打印图的顶点表void PrintVex(Graph G){ cout<<"图中的顶点为:"; for (int i = 0; i < G.vexnum; i++) { cout << G.Vex[i] << " "; } cout << endl;}//打印图的边矩阵void PrintEdge(Graph G){ cout<<"邻接矩阵为:"< > vn; cout << "请输入边数目:" << endl; cin >> an; cout << "请输入所有顶点名称:" << endl; for (int i = 0; i < vn; i++) { cin >> v; if (InsertNode(G, v)) continue;//插入点 else { cout << "输入错误!" << endl; break; } } cout << "请输入所有边(每行输入边连接的两个顶点及权值):" << endl; for (int j = 0; j < an; j++) { int weight; cin >> v >> w >> weight; if (InsertEdge(G, v, w, weight)) continue;//插入边 else { cout << "输入错误!" << endl; break; } } PrintVex(G); cout< > vname; for (int i = 0; i < G.vexnum; i++) { if (G.Vex[i] == vname) v = i; } if (v == -1) { cout << "没有找到输入点!" << endl; return; } Dijkstra(G, v); cout << "目标点" << "\t" << "最短路径值" << "\t" << "最短路径" << endl; for (int i = 0; i < G.vexnum; i++) { if (i != v) { cout << " " << G.Vex[i] << "\t" << " " << D[i] << "\t"; Path(G, i); cout << G.Vex[i] << endl; } }}//菜单void menu(){ cout<<"1.创建图" << endl; cout<<"2.广度遍历"< >choice; if (5 == choice) break; switch (choice) { case 1: CreateGraph(G); break; case 2: BFSTraverse(G); break; case 3: DFSTraverse(G); break; case 4: Shortest_Dijkstra(G); break; default: printf("输入错误!!!\n"); break; } cout<
邻接表
#includeusing namespace std;#define MAXSIZE 100int v[MAXSIZE];//标志位,判断该结点有没有被访问typedef struct ArcNode //定义边节点{ int adjvex;//该节点在图中的位置 int weight;//权值 struct ArcNode *next;//指向下一条边的指针} ArcNode;typedef struct VNode //定义顶点信息{ char data; ArcNode *firstarc;//指向第一条依附于顶点的边的指针} VNode,AdjList[MAXSIZE];//AdjList表示邻接表类型typedef struct //定义邻接表{ int vexnum,arcnum;//顶点数和边数 AdjList vertices;} ALGraph;//定位函数(将点的名称转化为点的位置)int LocateVex(ALGraph G,char u){ int i; for(i=1; i<=G.vexnum; ++i) if(u==G.vertices[i].data) return i; return -1;}void CreatUDG(ALGraph &G)//构建无向图{ int i,n,m,p1,p2; char a,b; ArcNode *s; cout<<"请输入顶点数和边数:"< >n>>m; G.vexnum=n; G.arcnum=m; cout<<"输入顶点名称:"< >G.vertices[i].data; G.vertices[i].firstarc=NULL;//一开始都指向NULL } cout<<"输入一条边对应的两个顶点:"< >a>>b; p1 = LocateVex(G,a); p2 = LocateVex(G,b);//将名称转化为位置 s=new ArcNode[sizeof(ArcNode)];//生成一个新的边结点 s->adjvex=p2;//邻接点的序号为p2 s->next=G.vertices[p1].firstarc; G.vertices[p1].firstarc=s;//将新结点前插至边表头部 s=new ArcNode[sizeof(ArcNode)]; s->adjvex=p1; s->next=G.vertices[p2].firstarc; G.vertices[p2].firstarc=s;//同上,将新结点前插至边表头部 }}int FirstAdjVex(ALGraph G,int k)//返回图G中与k相邻且未被访问过的点的编号,如果不存在这样的点返回-1{ ArcNode *s; s=G.vertices[k].firstarc; if(!s) return -1; while(s&&v[s->adjvex])//如果不空又访问过,就看下一个 s=s->next; if(s)//不空说明找到了 return s->adjvex; else//否则返回-1 return -1;}int NextAdjVex(ALGraph G,int k,int w)//返回图G中与k相邻、除了编号是w之外的未被访问过的点的编号,如果不存在这样的点返回-1{ ArcNode *s; s=G.vertices[k].firstarc; if(!s) return -1; while(s&&(v[s->adjvex]||s->adjvex==w))//不空,并且要么是访问过,要么是w,这样的点我们统统忽略 s=s->next; if(s)//不空说明找到了 return s->adjvex; else//否则-1 return -1;}void DFS(ALGraph G,int k)//对节点k进行深度优先遍历{ int w; v[k]=1;//进来就置1 cout< <<" ";//遍历输出 for(w=FirstAdjVex(G,k); w!=-1; w=NextAdjVex(G,k,w)) //找到所有和k相邻的节点的编号,挨个深搜递归 if(!v[w]) DFS(G,w);}void DFSTraverse(ALGraph G)//对所有点进行深度优先遍历(防止在非连通图中遗漏点){ int i; memset(v,0,sizeof(v)); for(i=1; i<=G.vexnum; i++) if(!v[i]) DFS(G,i);}void BFS(ALGraph G)//广度优先遍历{ int i,k,w; queue q;//定义一个队列存储点的名称 memset(v,0,sizeof(v));//因为之前深搜过,这里重新置0一下 for(i=1; i<=G.vexnum; i++) //依次对每个顶点进行考察(此处相当于把BFS和BFSTraverse合并) if(!v[i])//只要不空 { v[i]=1;//只要不空,进来第一件事就是置1 cout< <<" ";//置1之后马上输出 q.push(G.vertices[i].data);//输出完了之后就入队 while(!q.empty())//只要队列不空 { k=LocateVex(G,q.front());//取队首元素 q.pop();//然后队首出队 for(w=FirstAdjVex(G,k); w!=-1; w=NextAdjVex(G,k,w)) //将所有和队首邻接的顶点依次入队,入一个,输出一个 if(!v[w]) { v[w]=1; cout< <<" "; q.push(G.vertices[w].data); } } }}int main(){ ALGraph G; CreatUDG(G); cout<<"DFS:"; DFSTraverse(G); cout<
发表评论
最新留言
关注你微信了!
[***.104.42.241]2025年03月31日 07时52分09秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Redis进阶实践之十八 使用管道模式提高Redis查询的速度
2021-05-09
SQL注入
2021-05-09
MPI Maelstrom POJ - 1502 ⭐⭐ 【Dijkstra裸题】
2021-05-09
Problem A - Sequence with Digits (数学推导)
2021-05-09
Problem 330A - Cakeminator (思维)
2021-05-09
LeetCode75 颜色分类 (三路快排C++实现与应用)
2021-05-09
docker基础:容器生命周期管理命令
2021-05-09
C语言+easyX图形库的推箱子实现
2021-05-09
调试vs2019代码的流程
2021-05-09
脱壳与加壳-加壳-6-代码实现加密导入表
2021-05-09
Typora配置PicGo时,提示Failed to fetch
2021-05-09
ASP.NET CORE MVC 实现减号分隔(Kebab case)样式的 URL
2021-05-09
bcolz的新操作
2021-05-09
zmq的send
2021-05-09
阿里钉钉面试题
2021-05-09
C++中找资源或者函数的方法
2021-05-09
一些留给自己的思考题(只求回过头来能够有所获)
2021-05-09
delete对象时会自动调用类的析构函数
2021-05-09
C++ 子类对象直接赋值给父类对象可行,反过来不行
2021-05-09
linux下同一个动态库名为何辣么多的.so文件
2021-05-09