双向BFS搜索和A*算法

双向BFS适合给出起点和终点,求最短路径的问题

分别从起点和终点扩展,找交点。每次选择待扩展节点少的那个方向进行扩展,一次扩展一层。

扩展一个节点的时候,如果节点也在另一个方向的待扩展队列里,找到交点。

int doubleBFS(vector<vector<int>> &G, int start, int end) {
	vector<vector<bool>> marked(2, vector<bool>(G.size()));//dead and to-be-expanded nodes
	queue<int> q[2]; //newly expanded nodes, to be expanded
	int level[2] {0, 0}; //how many levels that has finished expanding
	q[0].push(start), marked[0][start] = true, marked[1][end] = true, q[1].push(end);
	//expand one level. choose next direction at end: whose to-be-expand list is smaller
	for (int t = 0; q[t].size() > 0; ++level[t], t = q[0].size() <= q[1].size() ? 0 : 1) {
		for (int sz = q[t].size(), i = 0; i < sz; ++i) {
			int v = q[t].front(); q[t].pop();
			//in the other direction's queue, intersection  found
			if (marked[!t][v]) return level[0] + level[1] + 1;
			for (int w : G[v]) {
				if (!marked[t][w]) {
					marked[t][w] = true;
					q[t].push(w);
				}
			}
		}
	}
	return -1; //the given nodes are not connected
}



具体求出路径

vector<int> doubleBFS(vector<vector<int>> &G, int start, int end) {
	vector<vector<bool>> marked(2, vector<bool>(G.size())); //dead and to-be-expand nodes
	vector<int> prev[2] {vector<int>(G.size()), vector<int>(G.size())}; //predecessor
	queue<int> q[2]; //newly expanded nodes, to be expanded
	q[0].push(start), marked[0][start] = true, marked[1][end] = true, q[1].push(end);
	//expand one level, determine next direction at end: whose queue is smaller
	for (int t = 0; q[t].size() > 0; t = q[0].size() <= q[1].size() ? 0 : 1) {
		for (int sz = q[t].size(), i = 0; i < sz; ++i) {
			int v = q[t].front(); q[t].pop();
			// in the other direction's to-be-extended list, intersection found
			if (marked[!t][v]) {
				deque<int> path;
				for (int x = v; x != start; x = prev[0][x]) path.push_front(prev[0][x]);
				path.push_back(v);
				for (int x = v; x != end; x = prev[1][x]) path.push_back(prev[1][x]);
				return vector<int>(path.begin(), path.end());
			}
			for (int w : G[v]) {
				if (!marked[t][w]) {
					marked[t][w] = true;
					prev[t][w] = v;
					q[t].push(w);
				}
			}
		}
	}
	return {}; //the given nodes are not connected
}


BFS,DFS,A*分别是三种不同的搜索(遍历)顺序:

BFS:宽度优先

DFS:深度优先

A* :  估价优先

A*是带一点启发式的搜索,对新扩展出来的节点用估价函数 f(v) = g(v) + h(v)进行估价,按估价排序,然后选择下一个扩展节点。A*是dfs、bfs之外的另一种遍历顺序——按估价。对应的容器分别是stack, queue, priority_queue。

BFS,DFS,A*只是搜索顺序不同,并没有排除、丢弃任何节点,都是O(n)的,只是期望目标节点尽可能排在前面。 还有一些搜索是可以排除、丢弃一部分节点的搜索,比如局部择优搜索、二分搜索。

双向A*算法并不一定比A*算法快。 传统A*算法结合了BFS算法迪杰斯特拉算法的优点,通过启发式函数评估当前节点到目标节点的距离代价,筛选扩展节点以搜索最短路径,适用于各种场景,具有灵活性[^3]。双向A*算法搜索过程中,从起点终点同时开始,使用启发式函数进行搜索,直到在某个节点相交找到路径[^1]。 在某些情况下,双向A*算法具有明显优势。当搜索空间较大且存在明确的起点终点时,双向搜索能减少不必要的搜索,缩小搜索范围,从而提高搜索效率。因为它从两个方向同时推进,能更快地在中间相遇,减少整体搜索的节点数量。 然而,双向A*算法也有局限性。如果搜索空间较为简单,或者起点终点之间存在特殊的拓扑结构,使得传统A*算法能直接找到较优路径,双向A*算法额外的开销(如维护两个搜索队列、处理两个方向的启发式计算等)可能会导致其性能不如传统A*算法。此外,双向A*算法的实现复杂度相对较高,在某些对时间空间要求极高的场景下,额外的开销可能会使它的性能不如传统A*算法。 ```python # 以下为简单示意代码,非完整实现 import math class AStar: def __init__(self, heuristic_type="manhattan"): self.heuristic_type = heuristic_type def h(self, s, goal): if self.heuristic_type == "manhattan": return abs(goal[0] - s[0]) + abs(goal[1] - s[1]) else: return math.hypot(goal[0] - s[0], goal[1] - s[1]) def search(self, start, goal): # 传统A*搜索逻辑 pass class BidirectionalAStar: def __init__(self, heuristic_type="manhattan"): self.heuristic_type = heuristic_type self.g_fore = {} self.s_goal = None def f_value_fore(self, s): return self.g_fore[s] + self.h(s, self.s_goal) def h(self, s, goal): if self.heuristic_type == "manhattan": return abs(goal[0] - s[0]) + abs(goal[1] - s[1]) else: return math.hypot(goal[0] - s[0], goal[1] - s[1]) def search(self, start, goal): # 双向A*搜索逻辑 pass ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值