C++ C++;使用优先级队列调试断言时失败,表达式:无效堆
环境:C++ C++;使用优先级队列调试断言时失败,表达式:无效堆,c++,priority-queue,assertions,C++,Priority Queue,Assertions,环境: -Win7 pro x64 -VS2010 -C++ -空项目 目标: 使用优先级队列实现Dijkstra最短路径算法 问题: 当程序运行时,它得到一个调试断言失败,表达式:无效堆错误。如果用户将源顶点输入为1,则一切正常。仅当源顶点不是1时,才会发生断言。此外,如果忽略断言,代码最终将完成并通过图形输出正确的路径。我猜这个错误与更改优先级队列中指针指向的数据有关,但如果是这种情况,我不明白为什么使用1作为源代码可以成功完成代码 谢谢你的帮助 标题: #ifndef _GRAPH_H_
-Win7 pro x64
-VS2010
-C++
-空项目 目标: 使用优先级队列实现Dijkstra最短路径算法 问题: 当程序运行时,它得到一个调试断言失败,表达式:无效堆错误。如果用户将源顶点输入为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
您应该在调用q.top()之后立即从priority_队列中弹出top元素。而是在使用
q.push(it->first)将新元素推入队列后执行q.pop()代码>
在我看来,这并不是您想要的,因为您现在可能会弹出一个与您认为的顶级元素不同的元素 您可能正在推送距离为无限的顶点
实例。比较两个无限
距离将不会产生一个比另一个小的距离,从而使比较器无效
如果这是一个严格的学习练习,并且您实际上不需要double
距离,我建议您使用整数距离,并使用“大”数代替infinite
使用N
位整数使用2^(N-3)
作为infinite
值是一个好主意,因为将它们相加将产生2^(N-2)
,它仍然可以用有符号的N位整数(不是2^(N-1)
)表示,并且它的值比简单的infinite
大,也就是说,infinite+infinite>infinite
,这样可以保持您的顺序正常。您应该避免修改当前在优先级队列中的元素,至少不要以修改其优先级的方式进行修改。
顶点的优先级由CompareVert
给出,它取决于dv
的值。
在“查找路径部分”中
if((temp->dv+it->second)first->dv)
{
打印=假;
it->first->dv=(temp->dv+it->second);//first->pv=temp;
q、 推(它->第一);
}
对dv
的赋值会影响队列中当前的元素。当您调用q.push()时,队列意识到它处于无效状态并抱怨您是否尝试在调试器中单步执行代码?我尝试过。似乎是push_堆调用导致了它。你的意思是push_back
?@Oli,实际上是push_back,但更准确地说,当我进入代码时,优先级队列从“算法”include使用的是push_堆调用。在将q.top()分配给temp之后,我尝试将代码更改为q.pop()。不幸的是,错误仍然会发生,更糟糕的是,无论选择哪个顶点作为源,错误都会发生,包括1。从算法上讲,将pop()放在top()之后是正确的做法,尽管它不能解决问题。也许你有一些未初始化的东西。我会试着在你的优先队列中注释掉一些东西,看看会发生什么。第一件事是注释掉顶点结构中的映射。你的结构顶点只是有一堆数据成员,这就是为什么我立即怀疑某些东西没有正确初始化的原因。
#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();
}
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
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);
}