有向图(1.基于邻接表的C++实现)

http://www.cnblogs.com/SadGeminids/archive/2011/11/02/2233575.html

 最近按BOSS要求做一个有向图,基于邻接表的实现。大部分代码还是参考网上的,然后自己修改了一些细节。参考原帖地址:http://www.cppblog.com/saha/articles/121696.html

 

  先说优缺点吧:优点是基本功能都有了,而且还有Dijkstra算法求最短路径,使用的模板,适合各种数据;缺点是并不像他所说的那样适合大数据的图,另外就是要求一个顶点的逆邻接表(即所有以该顶点为弧头的边)时比较麻烦。

 

  我做过测试,加入10W条边需要20+ minutes,这是个让人无法忍受的时间。大家可以自己试一下,找找到底是哪里花费了大量时间。

 

  下一个博文分析算法效率低劣的原因,然后过几天会另外发一个基于十字链表的实现方式,而且效率至少提少2个数量级。

 

声明类头文件:

 

复制代码
#ifndef __GRAPH_H__
#define __GRAPH_H__

#include <vector>

#define  IN
#define OUT
#define INOUT
using namespace std;

namespace graphspace
{
    template <typename weight>
    struct Edge                        //
    {
       int nDestVertex;               //邻接顶点编号
        weight edgeWeight;             //边权重
        Edge<weight> *pNextEdge;       //下一条边

        Edge(int d, weight c, Edge<weight> *p = NULL)
            :nDestVertex(d), edgeWeight(c), pNextEdge(p)
        {}
    };

    template <typename vertexNametype, typename weight>
    struct Vertex                      //顶点
    {
        vertexNametype vertexName;     //顶点名
        Edge<weight> *pAdjEdges;       //邻接边链表

        Vertex(vertexNametype x, Edge<weight> *p = NULL)
            :vertexName(x), pAdjEdges(p)
        {}
    };

    //adjacency list based graph
    template <typename vertexNametype, typename weight>
    class ALGraph
    {
    public:
        explicit ALGraph();
        ~ALGraph();
    public:
        
        //插入结点
        bool insertAVertex(IN const vertexNametype vertexName); 

        //插入边
        bool insertAEdge(IN const vertexNametype vertexName1, IN const vertexNametype vertexName2, IN const weight edgeWeight);

        //边是否存在
        bool edgeExist(IN const vertexNametype vertexName1, IN const vertexNametype vertexName2);

        //输出顶点的邻接表
        void vertexAdjEdges(IN const vertexNametype vertexName);

        //删除边
        bool removeAEdge(IN const vertexNametype vertexName1, IN const vertexNametype vertexName2, IN const weight edgeWeight);

        //获取最小权
        weight getMinWeight(IN const vertexNametype vertexName1, IN const vertexNametype vertexName2);

        //获取顶点索引
        int getVertexIndex(IN const vertexNametype vertexName);

        //获取顶点数
        int getVertexNumber();

        //获取顶点名
        vertexNametype getData(IN int index);

        //迪科斯彻算法,最短路径
        int Dijkstra(IN const vertexNametype vertexName1);

        //输出迪科斯彻
        void DijkstraPrint(IN int index, IN int sourceIndex, IN vector<int> vecPreVertex);

        friend ostream& operator<<(OUT ostream &out, IN const ALGraph<vertexNametype,weight> &graphInstance);   

    public:
        
        //获取边权
        weight getEdgeWeight(IN const Edge<weight> *pEdge);

        //将顶点的所有邻接边的权值放入数组或者vector中
        void getVertexEdgeWeight(IN const int v1, OUT vector<weight> &DistanceArray);

        vector< Vertex<vertexNametype, weight> > m_vertexArray;
    };

#include "ALGraph_realize.h"

}

#endif
复制代码


 

实现类头文件:

复制代码
#ifndef __GRAPH_REALIZE__H_
#define __GRAPH_REALIZE__H_


