补充上一个问题代码

来源:8-5 优化后的Prim算法的实现

易萧

2017-07-13

那个return 0是main.cpp就是最后结束程序的时候。我先贴个图:

http://szimg.mukewang.com/5966c9f90001ef8f08220541.jpg

main.cpp:

#include <iostream>
#include <vector>
#include "ReadGraphW.h"
#include "DenseGraphW.h"
#include "Edge.h"
#include "Prim.h"
using namespace std;

int main()
{
    vector<Edge<double> >vec;
    DenseGraphW<double> g1( 8, false );
    ReadGraphW<DenseGraphW<double>, double>( g1, "testG1.txt" );
    g1.show();
    cout<<endl;
    Prim<DenseGraphW<double>, double> p1( g1, g1.V() );
    /*如果不适用这个Prim算法,则不会崩溃*/
    p1.min_path( vec );
    for( int i=0 ; i<vec.size() ; i++ )
        cout<<vec[i]<<endl;
    cout<<"最小权值为:"<<p1.min_weight()<<endl;
    return 0;//就是在这里崩溃的
}

DensgraphW.h:

#ifndef DENSEGRAGH_H_INCLUDED
#define DENSEGRAGH_H_INCLUDED

#include <vector>
#include "Edge.h"
#include <iostream>
using namespace std;

template <class Value>
class DenseGraphW
{
    int v, e;
    bool direction;
    vector<vector<Edge<Value>* > > graph;
public:
    DenseGraphW( int n, bool dir )
    {
        int i;
        v = n;
        direction = dir;
        e = 0;
        for( i=0 ; i<n ; i++ )
            graph.push_back( vector<Edge<Value>* >(n, NULL) );
    }
    ~DenseGraphW()
    {
        for( int i=0 ; i<v ; i++)
            for( int j=0 ; j<v ; j++)
                if( graph[i][j] )
                    delete graph[i][j];
    }
    int V(){return v;}
    int E(){return e;}
    bool hasEdge( int a, int b ){return graph[a][b]!=NULL;}

    void addEdge( int a, int b, Value value )
    {
        if( hasEdge(a,b) )
        {
            graph[a][b]->change( value );
            if( !direction )
                graph[b][a]->change( value );
            return;
        }

        graph[a][b] = new Edge<Value>( a, b, value );
        if( !direction ) graph[b][a] = new Edge<Value>( b, a, value );
        e++;
    }

    void show()
    {
        int i,j;
        for( i=0 ; i<v ; i++ )
        {
            cout<<i<<":  ";
            for( j=0 ; j<v ; j++ )
                if( hasEdge( i,j ) )
                    cout<<j<<'('<<graph[i][j]->val()<<')'<<"  ";
            cout<<endl;
        }
    }

    class Iterator
    {
        DenseGraphW& G;
        int v, index;
    public:
        Iterator( DenseGraphW& g, int v ):G(g){ this->v = v; index = 0; }
        Edge<Value>* begin()
        {
            index = -1;
            return next();
        }
        Edge<Value>* next()
        {
            for( ++index ; index<G.V() ; ++index )
                if( G.graph[v][index] ) return G.graph[v][index];
            return NULL;
        }
        bool end(){return index>=G.V();}
    };
};

#endif // DENSEGRAGH_H_INCLUDED

ReadGraphW.h

#ifndef READGRAPH_H_INCLUDED
#define READGRAPH_H_INCLUDED

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;

template<class Graph, class Value>
class ReadGraphW
{
public:
    ReadGraphW( Graph& graph, const string& filename )
    {
        int V,E,i,a,b;Value c;
        string line;
        ifstream file(filename);
        getline(file, line);
        stringstream ss(line);
        ss>>V>>E;
        assert( file.is_open() );
        assert( graph.V()==V );
        for( i=0 ; i<E ; i++ )
        {
            getline(file, line);
            stringstream ss(line);
            ss>>a>>b>>c;
            graph.addEdge( a, b, c );
        }
    }
};
#endif // READGRAPH_H_INCLUDED

Edge.h

#ifndef EDGE_H_INCLUDED
#define EDGE_H_INCLUDED

#include <iostream>
using std::ostream;

