除了使用 A* 之外,还有其他优化 Dijkstra 算法的方法吗?
Posted
技术标签:
【中文标题】除了使用 A* 之外,还有其他优化 Dijkstra 算法的方法吗?【英文标题】:Is there a way of optimizing Dijkstra algorithm other than using A*? 【发布时间】:2022-01-04 04:32:57 【问题描述】:我需要在图中找到 2 个点之间的最短路径
这个任务必须用C语言完成
我选择使用 Dijkstra 算法来解决这个问题。当使用 442 个顶点时,我立即找到没有问题的路径,但是,当使用 6111 和 12605(教师的测试用例)时,算法开始变慢,以至于需要 8 分钟才能找到一条路径.
我的图形实现与相邻列表一起使用以防止 n^2 大小。
我实现的 Dijkstra 基于 ComputerPhile 的视频 https://www.youtube.com/watch?v=GazC3A4OQTE,使用优先级队列,带有 while(current_vertex != destination && get_size(priority_queue) > 0)
,优先级队列中每个节点的优先级也是使用 street_length 或 street_length/average_speed 计算的。
因为顶点在一个平面上,我尝试做一个 A* 自适应,从优先级队列中添加每个节点的成本当前之间的欧几里得距离顶点位置和目标顶点。
代码
编辑:用一个 if 优化
while(search != destination)
if(find_element(visited_vertexes, search, compare) == NULL) //Added this if
void* search_adjacents = list_of_adjacents_by_address(search);
for(void* aux = get_head(search_adjacents); aux; aux = get_next(aux))
void* edge = get_list_element(aux);
if(edge_get_from(edge) != edge_get_to(edge))
void* edge_data = edge_get_data(edge);
void* edge_to = edge_get_to(edge);
double cost_until_this_point = operation_mode(edge_data) + search_cost;
void* found = find_element(visited_vertexes, edge_to, compare);
if(found == NULL && edge_to != back_track)
priority_queue_insert(prior_queue, new_helper(edge_to, search, cost_until_this_point + distance_dijkstra(edge_to, destination)), cost_until_this_point + distance_dijkstra(edge_to, destination)); // Are we able to use a* ?
back_track = search; // Update to compare with the next vertex
helper* top = priority_queue_pop(prior_queue, false, free_helper);
insert_list(visited_vertexes, top); // Updated visited vertexes, remove from the priority queue
helper* next_vertex = priority_queue_get_element(priority_queue_get_head(prior_queue));
if(!next_vertex) break;
search = next_vertex->vertex;
search_cost = next_vertex->cost;
到目前为止,我已经做到了。 我认为它很慢,因为很多案例的优先级非常接近。 有什么建议可以进一步优化这个 Dijkstra 吗?
附注:
typedef struct helper
void* vertex; //Current vertex
void* from; //Where it came from
double cost; //Cost until here
helper;
void* new_helper(void* vertex, void* from, double cost)
helper* aux = calloc(1, sizeof(helper));
aux->vertex = vertex;
aux->from = from;
aux->cost = cost;
return aux;
【问题讨论】:
Dijkstra 的 C 语言算法在具有 12605 个顶点的图上花费的时间不会超过几毫秒,即使它非常密集。您不需要更复杂的算法。你只需要修复你的实现。问题似乎不在您发布的代码中。 我需要从文件中读取数据,这实际上不会超过1~2秒,但是代码慢的地方是在Dijkstra实现的这一部分。 您在循环中调用函数distance_dijkstra
,这是欧几里得距离计算器还是完整的Dijkstra 算法?此外,如果您使用自己的自定义优先级队列,您也应该发布该代码。例如,如果您的优先级队列实现具有线性时间插入,则不同的算法将无济于事。
每次插入优先级队列都涉及动态内存分配(在函数new_helper()
中),这很慢。不过,这是否占运行时间的分钟数似乎值得怀疑。很可能,主要问题是次优的优先级队列。
我认为它很慢,因为优先级考虑profiling
【参考方案1】:
在开始分析当前顶点之前使用if(find_element(visited_vertexes, search, compare) == NULL)
解决了问题。这可以防止在优先级队列中再次插入已经访问和分析过的顶点。
【讨论】:
以上是关于除了使用 A* 之外,还有其他优化 Dijkstra 算法的方法吗?的主要内容,如果未能解决你的问题,请参考以下文章
Android:除了 Location.getAltitude() 之外,还有其他方法可以获取高度吗? (我听说过使用传感器)
除了显而易见的之外,Perlin Noise 还有其他用途吗?
除了使用“extern”关键字:n3290 草案之外,还有其他可能证明这一点的方法吗