图的遍历小节完结

图的应用好像没有代码题,貌似图完结了....
This commit is contained in:
Ruvikm
2021-02-19 21:58:58 +08:00
parent 147e35f4c5
commit de75f73c16
4 changed files with 679 additions and 0 deletions

176
图/图的遍历/P232.2.cpp Normal file
View File

@@ -0,0 +1,176 @@
#include <iostream>
using namespace std;
#pragma region 创建邻接表存储的无向图
#define MaxVertexNum 10 //图中顶点数目最大值
#define VertexType char
#define _for(i,a,b) for(int i=(a);i<(b);i++)
typedef struct ArcNode { //边表结点
int adjvex; //该弧所指向的顶点的位置
ArcNode* next; //指向下一条弧的指针
}ArcNode;
typedef struct VNode { //顶点表结点
VertexType data; //顶点信息
ArcNode* first; //指向第一条依附该顶点的弧的指针
}VNode, AdjList[MaxVertexNum];
typedef struct {
AdjList vertices; //领接表
int vexnum, arcnum; //图的顶点数和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
int LocateVex(ALGraph& G, VertexType x) {
_for(i, 0, G.vexnum) {
if (G.vertices[i].data == x)
return i;
}
return -1;
}
void CreateALGraph(ALGraph& G) {
cout << "输入顶点数和边数" << endl;
cin >> G.vexnum >> G.arcnum;
_for(i, 0, G.vexnum) {
cout << "输入第" << i + 1 << "个顶点的信息" << endl;
cin >> G.vertices[i].data;
G.vertices[i].first = NULL;
}
_for(k, 0, G.arcnum) {
VertexType e1, e2;
cout << "输入第" << k + 1 << "条边的顶点:" << endl;
cin >> e1 >> e2;
ArcNode* e = new ArcNode;
if (!e) {
cout << "内存申请失败!" << endl;
exit(0);
}
int vi = LocateVex(G, e1);
int vj = LocateVex(G, e2);
e->adjvex = vj; //这三步,类似于单链表的头插法
e->next = G.vertices[vi].first;
G.vertices[vi].first = e;
e = new ArcNode;
if (!e) {
cout << "内存申请失败!" << endl;
exit(0);
}
e->adjvex = vi;
e->next = G.vertices[vj].first;
G.vertices[vj].first = e;
}
}
bool visited[MaxVertexNum];
void DFS(ALGraph G, int i) { //邻接表的深度优先递归
ArcNode* p;
visited[i] = true; //访问过了该顶点,标记为TRUE
cout << G.vertices[i].data << " ";
p = G.vertices[i].first; //让p指向边表第一个结点
while (p) { //在边表内遍历
if (!visited[p->adjvex]) //对未访问的邻接顶点递归调用
DFS(G, p->adjvex);
p = p->next;
}
}
void DFSTraverse(ALGraph G) { //邻接表的深度遍历操作
_for(i, 0, G.vexnum)
visited[i] = false; //初始设置为未访问 
_for(i, 0, G.vexnum)
if (!visited[i])
DFS(G, i); //对未访问的顶点调用DFS,若是连通图只会执行一次 
}
#pragma endregion
//P232.2
//试设计一个算法, 判断一个无向图G是否为一棵树。若是一棵树, 则算法返回true
//否则返回false
bool visit[MaxVertexNum];
int Enum = 0, Vnum = 0;
void DFS_2(ALGraph G, int i) { //邻接表的深度优先递归
ArcNode* p;
visit[i] = true; //访问过了该顶点,标记为TRUE
Vnum++;
p = G.vertices[i].first; //让p指向边表第一个结点
while (p) { //在边表内遍历
Enum++;
if (!visit[p->adjvex]) //对未访问的邻接顶点递归调用
DFS_2(G, p->adjvex);
p = p->next;
}
}
bool isTree(ALGraph G) {
memset(visit, false, sizeof(visit));
DFS_2(G, 1);
if (G.vexnum == Vnum && Enum == 2 * (G.vexnum - 1))
return true;
else
return false;
}
int main()
{
ALGraph G;
CreateALGraph(G);
cout << endl;
cout << "DFS:" << endl;
DFSTraverse(G);
cout << endl;
if (isTree(G))
cout << "图G是一棵树" << endl;
else
cout << "图G不是一棵树" << endl;
return 0;
}
/*
input:
5 7
a b c d e
a b
a e
b c
b d
b e
c d
d e
生成图的链接:https://s3.ax1x.com/2021/02/18/yW59vF.png
普通的树:
7 6
a b c d e f g
a b
a c
a d
b e
b f
d g
a
b c d
e f g
*/

157
图/图的遍历/P232.3.cpp Normal file
View File

@@ -0,0 +1,157 @@
#include <iostream>
#include <stack>
using namespace std;
#pragma region 创建邻接表存储的无向图
#define MaxVertexNum 10 //图中顶点数目最大值
#define VertexType char
#define _for(i,a,b) for(int i=(a);i<(b);i++)
typedef struct ArcNode { //边表结点
int adjvex; //该弧所指向的顶点的位置
ArcNode* next; //指向下一条弧的指针
}ArcNode;
typedef struct VNode { //顶点表结点
VertexType data; //顶点信息
ArcNode* first; //指向第一条依附该顶点的弧的指针
}VNode, AdjList[MaxVertexNum];
typedef struct {
AdjList vertices; //领接表
int vexnum, arcnum; //图的顶点数和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
int LocateVex(ALGraph& G, VertexType x) {
_for(i, 0, G.vexnum) {
if (G.vertices[i].data == x)
return i;
}
return -1;
}
void CreateALGraph(ALGraph& G) {
cout << "输入顶点数和边数" << endl;
cin >> G.vexnum >> G.arcnum;
_for(i, 0, G.vexnum) {
cout << "输入第" << i + 1 << "个顶点的信息" << endl;
cin >> G.vertices[i].data;
G.vertices[i].first = NULL;
}
_for(k, 0, G.arcnum) {
VertexType e1, e2;
cout << "输入第" << k + 1 << "条边的顶点:" << endl;
cin >> e1 >> e2;
ArcNode* e = new ArcNode;
if (!e) {
cout << "内存申请失败!" << endl;
exit(0);
}
int vi = LocateVex(G, e1);
int vj = LocateVex(G, e2);
e->adjvex = vj; //这三步,类似于单链表的头插法
e->next = G.vertices[vi].first;
G.vertices[vi].first = e;
e = new ArcNode;
if (!e) {
cout << "内存申请失败!" << endl;
exit(0);
}
e->adjvex = vi;
e->next = G.vertices[vj].first;
G.vertices[vj].first = e;
}
}
bool visited[MaxVertexNum];
void DFS(ALGraph G, int i) { //邻接表的深度优先递归
ArcNode* p;
visited[i] = true; //访问过了该顶点,标记为TRUE
cout << G.vertices[i].data << " ";
p = G.vertices[i].first; //让p指向边表第一个结点
while (p) { //在边表内遍历
if (!visited[p->adjvex]) //对未访问的邻接顶点递归调用
DFS(G, p->adjvex);
p = p->next;
}
}
void DFSTraverse(ALGraph G) { //邻接表的深度遍历操作
_for(i, 0, G.vexnum)
visited[i] = false; //初始设置为未访问 
_for(i, 0, G.vexnum)
if (!visited[i])
DFS(G, i); //对未访问的顶点调用DFS,若是连通图只会执行一次 
}
#pragma endregion
//P232.3
//写出图的深度优先搜索DFS算法的非递归算法(图采用邻接表形式)。
bool visit[MaxVertexNum];
void DFS_Non_RC(ALGraph& G, int v) {
memset(visit, false, sizeof(visit));
stack<int> s;
s.push(v);
visit[v] = true;
while (!s.empty()) {
ArcNode* p = G.vertices[s.top()].first;
cout << G.vertices[s.top()].data << " ";
s.pop();
while (p) {
if (!visit[p->adjvex]) {
s.push(p->adjvex);
visit[p->adjvex] = true;
}
p = p->next;
}
}
}
int main()
{
ALGraph G;
CreateALGraph(G);
cout << endl;
cout << "DFS:" << endl;
DFSTraverse(G);
cout << endl;
DFS_Non_RC(G, 0);
return 0;
}
/*
PS:
答案是对的,至于为什么两个DFS顺序不一样
是因为非递归DFS遍历用头插法插入的边表(逆置的)时
存入栈中正好把顺序给正过来了。
input:
5 7
a b c d e
a b
a e
b c
b d
b e
c d
d e
生成图的链接:https://s3.ax1x.com/2021/02/18/yW59vF.png
*/

178
图/图的遍历/P233.4.cpp Normal file
View File

@@ -0,0 +1,178 @@
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
#pragma region 创建邻接表存储的有向图
#define MaxVertexNum 10 //图中顶点数目最大值
#define VertexType char
#define _for(i,a,b) for(int i=(a);i<(b);i++)
typedef struct ArcNode { //边表结点
int adjvex; //该弧所指向的顶点的位置
ArcNode* next; //指向下一条弧的指针
}ArcNode;
typedef struct VNode { //顶点表结点
VertexType data; //顶点信息
ArcNode* first; //指向第一条依附该顶点的弧的指针
}VNode, AdjList[MaxVertexNum];
typedef struct {
AdjList vertices; //领接表
int vexnum, arcnum; //图的顶点数和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
int LocateVex(ALGraph& G, VertexType x) {
_for(i, 0, G.vexnum) {
if (G.vertices[i].data == x)
return i;
}
return -1;
}
void CreateALGraph(ALGraph& G) {
cout << "输入顶点数和边数" << endl;
cin >> G.vexnum >> G.arcnum;
_for(i, 0, G.vexnum) {
cout << "输入第" << i + 1 << "个顶点的信息" << endl;
cin >> G.vertices[i].data;
G.vertices[i].first = NULL;
}
_for(k, 0, G.arcnum) {
VertexType e1, e2;
cout << "输入第" << k + 1 << "条边(v1 -> v2)的顶点:" << endl;
cin >> e1 >> e2;
ArcNode* e = new ArcNode;
if (!e) {
cout << "内存申请失败!" << endl;
exit(0);
}
int vi = LocateVex(G, e1);
int vj = LocateVex(G, e2);
e->adjvex = vj; //这三步,类似于单链表的头插法
e->next = G.vertices[vi].first;
G.vertices[vi].first = e;
}
}
bool visited[MaxVertexNum];
void DFS(ALGraph G, int i) { //邻接表的深度优先递归
ArcNode* p;
visited[i] = true; //访问过了该顶点,标记为TRUE
cout << G.vertices[i].data << " ";
p = G.vertices[i].first; //让p指向边表第一个结点
while (p) { //在边表内遍历
if (!visited[p->adjvex]) //对未访问的邻接顶点递归调用
DFS(G, p->adjvex);
p = p->next;
}
}
void DFSTraverse(ALGraph G) { //邻接表的深度遍历操作
_for(i, 0, G.vexnum)
visited[i] = false; //初始设置为未访问 
_for(i, 0, G.vexnum)
if (!visited[i])
DFS(G, i); //对未访问的顶点调用DFS,若是连通图只会执行一次 
}
#pragma endregion
//P233.4
//分别采用基于深度优先遍历和广度优先遍历算法判别以邻接表方式存储的有向图中是否
//存在由顶点vi到顶点vj的路径(i≠j)。注意, 算法中涉及的图的基本操作必须在此存储
//结构上实现
bool visit1[MaxVertexNum] = { false };
bool ExistPath_DFS(ALGraph G,int i,int j) {
if (i == j)
return true;
else {
visit1[i] = true;
ArcNode* p = G.vertices[i].first; //让p指向边表第一个结点
while (p) { //在边表内遍历
if (!visit1[p->adjvex] && ExistPath_DFS(G, p->adjvex, j)) //对未访问的邻接顶点递归调用
return true;
p = p->next;
}
return false;
}
}
bool visit2[MaxVertexNum] = { false };
bool ExistPath_BFS(ALGraph G, int i, int j) {
queue<int> q;
q.push(i);
while (!q.empty()) {
visit2[q.front()] = true;
ArcNode* p = G.vertices[q.front()].first;
q.pop();
while (p) {
if (p->adjvex == j)
return true;
if (!visit2[p->adjvex])
q.push(p->adjvex);
p = p->next;
}
}
return false;
}
int main()
{
ALGraph G;
CreateALGraph(G);
cout << endl;
cout << "DFS:" << endl;
DFSTraverse(G);
cout << endl;
cout << endl;
cout << "使用DFS判别:" << endl;
if (ExistPath_DFS(G, 0, 4))
cout << "路径存在" << endl;
else
cout << "路径不存在" << endl;
cout << endl;
cout << endl;
cout << "使用BFS判别:" << endl;
if (ExistPath_BFS(G, 0, 4))
cout << "路径存在" << endl;
else
cout << "路径不存在" << endl;
return 0;
}
/*
input:
6 8
a b c d e f
a b
a d
b e
c e
c f
d b
e d
f f
有向图链接:https://s3.ax1x.com/2021/02/19/yhqBOx.png
*/

168
图/图的遍历/P233.5.cpp Normal file
View File

@@ -0,0 +1,168 @@
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
using namespace std;
#pragma region 创建邻接表存储的有向图
#define MaxVertexNum 10 //图中顶点数目最大值
#define VertexType char
#define _for(i,a,b) for(int i=(a);i<(b);i++)
typedef struct ArcNode { //边表结点
int adjvex; //该弧所指向的顶点的位置
ArcNode* next; //指向下一条弧的指针
}ArcNode;
typedef struct VNode { //顶点表结点
VertexType data; //顶点信息
ArcNode* first; //指向第一条依附该顶点的弧的指针
}VNode, AdjList[MaxVertexNum];
typedef struct {
AdjList vertices; //领接表
int vexnum, arcnum; //图的顶点数和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
int LocateVex(ALGraph& G, VertexType x) {
_for(i, 0, G.vexnum) {
if (G.vertices[i].data == x)
return i;
}
return -1;
}
void CreateALGraph(ALGraph& G) {
cout << "输入顶点数和边数" << endl;
cin >> G.vexnum >> G.arcnum;
_for(i, 0, G.vexnum) {
cout << "输入第" << i + 1 << "个顶点的信息" << endl;
cin >> G.vertices[i].data;
G.vertices[i].first = NULL;
}
_for(k, 0, G.arcnum) {
VertexType e1, e2;
cout << "输入第" << k + 1 << "条边(v1 -> v2)的顶点:" << endl;
cin >> e1 >> e2;
ArcNode* e = new ArcNode;
if (!e) {
cout << "内存申请失败!" << endl;
exit(0);
}
int vi = LocateVex(G, e1);
int vj = LocateVex(G, e2);
e->adjvex = vj; //这三步,类似于单链表的头插法
e->next = G.vertices[vi].first;
G.vertices[vi].first = e;
}
}
bool visited[MaxVertexNum];
void DFS(ALGraph G, int i) { //邻接表的深度优先递归
ArcNode* p;
visited[i] = true; //访问过了该顶点,标记为TRUE
cout << G.vertices[i].data << " ";
p = G.vertices[i].first; //让p指向边表第一个结点
while (p) { //在边表内遍历
if (!visited[p->adjvex]) //对未访问的邻接顶点递归调用
DFS(G, p->adjvex);
p = p->next;
}
}
void DFSTraverse(ALGraph G) { //邻接表的深度遍历操作
_for(i, 0, G.vexnum)
visited[i] = false; //初始设置为未访问 
_for(i, 0, G.vexnum)
if (!visited[i])
DFS(G, i); //对未访问的顶点调用DFS,若是连通图只会执行一次 
}
#pragma endregion
//P233.5
//假设图用邻接表表示, 设计一个算法, 输出从顶点Vi到顶点Vj的所有简单路径
bool visit[MaxVertexNum] = { false };
vector<int> path;
bool flag = false;
void FindPath(ALGraph G,int i,int j) {
path.push_back(i);
if (i == j) {
_for(i, 0, path.size()) {
if (i < path.size() - 1)
cout << G.vertices[path[i]].data << "->";
else
cout << G.vertices[path[i]].data << endl;
}
flag = true;
exit(0); //return还会多输出一次路径
}
else {
visit[i] = true;
ArcNode* p = G.vertices[i].first;
while (p) {
if (!visit[p->adjvex]) {
FindPath(G, p->adjvex, j);
}
p = p->next;
}
visit[i] = false;
path.pop_back();
}
}
void PrintPath(ALGraph G, VertexType vi, VertexType vj) {
FindPath(G, LocateVex(G, vi), LocateVex(G, vj));
}
int main()
{
ALGraph G;
CreateALGraph(G);
cout << endl;
cout << "DFS:" << endl;
DFSTraverse(G);
cout << endl;
cout << endl;
cout << "路径如下:" << endl;
PrintPath(G, 'c', 'd');
if (!flag) {
cout << "路径不存在!" << endl;
}
return 0;
}
/*
input:
6 8
a b c d e f
a b
a d
b e
c e
c f
d b
e d
f f
有向图链接:https://s3.ax1x.com/2021/02/19/yhqBOx.png
*/