参考王道《2023年数据结构考研复习指导》
由于需要用到队列,本代码中还涉及队列的建立、初始化、入队、出队、销毁等操作
#include <iostream>
#define MaxVerTexNum 20
typedef char VertexType; // 顶点的数据类型
typedef int EdgeType; // 带权图中边上权值的数据类型
// 邻接矩阵存储图
typedef struct {
VertexType Vex[MaxVerTexNum]; // 顶点表
EdgeType Edge[MaxVerTexNum][MaxVerTexNum]; // 邻接矩阵,边表
int vexnum, arcnum; // 图的当前顶点数和边数/弧数
} MGraph;
// 链式队列结点
typedef struct LinkNode {
int data; // 存储图的顶点的下标
struct LinkNode* next;
} LinkNode;
// 链式队列
typedef struct LinkQueue {
LinkNode* front, * rear;
} LinkQueue;
bool visited[MaxVerTexNum];
bool InitQueue(LinkQueue& Q);
bool IsEmpty(LinkQueue Q);
bool EnQueue(LinkQueue& Q, int x);
bool DeQueue(LinkQueue& Q, int& x);
void DestroyQueue(LinkQueue& Q);
int FirstNeighbor(MGraph G, int x);
int NextNeighbor(MGraph G, int x, int y);
void BFSTraverse(MGraph G);
void BFS(MGraph G, int v);
void visit(MGraph G, int v);
void DFSTraverse(MGraph G);
void DFS(MGraph G, int v);
int main() {
MGraph G = {
{'1', '2', '3', '4', '5', '6', '7', '8'},
{
{0,1,0,0,1,0,0,0},
{1,0,0,0,0,1,0,0},
{0,0,0,1,0,1,1,0},
{0,0,1,0,0,0,1,1},
{1,0,0,0,0,0,0,0},
{0,1,1,0,0,0,1,0},
{0,0,1,1,0,1,0,1},
{0,0,0,1,0,0,1,0},
},
8, 10
};
BFSTraverse(G);
std::cout << std::endl;
DFSTraverse(G);
std::cout << std::endl;
system("pause");
return 0;
}
/*==================================================================*/
// 初始化队列(带头结点)
bool InitQueue(LinkQueue& Q) {
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
if (Q.front == NULL)
return false;
Q.front->next = NULL;
return true;
}
// 判断队列是否为空
bool IsEmpty(LinkQueue Q) {
if (Q.front == Q.rear)
return true;
else
return false;
}
// 入队(带头结点)
bool EnQueue(LinkQueue& Q, int x) {
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
if (s == NULL)
return false;
s->data = x;
s->next = NULL;
Q.rear->next = s;
Q.rear = s;
return true;
}
// 出队(带头结点)
bool DeQueue(LinkQueue& Q, int& x) {
if (IsEmpty(Q))
return false;
LinkNode* p = Q.front->next;
x = p->data;
Q.front->next = p->next;
if (p == Q.rear) // 若此时是最后一个结点出队
Q.rear = Q.front;
free(p);
return true;
}
void DestroyQueue(LinkQueue& Q) {
LinkNode* p = Q.front->next;
LinkNode* q;
while (p != NULL) {
q = p;
p = p->next;
free(q);
}
free(Q.front);
Q.front = Q.rear = NULL;
}
/*==================================================================*/
// 求图G中顶点x(下标)的第一个邻接点,若有则返回顶点号。若x没有邻接点或图中不存在x,则返回-1
int FirstNeighbor(MGraph G, int x) {
if (x >= G.vexnum)
return -1;
int i = 0;
while (i < G.vexnum) {
if (G.Edge[x][i] != 0)
return i;
i++;
}
return -1;
}
// 假设图G中顶点y是顶点x的一个邻接点,返回除y之外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1
int NextNeighbor(MGraph G, int x, int y) {
if (x >= G.vexnum || y >= G.vexnum)
return -1;
int i = y + 1;
while (i < G.vexnum) {
if (G.Edge[x][i] != 0)
return i;
i++;
}
return -1;
}
/*==================================================================*/
void BFSTraverse(MGraph G) { // 对图G进行广度优先遍历
for (int i = 0; i < G.vexnum; ++i) {
visited[i] = false; // 访问标记数组初始化
}
for (int i = 0; i < G.vexnum; ++i) {
if (!visited[i]) { // 对每个连通分量调用一次BFS
BFS(G, i);
}
}
}
void BFS(MGraph G, int v) { // 从顶点v出发,广度优先遍历图G
visit(G, v); // 访问初始结点v
visited[v] = true;
LinkQueue Q;
InitQueue(Q);
EnQueue(Q, v); // 顶点v入队列Q
while (!IsEmpty(Q)) {
DeQueue(Q, v); // 顶点v出队列
for (int w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) { //检测v所有邻接点
if (!visited[w]) { // w为v的尚未访问的邻接点
visit(G, w); // 访问顶点w
visited[w] = true; // 对w做已访问标记
EnQueue(Q, w);
}
}
}
DestroyQueue(Q);
}
void visit(MGraph G, int v) {
std::cout << G.Vex[v] << " ";
}
/*==================================================================*/
void DFSTraverse(MGraph G) {
for (int i = 0; i < G.vexnum; ++i) {
visited[i] = false; // 初始化已访问标记数据
}
for (int v = 0; v < G.vexnum; ++v) {
if (!visited[v]) {
DFS(G, v);
}
}
}
void DFS(MGraph G, int v) { // 从顶点v出发,深度优先遍历图G
visit(G, v); // 访问顶点v
visited[v] = true; // 设置已访问标志
for (int w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) {
if (!visited[w]) { // w为v的尚未访问的邻接点
DFS(G, w);
}
}
}