环境:
- Win7 pro x64
- VS2010
- C ++
- 空项目
目标: 使用优先级队列实现Dijkstra的最短路径算法。
问题: 当程序运行时,它会导致Debug断言失败,表达式:无效的堆错误。如果用户将源顶点输入为1,则一切正常。断言仅在源顶点不是1时发生。此外,如果忽略断言,则代码最终完成并通过图形输出正确的路径。我猜这个错误与更改优先级队列中的指针指向的数据有关,但如果是这种情况,我不明白为什么使用1作为源允许代码成功完成。
感谢您的帮助!
头:
#ifndef _GRAPH_H_
#define _GRAPH_H_
#include <map>
#include <queue>
#include <vector>
#include <fstream>
using namespace std;
class Graph
{
public:
struct Vertex
{
int name; // V number
double dv; // distance
Vertex* pv; // previous V* from this V
map<Vertex*, double> neighbors; // map of all neighbors/distances connected to vert
};
vector<Vertex*> verts; // vector of all V*
void dijkstra(ifstream& stream, int start_vert); // create graph & find shortest paths
void printPath(Vertex* v); // echo path
class CompareVert // overloaded compare operator for priorty queue data struct, sort queue so V with smallest dist on top
{
public:
bool operator()(const Vertex* v1, const Vertex* v2) const
{
return v1->dv > v2->dv;
}
};
};
#endif
实施:
#include "Graph.h"
#include <iostream>
#include <queue>
#include <limits> // used for numeric_limits<double>::infinity()
#include <vector>
using namespace std;
int path_length = 0;
void Graph::printPath(Vertex* v) // print shortest paths
{
if (v->pv != NULL)
{
printPath(v->pv);
cout << " -> ";
}
cout << v->name;
}
void Graph::dijkstra(ifstream& stream, int start_vert) // create graph & get shortest path
{
/////////////////////////////////////////////
/////////////// create graph ////////////////
/////////////////////////////////////////////
int total_edges;
priority_queue<Vertex*, vector<Vertex*>, CompareVert> q;
double infinity = numeric_limits<double>::infinity();
int source;
int dest;
double dist;
stream >> total_edges;
for (int i=0;i<total_edges;i++)
{
stream >> source;
stream >> dest;
stream >> dist;
bool source_exists = false;
bool dest_exists = false;
Vertex* _source;
Vertex* _dest;
for (int i=0;i<verts.size();i++)
{
if (verts.at(i)->name == source) // vertex already exists, set to V
{
_source = verts.at(i);
source_exists = true;
break;
}
}
for (int i=0;i<verts.size();i++)
{
if (verts.at(i)->name == dest) // vertex already exists, set to V
{
_dest = verts.at(i);
dest_exists = true;
break;
}
}
if (!source_exists) // create vert
{
_source = new Vertex;
_source->name = source;
_source->dv = infinity;
_source->pv = NULL;
verts.push_back(_source);
}
if (!dest_exists) // create vert
{
_dest = new Vertex;
_dest->name = dest;
_dest->dv = infinity;
_dest->pv = NULL;
verts.push_back(_dest);
}
_source->neighbors.insert(pair<Vertex*, double>(_dest, dist)); // populate V's adjacency map
}
for (int i=0;i<verts.size();i++)
{
if (verts.at(i)->name == start_vert) // set source
{
verts.at(i)->dv = 0;
}
q.push(verts.at(i)); // push all vertices to priority queue
}
/////////////////////////////////////////////
//////////////// find paths ///////////////
/////////////////////////////////////////////
vector<int> displayed;
bool print; // flag to call printPath
while (!q.empty())
{
map<Vertex*, double>::iterator it;
Vertex* temp = q.top(); // get V with smallest dist
print = true;
for (it = temp->neighbors.begin(); it!=temp->neighbors.end();++it)
{
if ((temp->dv + it->second) < it->first->dv)
{
print = false;
it->first->dv = (temp->dv + it->second);
it->first->pv = temp;
q.push(it->first);
}
}
for (int i=0;i<displayed.size();i++) // if end V of path has already been printed, do not print
{
if (displayed.at(i) == temp->name)
print = false;
}
if (print == true)
{
printPath(temp);
path_length = temp->dv;
cout << " total distance = " << path_length <<endl << endl;
displayed.push_back(temp->name);
}
path_length = 0;
q.pop();
}
}
驱动器:
#include "Graph.h"
#include <stdio.h>
#include <iostream>
#include <string>
#include <fstream>
#include <list>
using namespace std;
string fname;
int vname;
string line;
int main(void)
{
cout << "Please enter the file to read in a graph (graph.txt): ";
cin >> fname;
cout << "Please choose a starting vertex (1 is a good choice): ";
cin >> vname;
cout << endl;
ifstream my_stream (fname);
Graph my_graph;
my_graph.dijkstra(my_stream, vname);
my_stream.close();
}
graph.txt:
12
1 2 2
1 4 1
2 4 3
2 5 10
3 1 4
3 6 5
4 3 2
4 5 2
4 6 8
4 7 4
5 7 6
7 6 1
答案 0 :(得分:1)
您应该在调用q.top()后立即从priority_queue中弹出顶部元素。相反,在使用q.push(it->first);
在我看来,这不是你想要的,因为你现在可能会弹出一个与你认为的顶级元素不同的元素。
答案 1 :(得分:1)
您可能正在推送Vertex
距离infinite
的实例。比较两个infinite
距离将导致它们中的任何一个更小,从而使比较器无效。
如果这是一个严格的学习练习,并且您实际上并不需要double
个距离,我建议您使用整数距离并使用“大”数代替infinite
。
使用N
位整数最好使用2^(N-3)
作为infinite
值,因为添加它们会产生2^(N-2)
,这仍然可以通过签名N来表示位整数(不是2^(N-1)
),它是一个比简单infinite
更大的值,即infinite + infinite > infinite
,它可以保持您的排序正确。
答案 2 :(得分:0)
您应该避免修改当前位于优先级队列中的元素,至少不要修改其优先级。
顶点的优先级由app.controller('PlaceController', function($scope, $http, searchData) {
$scope.fromSelected = '';
$scope.toSelected = '';
$scope.$watch('fromSelected', function(newValue, oldValue){
if (newValue !== oldValue) searchData.setTravelFrom(newValue);
});
$scope.$watch('toSelected', function(newValue, oldValue){
if (newValue !== oldValue) searchData.setTravelTo(newValue);
});
// Any function returning a promise object can be used to load values asynchronously
$scope.getPlace = function(term, locale) {
return $http.get('http://localhost:8080/api/places/search', {
params: {
term: term,
locale: locale
}
}).then(function(response){
return response.data.map(function(item){
return {
'id': item.id,
'name': item.name,
'readableName': item.name + ' (' + item.id + ')'
};
});
});
};
});
给出,这取决于CompareVert
的值。
在&#34;查找路径部分&#34;你有
dv
if ((temp->dv + it->second) < it->first->dv)
{
print = false;
it->first->dv = (temp->dv + it->second); // <-- here is the problem!
it->first->pv = temp;
q.push(it->first);
}
的分配会影响当前队列中的元素。当你调用q.push()时,队列意识到它处于无效状态并抱怨