template<class Value>
class Edge
{
    int v, w;
    Value value;
public:
    Edge( int v, int w, const Value& value )
    {
        this->v=v;
        this->w=w;
        this->value=value;
    }
    Edge(){}
    int other( int p ){ return p==v?w:v; }
    Value val()const { return value; }
    int V(){ return v;}
    int W(){ return w;}
    void change( const Value& value ){ this->value = value; }
    bool operator<( const Edge& e ){ return value<e.val(); }
        bool operator>( const Edge& e ){ return value>e.val(); }
        bool operator==( const Edge& e ){ return value==e.val(); }
        bool operator<=( const Edge& e ){ return value<=e.val(); }
        bool operator>=( const Edge& e ){ return value>=e.val(); }
    friend ostream& operator<<( ostream& out, const Edge& e ){
        return out<<e.v<<"-"<<e.w<<": "<<e.value;
    }
};
#endif // EDGE_H_INCLUDED

Prim.h

#ifndef PRIM_H_INCLUDED
#define PRIM_H_INCLUDED

#include "Edge.h"
#include "MinIndexHeap2.h"
#include <vector>
using namespace std;

template <class Graph, class Value>
class Prim
{
    Graph G;
    bool *visited;
    MIHeap2<Value> heap;
    vector<Edge<Value>* > edgeto;
    vector<Edge<Value> > vec;
    Value minw;

    void prim( int i )
    {
        class Graph::Iterator ite( G, i );
        Edge<Value> *p; int j;
        visited[i] = true;
        for( p=ite.begin() ; !ite.end(); p=ite.next() )
        {
            j=p->other(i);
            if( !visited[j] )
            {
                if( !edgeto[j] )
                {
                    heap.insert( j, p->val() );
                    edgeto[j] = p;
                }
                else if( p->val() < heap[j] )
                {
                    heap.change( j, p->val() );
                    edgeto[j] = p;
                }
            }
        }
    }

public:
    Prim( Graph& g, int v ):
    G(g), heap(v), vec(v-1)
    {
        int i,tmp;
        visited = new bool[v];
        for( i=0 ; i<v ; i++ )
        {
            visited[i] = false;
            edgeto.push_back(NULL);
        }
        vec.clear();
        prim(0);
        while( !heap.isEmpty() )
        {
            tmp = heap.popindex();
            vec.push_back( *edgeto[tmp] );
            prim(tmp);
        }
        minw=vec[0].val();
        for( i=1 ; i<vec.size() ; i++)
            minw+=vec[i].val();
    }
    ~Prim(){ delete []visited; }
    void min_path( vector<Edge<Value> >& vec_s ){ vec_s = vec; }
    Value min_weight() { return minw; }
};

#endif // PRIM_H_INCLUDED

以下是使用VS调试的时候弹出提示触发了一个断点:

http://szimg.mukewang.com/5966ce1c00010fc407310384.jpg

这是VS触发断点时弹出的一个名为debug_heap.cpp的文件里的,其中905和908都有问题,还有第1407行没有截图下来。这些我都看不懂。。。。下面是读到这一行时的监测窗口

http://szimg.mukewang.com/5966cec60001860409020187.jpg

由于长度限制,没有把MinIndexHeap2.h弄上来

写回答

1回答

liuyubobobo

2017-07-14

believe or not,你贴的编译器提示的错误,我也不懂。


但是我们可以推测啊!因为return 0前的cout被成功打印出来了。那么最后执行的就只有析构函数了。问题肯定出在析构函数上。请在你的所有类的析构函数中打上断点,或者在析构逻辑的开始和结尾加上输出。以Prim类为例:

~Prim(){ 
    cout << "Prim destructor begin." << endl;
    delete []visited; 
    cout << "Prim destructor end." << endl;
}

再看看崩溃在哪里发生,进而寻找为什么会崩溃。


一定不要忘了测试你没有贴上来的索引堆。另外,对于索引堆,包括这里的ReadGraph类,等等等等,都可以使用模块测试的方式。用索引堆完成一个排序看是不是有问题,简单验证一下我们的索引堆的正确性;同理,用ReadGraph读取一个图,输出相应信息试一下,验证ReadGraph的正确性,等等等等。如果能够确保每个模块儿的正确性,就可以进一步缩小错误发生的位置了。


虽然在有些时候,编译器提供的信息是有用的;但是当你犯的错误越“高级”,你就会发现编译器提供的错误越没用,有的时候甚至有迷惑作用。debug首先要学会的,是一点一点寻找错误产生的位置。


加油!

0
1
易萧
非常感谢!
2017-07-14
共1条回复

算法与数据结构(C++版) 面试/评级的算法复习技能包

课程专为:短时间内应对面试、升职测评等艰巨任务打造

11187 学习 · 1614 问题

查看课程