template<typename vertexNametype, typename weight>
ALGraph<vertexNametype, weight>::ALGraph()
{
    //没做重复顶点处理,因为我需要的数据是从另一个系统所得,已经确保没有重复节点
    if (!m_vertexArray.empty())
    {
        m_vertexArray.clear();
    }
    
}

template<typename vertexNametype, typename weight>
ALGraph<vertexNametype, weight>::~ALGraph()
{
    vector< Vertex<vertexNametype, weight> >::iterator iter;
    for(iter = m_vertexArray.begin(); iter != m_vertexArray.end(); iter++)              //删除每个结点的邻接链表
    {
        Edge<weight> *p = iter->pAdjEdges;
        while(NULL != p)  //删除邻接链表
        {
            iter->pAdjEdges = p->pNextEdge;
            delete p;
            p = iter->pAdjEdges;
        }
    }
    if (!m_vertexArray.empty())
    {
        m_vertexArray.clear();
    }
}

template<typename vertexNametype, typename weight>
bool ALGraph<vertexNametype, weight>::insertAVertex(IN const vertexNametype vertexName)
{
    int v = getVertexIndex(vertexName);
    if (-1 != v)
    {
        cerr << "There vertex "<<vertexName<<" is existed!" << endl;
        return false;
    }

    Vertex<vertexNametype, weight> VertexInstance(vertexName, NULL);
    m_vertexArray.push_back(VertexInstance);

    return true;
}

template<typename vertexNametype, typename weight>
bool ALGraph<vertexNametype, weight>::insertAEdge(IN const vertexNametype vertexName1, 
                            IN const vertexNametype vertexName2, IN const weight edgeWeight)
{
    int v1 = getVertexIndex(vertexName1);
    if (-1 == v1)
    {
        cerr << "There is no vertex 1" << endl;
        return false;
    }

    int v2 = getVertexIndex(vertexName2);
    if (-1 == v2)
    {
        cerr << "There is no vertex 2" << endl;
        return false;
    }

    Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges;
    while(p != NULL && p->nDestVertex != v2)     //邻接链表是否存在,并且搜索V2是否已经在邻接表中了
    {
        p = p->pNextEdge;
    }

    if (NULL == p)                 //邻接表为空,或没找到顶点V2,则添加一条边
    {
        p = new Edge<weight>(v2, edgeWeight, m_vertexArray.at(v1).pAdjEdges);    
        m_vertexArray.at(v1).pAdjEdges = p;
        return true;
    }
    if (v2 == p->nDestVertex)      //若V1,V2之间已有一条边,则加一条新的边到已存在的第一条V1->V2边之后
    {
        Edge<weight> *q = p;
        p = new Edge<weight>( v2, edgeWeight, q->pNextEdge );
        q->pNextEdge = p;
        return true;
    }
    
    return false;
}

template<typename vertexNametype, typename weight>
bool ALGraph<vertexNametype, weight>::edgeExist(IN const vertexNametype vertexName1, 
                            IN const vertexNametype vertexName2)
{
    int v1 = getVertexIndex(vertexName1);
    if (-1 == v1)
    {
        cerr << "There is no vertex 1" << endl;
        return false;
    }

    int v2 = getVertexIndex(vertexName2);
    if (-1 == v2)
    {
        cerr << "There is no vertex 2" << endl;
        return false;
    }

    Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges;
    while(p != NULL && p->nDestVertex != v2)    
    {
        p = p->pNextEdge;
    }

    if(NULL == p)
    {
        cout<<"dont exist"<<endl;
        return false;
    }
    if(v2 == p->nDestVertex)
    {
        cout<<"exist"<<endl;
        cout << vertexName1 << ":    ";

        while(p != NULL && p->nDestVertex == v2)     //如果v1->v2之间有几条不同的边,都输出
        {
            cout << "(" << vertexName1 << "," << vertexName2 << "," << p->edgeWeight << ")  ";
            p = p->pNextEdge;
        }
        cout << endl;
        return true;
    }
}

