使用优先级队列时C ++调试断言失败,表达式:无效堆

时间:2011-05-02 00:49:47

标签: c++ priority-queue assertions

环境:
- 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

3 个答案:

答案 0 :(得分:1)

您应该在调用q.top()后立即从priority_queue中弹出顶部元素。相反,在使用q.push(it->first);

将新元素推入队列后,您会执行q.pop()

在我看来,这不是你想要的,因为你现在可能会弹出一个与你认为的顶级元素不同的元素。

答案 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()时,队列意识到它处于无效状态并抱怨