图的遍历(邻接矩阵)——广度遍历、深度遍历(王道版)

参考王道《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);
		}
	}
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈阿土i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值