template<typename vertexNametype, typename weight>
void ALGraph<vertexNametype, weight>::vertexAdjEdges(IN const vertexNametype vertexName)
{
    int v1 = getVertexIndex(vertexName);
    if( -1 == v1)
    {
        cerr<<"There is no vertex: "<<vertexName<<endl;
        return ;
    }

    Edge<weigh> *p = m_vertexArray.at(v1).pAdjEdges;
    cout << vertexName << ":    ";
    while( p != NULL)
    {
        cout<<"(" << vertexName << "," << getData(p->nDestVertex) <<"," << p->edgeWeight <<") ";
    }
    cout<<endl;
}

template<typename vertexNametype, typename weight>
bool ALGraph<vertexNametype, weight>::removeAEdge(IN const vertexNametype vertexName1, 
                                          IN const vertexNametype vertexName2, IN const weight edgeWeight)
{
    int v1 = getVertexIndex(vertexName1);
    if (-1 == v1)
    {
        cerr << "There is no vertex 1" << endl;
        return false;
    }

    int v2 = getVertexIndex(vertexName2);
    if (-1 == v2)
    {
        cerr << "There is no vertex 2" << endl;
        return false;
    }

    Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges;
    Edge<weight> *q = NULL;                
    while(p != NULL && p->nDestVertex != v2 )
    {
        q = p;
        p = p->pNextEdge;
    }
    if (NULL == p)
    {
        cerr << "Edge is not found" << endl;
        return false;
    }
    while( edgeWeight != p->edgeWeight && p->nDestVertex == v2)    //搜索相同边
    {
        q = p;
        p = p->pNextEdge;
    }
    if (v2 != p->nDestVertex)
    {
        cerr << "Edge is not found" << endl;
        return false;
    }

    if( q == NULL )                                  //m_vertexArray.at(v1).pAdjEdges所指的值即为所求时
        m_vertexArray.at(v1).pAdjEdges = p->pNextEdge;
    else
      q->pNextEdge = p->pNextEdge;                   //这里如果同一条边有好几个相同值,只会删除一次
    delete p;

    return true;
}

template<typename vertexNametype, typename weight>
weight ALGraph<vertexNametype, weight>::getEdgeWeight(IN const Edge<weight> *pEdge)
{
    return pEdge->edgeWeight;
}

template<typename vertexNametype, typename weight>
void ALGraph<vertexNametype, weight>::getVertexEdgeWeight(IN const int v1, OUT vector<weight> &DistanceArray)
{
    Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges;
    int prevIndex = -1;
    weight tmp;

    while(NULL != p)
    {
        //需考虑相同边的存在,取最小的一个值
        if (prevIndex == p->nDestVertex)
        {
            if (tmp > p->edgeWeight)
            {
                DistanceArray[prevIndex] = p->edgeWeight;
            }
        }
        else
        {
            DistanceArray[p->nDestVertex] = p->edgeWeight;
            prevIndex = p->nDestVertex;
            tmp = p->edgeWeight;
        }
        
        p = p->pNextEdge;
    }
}

template<typename vertexNametype, typename weight>
weight ALGraph<vertexNametype, weight>::getMinWeight(IN const vertexNametype vertexName1, 
                                          IN const vertexNametype vertexName2)
{
    Edge<weight> *pEdge = NULL;
    int v1 = getVertexIndex(vertexName1);
    if (-1 == v1)
    {
        cerr << "There is no vertex 1" << endl;
        return false;
    }

    int v2 = getVertexIndex(vertexName2);
    if (-1 == v2)
    {
        cerr << "There is no vertex 2" << endl;
        return false;
    }

    Edge<weight> *p = m_vertexArray.at(v1).pAdjEdges;
    while (p != NULL && p->nDestVertex != v2)
    {
        p = p->pNextEdge;
    }
    if (NULL == p)
    {
        pEdge = NULL;
        return weight(0);
    }
    weight tmp = getEdgeWeight(p);
    pEdge = p;
    while (NULL != p && v2 == p->nDestVertex)   //相同边,取权值最小的一条
    {
        if (tmp > getEdgeWeight(p))
        {
            tmp = getEdgeWeight(p);
            pEdge = p;
        }
        p = p->pNextEdge;
    }
    return tmp;
}

