邻接链表、矩阵表示图时的广度优先搜索与深度优先搜索

1、图的基本表示:
G(V,E)表示图,V为vector节点,E为edge边。
邻接链表常用于表示稀疏图,邻接矩阵常表示稠密图,其中图规模较小时也常用邻接矩阵表示,因为矩阵表示简单。
在这里插入图片描述
无向图邻接链表长度之和为2|E|,有向图邻接链表长度之和为|E|
在这里插入图片描述
2、广度优先搜索BFS:
BFS为最基础的无权重图的最短路径求解算法。
在其基础上的单源最短路径问题有权重图的最短路径求解问题,解法为Dijkstra算法(基于BFS改进)。

算法在发现所有距离源节点s为k的所有节点后,才会发现距离源节点s为k+1的其他节点。
在这里插入图片描述
注意: 广度优先搜索是一种分层的查找过程,每向前走一步可能访问一批顶点,不像深度优先搜索那样有往回退的情况,因此它不是一个递归的算法。为了实现逐层的访问,算法必须借助一个辅助队列,以记录正在访问的顶点的下一层顶点
同时需要保存节点访问的状态(避免重复访问),若为邻接矩阵形式则使用一个数组保存节点访问状态;若为邻接链表形式则增加链表中节点属性如node.accessed = true
2.1、邻接矩阵表示的广度优先搜索C++代码:
用数组保存节点访问状态

const int MaxNum = 10; // 图的大小10X10
int G[MaxNum ][MaxNum ]; // 表示图 ,顶点为数字0-9,此部分要随题变化
int visited[MaxNum ] = {0}; // 保存访问状态
int route[MaxNum ] ={-1}; //记录路径
queue<int> q; // 记录待访问节点
void BFS(int* G,int start) // 输入图与搜索起点,起点类型随题目而变
{
	visited[start] = 1;
	route[start] = -1; //源头,-1表示已经没有路了
	q.push(start);
	while(!q.empty()){
		int tmpnode = q.front();
		q.pop();
		for(int i = 0;i<MaxNum;i++){
			if(G[tmpnode][i] = 1 && visited[i] == 0){ //1代表连接(有路) 
			//当两节点间连接且没访问过则进行处理:加入待放问列表
				route[i] = tmpnode; //路的来源
				q.push(i); 
				visited[i] = 1;
			}
		}
	}
}

//输出起点start到任一点的路径:
void route(int start, int end)
{
	vector<int> route_start_end;
	while( end !=-1){
		route_start_end.push_back(end);
		end = route[end];
	}
	for(int i = route_start_end.size()-1;i>=0;i--){
		std::cout<<route_start_end[i];
	}
}

2.2、邻接链表表示的广度优先搜索C++代码:
也可以在node中加入visited属性代替visited数组

struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) : val(x), next(NULL) {}
}
const int MaxNum = 10; // 图的大小10X10
ListNode* G[MaxNum]; // 图,假设已经构造好了
void BFS(ListNode* G,int start) // 输入图与搜索起点,起点类型随题目而变
{
	int visited[MaxNum ] = {0}; // 保存访问状态
	int route[MaxNum ] ={-1}; //记录路径
	queue<ListNode*> q; // 记录待访问节点
	q.push(G[start]); //起点入队
	visited[start] = 1; //标识起点已经访问
	while(!q.empty()){
		ListNode* tmp = q.front();
		q.pop();
		while(tmp->next != null){
			if(visited[tmp->next->val]!=1){
				q.push(tmp->next);
				visited[tmp->next->val] = 1;
				route[tmp->next->val] =tmp->val; //记录路径
			}
			tmp = tmp->next;
		}
	}
}

2.3、非联通图的广度优先搜索:

void BFSall(ListNode* G)
{
	for(int i = 0;i<MaxNum;i++){
		if(visited[i]!=1){
			BFS(G,i); // 若这个节点未访问过说明与其他节点不连通,从此节点开始再调用BFS 
		}
	}
}

参考资料:
good: 图的广度优先搜索(BFS)和深度优先搜索(DFS)算法解析
广度优先搜索(BFS)C++实现

3、深度优先搜索:
深度优先搜索类似于树的先序遍历,需要数组记录已访问的节点,同时利用递归,当节点都访问过时返回前驱节点
3.1、邻接矩阵表示的深度优先搜索C++代码:

int visited[MaxNum] = {0}; // 保存访问状态
void DFS(int* G,int start)
{
	visit(start); // 可以是输出、记录父节点等任何操作
	visited[start] = 1;
	for(int i = 0;i<MaxNum;i++){
		if(G[start][i]!=0 && visited[i]!=1){
			DFS(G,i);
		}
	}
} 

3.2、邻接链表表示的深度优先搜索C++代码:

int visited[MaxNum] = {0}; // 保存访问状态
void DFS(ListNode* G,int start) //start为访问起点
{
	visit(start); // 可以是输出、记录前驱节点等任何操作
	visited[start] = 1;
	ListNode* head = G[start];
	while(head){
		ListNode* tmp = head->next;
		if(tmp && visited[tmp->val]!=1){ //若节点存在且未访问,则递归进入
			DFS(G,tmp->val); 
		}
		head = tmp; //否则就退回源节点,转到链表其余节点
	}
} 

参考资料:图的广度优先搜索(BFS)和深度优先搜索(DFS)算法解析

总结:

1、广度优先搜索类似层序遍历,需要一个队列保存待访问的节点,同时需要一个属性标识节点的访问状态,若要保存节点路径,还需要一个路径数组。
2、深度优先搜索类似于前序遍历,利用递归实现。
3、BFS与DFS搜索起点不确定,因此在解题时一般首先要查找起点。
4、广度优先搜索算法可用于求最短路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值