7.2 图的基础综合运算(邻接表存储)
实验7.2 图的基础综合运算(邻接表存储)
实验目的
- 理解邻接表存储方式方法
- 理解连通图以邻接表存储时的深度-广度优先搜索遍历算法及实现
说明
- 参考代码里面固定创建队列和顶点数组容量为100, 邻接矩阵固定 100*100, 有点浪费内存,改成动态创建了
- 代码里面很多变量名只有单个字符,读起来不方便,都改成有意义的名字了
tu2.txt
需要放到与编译后可执行文件相同的路径下(不是源代码目录),对于使用 VisualStudio 的同学,可执行文件一般在你项目路径下的Debug
文件夹内
代码
tu2.txt
该文件格式为:
结点数 边数
结点名字(char)
边1(结点1 结点2)
边2
...
如
4 4
A B C D
A B
A C
A D
B D
Graph_AdjList.cpp
#include <iostream>
#include <fstream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define GRAPH_FILE "./tu2.txt" // 输入的文件路径
typedef char VerTexType; //假设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整型
struct ArcNode
{ //边结点
int adjvex; //该边所指向的顶点的位置
ArcNode *nextarc; //指向下一条边的指针
};
struct VNode
{
VerTexType data; //顶点信息
ArcNode *firstarc; //指向第一条依附该顶点的边的指针
};
struct ALGraph
{
VNode *vertices; //邻接表
int vexnum, arcnum; //图的当前顶点数和边数
};
struct SqQueue
{
size_t capacity; // 最大大小
ArcType *base; //初始化的动态分配存储空间
int front; //头指针,若队列不空,指向队头元素
int rear; //尾指针,若队列不空,指向队尾元素的下一个位置
};
// 初始化循环队列
int InitQueue(SqQueue &Q, size_t size)
{
Q.capacity = size;
Q.base = new ArcType[size];
if (!Q.base)
return OVERFLOW;
Q.front = Q.rear = 0;
return OK;
}
// 销毁循环队列
void DestroyQueue(SqQueue &Q)
{
delete[] Q.base;
}
// 判空
bool QueueEmpty(SqQueue &Q)
{
return Q.front == Q.rear;
}
// 判满
bool QueueFull(SqQueue &Q)
{
return (Q.rear + 1) % Q.capacity == Q.front;
}
// 入队 e
int EnQueue(SqQueue &Q, ArcType e)
{
if (QueueFull(Q))
return ERROR;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % Q.capacity;
return OK;
}
// 出队
int DeQueue(SqQueue &Q, ArcType &u)
{
if (QueueEmpty(Q))
return ERROR;
u = Q.base[Q.front];
Q.front = (Q.front + 1) % Q.capacity;
return OK;
}
// 找到结点 v 在头结点列表的下标
int LocateVex(ALGraph &G, VerTexType v)
{
for (int i = 0; i < G.vexnum; ++i)
if (G.vertices[i].data == v)
return i;
return -1;
}
// 采用邻接表表示法,创建无向图G
void CreateUDG(ALGraph &G)
{
fstream file;
file.open(GRAPH_FILE);
if (!file)
{
cout << "没有找到图文件!" << endl;
exit(ERROR);
}
file >> G.vexnum >> G.arcnum; // 输入总顶点数,总边数
G.vertices = new VNode[G.vexnum]; // 创建表头结点列表
for (int i = 0; i < G.vexnum; ++i)
{
file >> G.vertices[i].data; // 输入顶点值
G.vertices[i].firstarc = nullptr; // 初始化表头结点的指针域为空
}
for (int k = 0; k < G.arcnum; ++k)
{
VerTexType v1, v2;
file >> v1 >> v2; // 输入一条边依附的两个顶点值
int i = LocateVex(G, v1); // 找到这两个顶点的下标
int j = LocateVex(G, v2);
ArcNode *p1 = new ArcNode; // 创建一个边结点, 插到 i 号下标结点的边表上
p1->adjvex = j;
p1->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p1;
// 相对应的,j结点的边链表也要插入一个边结点,有向图不用下面这个
ArcNode *p2 = new ArcNode;
p2->adjvex = i;
p2->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p2;
}
}
// 深度优先递归遍历连通图G
void DFS(ALGraph &G, int vex_index, bool *visited)
{
cout << G.vertices[vex_index].data << '\t' << flush; // 访问下标为 vex_index 的结点
visited[vex_index] = true;
ArcNode *p = G.vertices[vex_index].firstarc; // p 指向下标为 vex_index 结点的边链表的第一个边结点
while (p)
{
int adj_vex_index = p->adjvex; // 与它相邻的第一个结点的下标
if (!visited[adj_vex_index]) // 如果没有访问过
DFS(G, adj_vex_index, visited); // 继续递归遍历它
p = p->nextarc; // 继续遍历下一条边
}
}
// 广度优先遍历
void BFS(ALGraph &G, int vex_index)
{
bool *visited = new bool[G.vexnum]{}; // 创建 visited 数组记录已经访问过的结点下标
cout << G.vertices[vex_index].data << '\t'; // 访问下标为 vex_index 的结点
visited[vex_index] = true;
SqQueue Q;
int visited_index;
InitQueue(Q, G.vexnum); // 创建一个长度为结点数的队列
EnQueue(Q, vex_index); // 访问过的下标入队
while (!QueueEmpty(Q))
{
DeQueue(Q, visited_index); // 取出第一个访问过的结点
ArcNode *p = G.vertices[visited_index].firstarc; // 找到它的第一个边结点
while (p)
{
if (!visited[p->adjvex]) // 如果它存在且为被访问
{
cout << G.vertices[p->adjvex].data << '\t'; // 访问它
visited[p->adjvex] = true;
EnQueue(Q, p->adjvex); // 访问过的下标入队
}
p = p->nextarc; // 沿着邻接点链表一直往下遍历
}
}
delete[] visited;
}
// 显示图
void Display(ALGraph &G)
{
for (int i = 0; i < G.vexnum; ++i)
{
VNode temp = G.vertices[i];
ArcNode *p = temp.firstarc;
if (!p)
cout << G.vertices[i].data << "|" << endl;
else
{
cout << temp.data << "|";
while (p)
{
cout << " -> ";
cout << G.vertices[p->adjvex].data;
p = p->nextarc;
}
}
cout << endl;
}
}
// 销毁图
void DestroyGraph(ALGraph &G)
{
for (int i = 0; i < G.vexnum; i++)
{
ArcNode *p = G.vertices[i].firstarc;
while (p)
{
ArcNode *t = p;
delete t;
p = p->nextarc;
}
}
delete[] G.vertices;
}
int main()
{
cout << "************算法6.6 采用邻接表表示图的深度优先搜索遍历**************" << endl;
ALGraph G;
CreateUDG(G);
cout << "无向连通图G创建完成!" << endl;
cout << "**************邻接表表示无向连通图*******************" << endl;
Display(G);
cout << "********************************" << endl;
VerTexType vex_name;
int i;
do
{
cout << "请输入遍历连通图的起始点: ";
cin >> vex_name;
for (i = 0; i < G.vexnum; ++i)
{
if (vex_name == G.vertices[i].data)
break;
else
cout << "该点不存在,请重新输入!" << endl;
}
} while (i >= G.vexnum);
cout << "深度优先搜索遍历连通图结果:" << endl;
bool *visited = new bool[G.vexnum]{}; // 动态创建visited数组保存结点访问状态
DFS(G, i, visited);
delete[] visited;
cout << "\n广度优先搜索遍历连通图结果:" << endl;
BFS(G, i);
cout << endl;
DestroyGraph(G);
}
运行截图
OOP 版
还没写...