template<typename vertexNametype, typename weight>
int ALGraph<vertexNametype, weight>::getVertexIndex(IN const vertexNametype vertexName)
{
    for (int i = 0; i < m_vertexArray.size(); i++)
    {
        if (vertexName == getData(i))
        {
            return i;
        }
    }
    return -1;
}

template<typename vertexNametype, typename weight>
int ALGraph<vertexNametype, weight>::getVertexNumber()
{
    return m_vertexArray.size();
}

template<typename vertexNametype, typename weight>
vertexNametype ALGraph<vertexNametype, weight>::getData(IN int index)
{
    return m_vertexArray.at(index).vertexName;
}

template<typename vertexNametype, typename weight>
int ALGraph<vertexNametype, weight>::Dijkstra(IN const vertexNametype vertexName1)
{
    int sourceIndex = getVertexIndex(vertexName1);
    if (-1 == sourceIndex)
    {
        cerr << "There is no vertex " << endl;
        return false;
    }
    int nVertexNo = getVertexNumber();

    //the array to record the points have been included, if included the value is true
    //else is false
    vector<bool> vecIncludeArray;
    vecIncludeArray.assign(nVertexNo, false);
    vecIncludeArray[sourceIndex] = true;

    //the array to record the distance from vertex1
    vector<weight> vecDistanceArray;
    vecDistanceArray.assign(nVertexNo, weight(INT_MAX));
    vecDistanceArray[sourceIndex] = weight(0);

    //prev array to record the previous vertex
    vector<int> vecPrevVertex;
    vecPrevVertex.assign(nVertexNo, sourceIndex);

    getVertexEdgeWeight(sourceIndex, vecDistanceArray);

    int vFrom, vTo;

    while(1)
    {
        weight minWeight = weight(INT_MAX);
        vFrom = sourceIndex;
        vTo = -1;
        for (int i = 0; i < nVertexNo; i++)
        {
            if (!vecIncludeArray[i] && minWeight > vecDistanceArray[i])
            {
                minWeight = vecDistanceArray[i];
                vFrom = i;
            }
        }
        if (weight(INT_MAX) == minWeight)
        {
            break;
        }
        vecIncludeArray[vFrom] = true;

        Edge<weight> *p = m_vertexArray[vFrom].pAdjEdges;
        while (NULL != p)
        {
            weight wFT = p->edgeWeight;
            vTo = p->nDestVertex;
            if (!vecIncludeArray[vTo] && vecDistanceArray[vTo] > wFT + vecDistanceArray[vFrom])
            {
                vecDistanceArray[vTo] = wFT + vecDistanceArray[vFrom];
                vecPrevVertex[vTo] = vFrom;
            }
            p = p->pNextEdge;
        }
                
    }

    //print the shortest route of all vertexes
    for (int i = 0; i < nVertexNo; i++)
    {
        if (weight(INT_MAX) != vecDistanceArray[i])
        {
            cout << getData(sourceIndex) << "->" << getData(i) << ": ";
            DijkstraPrint(i, sourceIndex, vecPrevVertex);
            cout << "" << vecDistanceArray[i];
            cout << endl;
        }
    }

    return 0;
}

template<typename vertexNametype, typename weight>  
void ALGraph<vertexNametype, weight>::DijkstraPrint(IN int index, IN int sourceIndex, IN vector<int> vecPreVertex)
{
    if (sourceIndex != index)
    {
        DijkstraPrint(vecPreVertex[index], sourceIndex, vecPreVertex);
    }
    cout << getData(index) << "";
}

template<typename vertexNametype, typename weight>   
ostream& operator<<(OUT ostream &out, IN  ALGraph<vertexNametype,weight> &graphInstance)
{
    int vertexNo = graphInstance.getVertexNumber();
    out << "This graph has " << vertexNo << "vertexes" << endl;

    for(int i = 0; i < vertexNo; i++)
    {
        vertexNametype x1 = graphInstance.getData(i);
        out << x1 << ":    ";

        Edge<weight> *p = graphInstance.m_vertexArray.at(i).pAdjEdges;
        while (NULL != p)
        {
            out << "(" << x1 << "," << graphInstance.getData(p->nDestVertex) << "," << p->edgeWeight << ")  ";
            p = p->pNextEdge;
        }
        out << endl;
    }
    return out;
}

#endif
复制代码

 

主程序:

复制代码
#include <iostream>
#include <ctime>
#include <string>
#include "ALGraph.h"

using namespace std;
using namespace graphspace;

int main()
{
    ALGraph<string, int> g;
    clock_t start1,finish1;
    double duration;

    
    g.insertAVertex("A");
    g.insertAVertex("B");
    g.insertAEdge("A", "B", 16);
    g.insertAEdge("A", "B", 26);
    g.insertAEdge("A", "B", 36);
    g.insertAEdge("A", "B", 46);
    g.insertAEdge("A", "B", 6);

    g.insertAVertex("C");
    g.insertAVertex("D");
    g.insertAVertex("E");
    g.insertAVertex("F");
    cout<<g<<endl<<endl;

    g.insertAEdge("A", "B", 6);
    g.insertAEdge("A", "C", 3);
    g.insertAEdge("B", "C", 2);
    g.insertAEdge("B", "D", 5);
    g.insertAEdge("C", "D", 3);
    g.insertAEdge("C", "E", 4);
    g.insertAEdge("D", "E", 2);
    g.insertAEdge("D", "F", 3);
    g.insertAEdge("E", "F", 5);


    g.insertAEdge("B", "A", 6);
    g.insertAEdge("C", "A", 3);
    g.insertAEdge("C", "B", 2);
    g.insertAEdge("D", "B", 5);
    g.insertAEdge("D", "C", 3);
    g.insertAEdge("E", "C", 4);
    g.insertAEdge("E", "D", 2);
    g.insertAEdge("F", "D", 3);
    g.insertAEdge("F", "E", 5);

    cout<<g<<endl<<endl;

    g.Dijkstra("A");
    
    /*
    char vertex[9];
    srand((unsigned)time(0));
    string str[10000];

    for(int i=0; i<10000; i++)      //随机生成1 W个顶点
    {
        for(int j=0; j<8; j++)
        {
            vertex[j] = rand()%26 + 97;
            str[i] += vertex[j];
        }
        g.insertAVertex(str[i]);
    }
    cout<<g<<endl<<endl;

    for(int i=0; i<100000; i++)    //随机生成10W条边
    {
        int num1 = rand()%10000;
        int num2 = rand()%10000;
        int num3 = rand()%10;
        g.insertAEdge(str[num1], str[num2], num3);
    }

    string lastname = "test";
    g.insertAVertex(lastname);
    for(int i=0; i<5000; i++)     //单个顶点关联的边并不多,这里单独加一个顶点,关联5K条边
    {
        int num5 = rand()%10000;
        int num6 = rand()%10000;
        g.insertAEdge(lastname, str[num5], num6);
    }
    cout<<g<<endl<<endl;
    
    string vertex1;
    string vertex2;
    cout<<"entry 2 vertem name"<<endl;
    cin>>vertex1;
    cin>>vertex2;
    while(vertex1 != "q")
    {
        start1 = clock();
        g.edgeExist(vertex1, vertex2);
        finish1 = clock();
        duration = (double)(finish1 - start1) / CLOCKS_PER_SEC; 
        cout<<duration<<" seconds"<<endl;
        cout<<"entry 2 vertem name"<<endl;
        cin>>vertex1;
        cin>>vertex2;
    }
    */
    system("pause");
    return 0;
}
复制代码


运行结果:


 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值