• 数据结构作业笔记二


    有向网的邻接矩阵存储结构的设计与实现,要求:

    (1)实现图的基本运算;求各个顶点的入度和出度;

    (2)完成最短路径(Dijkstra和Floyd)和关键路径算法的实现。

    主要代码如下:

    #ifndef ADJMATRIXDIRGRAPH_H
    #define ADJMATRIXDIRGRAPH_H
    #include "Assistance.h"
    #include "LinkStack.h"
    #include "LinkQueue.h"
    
    #define infinity 10000
    
    //有向图的邻接矩阵表示
    template <class ElemType>
    class AdjMatrixDirGraph
    {
    protected:
    // 邻接矩阵的数据成员:
        int vexNum, vexMaxNum, arcNum;            // 顶点数目、允许的顶点最大数目和边数
        int **arcs;                                // 存放边信息邻接矩阵
        ElemType *vertexes;                        // 存放顶点信息的数组 
        mutable Status *tag;                    // 标志数组
    public:
        AdjMatrixDirGraph(ElemType es[], int vertexNum, int vertexMaxNum = DEFAULT_SIZE);
        // 以数组es[]为顶点,顶点个数为vertexNum,允许的顶点最大数目为vertexMaxNum,边数为0的有向图
        AdjMatrixDirGraph(int vertexMaxNum = DEFAULT_SIZE);
        // 构造允许的顶点最大数目为vertexMaxNum,边数为0的无向图
        ~AdjMatrixDirGraph();                        //析构函数
        void Clear();                                  // 清空图             
        bool IsEmpty();                             // 判断无向图是否为空 
        int GetOrder(ElemType &d) const;            // 求顶点的序号    
        Status GetElem(int i, ElemType &d) const;    // 求顶点的元素值    
        Status SetElem(int i, const ElemType &d);    // 设置顶点的元素值
        int GetVexNum() const;                        // 返回顶点个数             
        int GetArcNum() const;                        // 返回边数             
        int FirstAdjVex(int i) const;                // 返回顶点v的第一个邻接点             
        int NextAdjVex(int v1, int v2) const;        // 返回顶点v1的相对于v2的下一个邻接点
        int GetWeight(int v1, int v2) const;        // 返回边的权值             
        void InsertVex(const ElemType &d);             // 插入元素值为d的顶点         
        void InsertArc(int v1, int v2, int weight);    // 插入顶点为v1和v2的边             
        void DeleteVex(const ElemType &d);            // 删除元素值为d的顶点             
        void DeleteArc(int v1, int v2);                // 删除顶点为v1和v2的边             
        Status GetTag(int v) const;                    // 返回顶点v的标志         
        void SetTag(int v, Status val) const;           // 设置顶点v的标志为val
        AdjMatrixDirGraph(const AdjMatrixDirGraph<ElemType> &g);    // 复制构造函数
        AdjMatrixDirGraph<ElemType> &operator =(const AdjMatrixDirGraph<ElemType> &g); // 赋值语句重载
        void Display();                                 // 显示邻接矩阵有向图
        int InDegree(const ElemType &d);            //求某一顶点的入度
        int OutDegree(const ElemType &d);            //求某一顶点的出度
        void ShortestPathDij(const ElemType &d);      //Dijkstra最短路径算法 
        void ShortesPathFloyed();                    //Floyed算法求最短路径算法
        void CriticalPath();                        //求关键路径 
    };
    // 有向图的邻接矩阵类的实现部分
    template <class ElemType>
    AdjMatrixDirGraph<ElemType>::AdjMatrixDirGraph(ElemType es[], int vertexNum, int vertexMaxNum)
    {
        if(vertexNum < 0)
            throw Error("最大顶点数不能为负数!!!");  //抛出异常
        if(vertexMaxNum < vertexNum)
            throw Error("输入的顶点数超过最大顶点数!!!");
        vexNum = vertexNum;
        vexMaxNum = vertexMaxNum;
        arcNum = 0;
    
        vertexes = new ElemType[vexMaxNum];
        tag = new Status[vexMaxNum];
        arcs =  new int *[vexMaxNum];
        for(int i = 0; i < vexMaxNum; i++)
            arcs[i] = new int[vexMaxNum];
    
        for (int i = 0; i < vexNum; i++) 
        {
            vertexes[i] = es[i];
            tag[i] = UNVISITED;
            for (int j = 0; j < vexNum; j++)
            {
                arcs[i][j] = infinity;        //给定无穷值,表示两顶点之间无边相连
                if(i == j)
                    arcs[i][j] = 0;            //对角线的值赋值为0,我们不考虑环,方便后续处理
            }
        }
    }
    
    template <class ElemType>
    AdjMatrixDirGraph<ElemType>::AdjMatrixDirGraph(int vertexMaxNum)
    {
        if(vertexMaxNum < 0)
            throw Error("最大顶点数不能为负数!!!");
        
        vexNum = 0;
        vexMaxNum = vertexMaxNum;
        arcNum = 0;
    
        vertexes = new ElemType[vexMaxNum];
        tag = new Status[vexMaxNum];
        arcs = new int*[vexMaxNum];
        for(int i = 0; i < vexMaxNum; i++)
        {
            arcs[i] = new int[vexMaxNum];
        }
    }
    
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::Clear()
    {
        vexNum = 0;
        arcNum = 0;
    }
    
    template <class ElemType>
    bool AdjMatrixDirGraph<ElemType>::IsEmpty()
    //判断是否为空
    {
        return vexNum = 0;
    }
    
    template <class ElemType>
    AdjMatrixDirGraph<ElemType>::~AdjMatrixDirGraph()
    //析构函数
    {
        delete []vertexes;
        delete []tag;
    
        for(int i = 0; i < vexMaxNum; i++)
        {
            delete []arcs[i];
        }
        delete []arcs;
    }
    
    template <class ElemType>
    int AdjMatrixDirGraph<ElemType>::GetOrder(ElemType &d) const //已知元素找序号 
    //求顶点序号,顶点信息在vertexes数组中,从中即可获得顶点的信息
    {
        for(int i = 0; i < vexNum; i++)
        {
            if(vertexes[i] == d)
                return i;
        }
        return -1;
    }
    
    template <class ElemType>
    Status AdjMatrixDirGraph<ElemType>::GetElem(int i, ElemType &d) const    //已知序号找元素
    //求顶点的元素值,根据i的序号值,来找到对应元素
    {
        if(i < 0 || i > vexNum)
            return NOT_PRESENT;  //范围错误,返回元素不存在
        else 
        {
            d = vertexes[i];
            return ENTRY_FOUND;
        }
    }
    
    template <class ElemType>
    Status AdjMatrixDirGraph<ElemType>::SetElem(int i, const ElemType &d)
    //根据顶点的序号,来重新设置该顶点的值 
    {
        if( i < 0 || i > vexNum) 
            return RANGE_ERROR;
        else 
        {
            vertexes[i] = d;
            return SUCCESS;    
        } 
    }
    
    template <class ElemType>
    int AdjMatrixDirGraph<ElemType>::GetVexNum() const    //返回顶点数
    {
        return vexNum;
    }
    
    template <class ElemType>
    int AdjMatrixDirGraph<ElemType>::GetArcNum() const    //返回边数
    {
        return arcNum;
    }
    
    template <class ElemType>
    int AdjMatrixDirGraph<ElemType>::FirstAdjVex(int i) const
    //返回顶点的第1个邻接点的序号
    {
        if(i < 0 || i > vexNum)
            throw Error("输入不合法");
        
        for(int j = 0; j < vexNum; i++)
        {
                if (arcs[i][j] != 0 && arcs[i][j] != infinity) {
                    return j;
                }    
        }
    }
    
    template <class ElemType>
    int AdjMatrixDirGraph<ElemType>::NextAdjVex(int v1, int v2) const
    //返回顶点v1相对于v2的下一个邻接点
    {
        if(v1 < 0 || v1 >= vexNum)
            throw Error("v1不合法");
        if(v2 < 0 || v2 >= vexNum)
            throw Error("v2不合法");
        if(v1 == v2)
            throw Error("v1不能等于v2");
    
        for(int i = v2 + 1; i < vexNum; i++)
        {
            if (arcs[v1][i] != 0 && arcs[v1][i] != infinity) {
                return i;
            }
        }
        return -1;
    }
    
    //返回边的权值 
    template <class ElemType>
    int  AdjMatrixDirGraph<ElemType>::GetWeight(int v1, int v2) const
    {
        if(v1 < 0 || v1 >= vexNum)
            throw Error("v1不合法");
        if(v2 < 0 || v2 >= vexNum)
            throw Error("v2不合法");
        return arcs[v1][v2];
    }
    
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::InsertVex(const ElemType &d)
    //插入顶点d
    {
        if(vexNum == vexMaxNum)
            throw Error("顶点数已经达到最大值,无法继续插入元素");
    
        vertexes[vexNum] = d;                //这里将顶点信息记录到vertexes中
        tag[vexNum] = UNVISITED;
        for(int i = 0; i < vexNum; i++)
        {
            arcs[vexNum][i] = infinity;
            arcs[i][vexNum] = infinity;
        }
        cout << "  " << vexNum << endl;
        vexNum++;
    }
    
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::InsertArc(int v1, int v2, int weight)
    //插入依附于顶点的边
    {
        if (v1 < 0 || v1 >= vexNum)
            throw Error("v1不合法!!!");
        
        if (v2 < 0 || v2 >= vexNum)
            throw Error("v2不合法!!!");
        if (v1 == v2)
            throw Error("v1不能等于v2!!!");
    
        if(arcs[v1][v2] == infinity)    //原图中没有改变,则添加该边
        {
            arcNum++;
            arcs[v1][v2] = weight;
        }
    }
    
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::DeleteVex(const ElemType &d)
    //删除元素为d的顶点
    {
        int i;
        for(i = 0; i < vexNum; i++)        //遍历查询该点
        {
            if(vertexes[i] == d)
                break;
        }
    
        if(i == vexNum)
            throw Error("不存在该点!!!");
        
        for(int j = 0; j < vexNum; j++)
        {
            if(arcs[i][j] != infinity && i != j)
            {
                arcNum--;
                arcs[i][j] = infinity;
                arcs[j][i] = infinity;
            }
        }
    
        vexNum--;    //用最后一行将空白行填充
        if(i < vexNum)
        {
            vertexes[i] = vertexes[vexNum];
            tag[i] = tag[vexNum];
            for(int j = 0; j <= vexNum; j++)
            {
                arcs[i][j] = arcs[vexNum][j];
                arcs[j][i] = arcs[j][vexNum];
            }
        }
    }
    
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::DeleteArc(int v1, int v2)
    //删除依附于顶点的边
    {
        if (v1 < 0 || v1 >= vexNum)
            throw Error("v1不合法!");    
        if (v2 < 0 || v2 >= vexNum)
            throw Error("v2不合法!");    
        if (v1 == v2)
            throw Error("v1不能等于v2!");
    
        if(arcs[v1][v2] != infinity && arcs[v1][v2] != 0)
        {
            arcNum--;
            arcs[v1][v2] = infinity;
        }
    }
    
    template <class ElemType>
    Status AdjMatrixDirGraph<ElemType>::GetTag(int v) const
    //返回顶点的标志
    {
        if(v < 0 || v >= vexNum)
            throw Error("v不合法");
    
        return tag[v];
    }
    
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::SetTag(int v, Status val) const
    {
        if(v < 0 || v >= vexNum)
            throw Error("v不合法");
        
        tag[v] = val;
    }
    
    
    template <class ElemType>
    AdjMatrixDirGraph<ElemType>::AdjMatrixDirGraph(const AdjMatrixDirGraph<ElemType> &g)
    //赋值构造函数
    {
        vexNum = g.vexNum;
        vexMaxNum = g.vexMaxNum;
        arcNum = g.arcNum;
    
        vertexes = new ElemType[vexMaxNum];
        tag = new Status[vexMaxNum];
        arcs = new int *[vexMaxNum];
        for(int i = 0; i < vexMaxNum; i++)
            arcs[i] = new int[vexMaxNum];
        
        for(int i = 0; i < vexNum; i++)
        {
            vertexes[i] = g.vertexes[i];
            tag[i] = g.tag[i];
            for(int j = 0; j < vexNum; j++)
                arcs[i][j] = g.arcs[i][j];
        }
    }
    
    template <class ElemType>
    AdjMatrixDirGraph<ElemType> &AdjMatrixDirGraph<ElemType>::operator=(const AdjMatrixDirGraph<ElemType> &g)
    //赋值语句重载
    {
        if(&g != this)
        {
            delete []vertexes;
            delete []tag;
    
            for(int i = 0; i < vexMaxNum; i++)
                delete []arcs[i];
            delete []arcs;
    
            vexNum = g.vexNum;
            vexMaxNum = g.vexMaxNum;
            arcNum = g.arcNum;
    
            vertexes = new ElemType[vexMaxNum];
            tag = new Status[vexMaxNum];
            arcs = new int* [vexMaxNum];
            for(int i = 0; i < vexMaxNum; i++)
                arcs[i] = new int[vexMaxNum];
    
            for(int i = 0; i<vexNum; i++) //复制数据
            {
                vertexes[i] = g.vertexes[i];
                tag[i] = g.tag[i];
                for(int j = 0; j < vexNum; j++)
                    arcs[i][j] = g.arcs[i][j];
            }
        }
        return *this;
    }
    
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::Display()
    {
        cout << "	" << "该有向图的邻接矩阵如下所示" << endl; 
        for (int v = 0; v < vexNum; v++)
             cout << "	" << vertexes[v];
        cout << endl;
    
        for (int v = 0; v < vexNum; v++)    
        {
            cout << vertexes[v];
            for (int u = 0; u < vexNum; u++)
            {
                if(arcs[v][u] != infinity)                    
                    cout << "	" << arcs[v][u];
                else 
                    cout << "	" << "";
            }
            cout << endl;
        }
    }
    
    //求图某点的入度 
    template <class ElemType>
    int  AdjMatrixDirGraph<ElemType>::InDegree(const ElemType &d)
    {
        int i = -1;
        int count = 0;
        for(int j = 0; j < vexNum; j++)
        {
            if(vertexes[j] == d)
                i = j; 
        }
        if(i == -1) return -1;
        
        for(int j = 0; j < vexNum; j++)
            if(i != j && arcs[j][i] != infinity)
                count++;
        
        return count;
    }
    
    //求图某点的出度 
    template <class ElemType>
    int  AdjMatrixDirGraph<ElemType>::OutDegree(const ElemType &d)
    {
        int i = -1;
        int count = 0;
        for(int j = 0; j < vexNum; j++)
        {
            if(vertexes[j] == d)
                i = j; 
        }
        if(i == -1) return -1;
        
        for(int j = 0; j < vexNum; j++)
            if(i != j && arcs[i][j] != infinity)
                count++;
                
        return count;            
    }
    
    //求某一点最短路径 
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::ShortestPathDij(const ElemType &d)
    {
        int v0 = -1;
        int count = 0;
        for(int j = 0; j < vexNum; j++)
        {
            if(vertexes[j] == d)
                v0 = j; 
        }
        if(v0 == -1)
        {
            cout << "该点不存在,无法求出";
            return ; 
        } 
        int path[vexNum];//设置path数组来存储前驱 
        int dist[vexNum];//设置dist数组来存储权值 
        int i, j, minVal;
        for(i = 0; i < vexNum; i++)
        {
            dist[i] = arcs[v0][i];    
            if(dist[i] == infinity || i == v0)
                path[i] = -1;
            else 
                path[i] = v0;
            SetTag(i, UNVISITED);                //将顶点标志设为未访问 
        }
        SetTag(v0, VISITED);                        //将v0点设置为未访问 
        
        for(int  v = 0; v < vexNum; v++) 
        {
            minVal = infinity;
            j = v0;
            for(i = 0; i < vexNum; i++)
            {
                if(GetTag(i) == UNVISITED && dist[i] < minVal)//根据顶点状态和权值大小判断是否执行 
                {
                    j = i;
                    minVal = dist[i];
                }
            }
            SetTag(j, VISITED);
            
            for(i = 0; i < vexNum; i++)
            {
                if(GetTag(i) == UNVISITED && minVal + arcs[j][i] < dist[i])
                {
                    dist[i] = minVal + arcs[j][i];
                    path[i] = j;
                } 
            }
        } 
         
        //输出最大路径值
        LinkStack<int> stack;
        int num;
        for(i = 0; i < vexNum; i++)
        {
            num = path[i];
            if(i != v0)
            {
                while(i != v0 && num != -1)
                {
                    stack.Push(num);
                    num = path[num];
                
                }
                if(dist[i] != infinity)
                    cout << vertexes[v0] << "" << vertexes[i] << "的最短路径为" << dist[i] << ",路径为";
                else 
                    cout << vertexes[v0] << "" << vertexes[i] << "的最短路径不存在";
                while(!stack.IsEmpty())
                {
                    stack.Pop(num);
                    cout << vertexes[num] << "->";
                }
                cout << vertexes[i];
                cout << endl;    
            }    
        }    
    }
    
    //求全部顶点的最短路径 
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::ShortesPathFloyed()
    {
        int path[vexNum][vexNum];
        int dist[vexNum][vexNum];
        
        for(int i = 0; i < vexNum; i++)
        {
            for(int j =0; j < vexNum; j++)
            {
                dist[i][j] = arcs[i][j];
                if(i != j && dist[i][j] < infinity)
                    path[i][j] = i;
                else 
                    path[i][j] = -1;
            }
        }
        
        for(int i = 0; i < vexNum; i++)
            for(int j = 0; j < vexNum; j++)
                for(int k =0; k <vexNum; k++)
                {
                    if(dist[j][i] + dist[i][k] < dist[j][k])
                    {
                        path[j][k] = i;
                        dist[j][k] = dist[j][i] + dist[i][k];
                    }
                }
                
        cout << "各点的最短路径如下(∞表示不存在最短路径)" << endl;
        for(int i =0; i < vexNum; i++)
            cout << "	" << vertexes[i];
        cout << endl;
        
        for(int i =0; i < vexNum; i++)
        {
            cout << vertexes[i];
            for(int j = 0; j < vexNum; j++)
            {
                if(dist[i][j] != infinity)
                    cout << "	" << dist[i][j];
                else 
                    cout << "";  
            }
                
            cout << endl;
        }
    }
    
    //求关键路径 
    template <class ElemType>
    void AdjMatrixDirGraph<ElemType>::CriticalPath()
    {
        int ve[vexNum], vl[vexNum];
        int InDegree[vexNum];            //存储每个顶点的度数 
        LinkStack<int> stack;
        LinkQueue<int> queue;
        int count = 0;
        int temp, ae, al;
        
        //判断图中入度为 0 的顶点数,在求关键路径时,不能存在多个入度为 0 的顶点 
        for(int i = 0; i < vexNum; i++)
        {
            InDegree[i] = 0;        //初始化 
            ve[i] = 0;
            for(int j =0; j < vexNum; j++)
            {
                if(arcs[j][i] != infinity && i != j)
                {
                    InDegree[i]++;
                }
            }
        }
        
        for(int i = 0; i < vexNum; i++)
        {
            if(InDegree[i] == 0) 
            {
                count++;
                queue.EnQueue(i);
            }    
        }    
        
        if(count != 1) 
        {
            cout << "无法求关键路径,该图中有多条入度为 0 或者不存在入度为 0 的顶点" << endl;; 
            return ;
        }
         
        count = 0;
        while(!queue.IsEmpty())
        {
            queue.DelQueue(temp);
            stack.Push(temp);
            count++;
            for(int i = 0; i < vexNum; i++)
            {
                if(arcs[temp][i] != infinity && arcs[temp][i] && --InDegree[i] == 0)
                {
                    queue.EnQueue(i);
                }    
                if(arcs[temp][i] != infinity  && arcs[temp][i] && ve[temp] + arcs[temp][i] > ve[i])
                    ve[i] = ve[temp] + arcs[temp][i];
            }
        }
         
        if(count < vexNum)
        {
            cout << "该图中存在回路,无法求关键路径" << endl;
            return ; 
        }
        
        stack.Top(temp);               //这一步算是关键点,假想空的这个数组里面的元素无限大,后面进来的元素才能进入 
        for(int i = 0; i < vexNum; i++)//****初始化,将所有值赋为最大值**** 
            vl[i] = ve[temp];
        
        while(!stack.IsEmpty())
        {
            stack.Pop(temp);
            for(int i = 0; i < vexNum; i++)
            {
                if(arcs[temp][i] != infinity && vl[i] - arcs[temp][i] < vl[temp]) //注意判断不能出错 
                {
                    vl[temp] = vl[i] - arcs[temp][i];
                }
            }    
        } 
    
        for(int i = 0; i < vexNum; i++)
        {
            for(int j = 0; j < vexNum; j++)//遍历寻找i的下一结点,并构成边 
            {
                if(arcs[i][j] != infinity && i != j)
                {
                    ae = ve[i];
                    al = vl[j] - arcs[i][j];
                    if(ae == al)
                    {
                        cout << "<" << vertexes[i] << "," << vertexes[j] << "> "; 
                    }
                }
            }
        }
        cout << endl;
    }
    #endif

    测试文件:

    #include "AdjMatrixDirGraph.h"
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        try
        {
        int flag = 1;
        char item;
        char items[7] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; 
        int weight[7][7]= {
            {        0,           3,         2,           6, infinity, infinity, infinity},
            {infinity,           0, infinity,           2,         4, infinity, infinity},
            {infinity, infinity,         0,           1, infinity,           3, infinity},
            {infinity, infinity, infinity,              0,         1, infinity, infinity},
            {infinity, infinity, infinity, infinity,         0, infinity,        3},
            {infinity, infinity, infinity, infinity, infinity,           0,         4},
            {infinity, infinity, infinity, infinity, infinity, infinity,         0}     
        };
        AdjMatrixDirGraph<char> g(items, 7, 7);
        for(int i = 0; i < 7; i++)
            for(int j = 0; j < 7; j++)
            {    
                if(i != j && weight[i][j] != infinity)
                    g.InsertArc(i, j, weight[i][j]);
            }        
        
        g.Display(); 
        system("pause");
        cout << endl;
        
        while(flag)
        {
            cout << "请输入一个顶点元素,以求其出入度(注意大小写): ";
            cin >> item;
            if(g.InDegree(item) != -1)
            {
                cout << "该点的入度为:" << g.InDegree(item) << endl;
                cout << "该点的出度为:" << g.OutDegree(item) << endl;
                flag = 0;
            }        
            else 
                cout << "该顶点不存在!!!请重新输入!!!" << endl; 
        }
        system("pause");
        cout << endl;
        
        cout << "输入一个顶点,求该顶点到其他顶点的最短路径(注意大小写):";
        cin >> item; 
        g.ShortestPathDij(item); 
        system("pause");
        cout << endl;
        
        
        g.ShortesPathFloyed();
        system("pause");
        cout << endl;
        
        cout << "该图的关键路径为" << endl; 
        g.CriticalPath();
        system("pause");
        }    
        catch (Error err)                    // 捕捉并处理异常
        {
            err.Show();                        // 显示异常信息
        }
        return 0;
    }
    记录点点滴滴
  • 相关阅读:
    关于桌面的图片打开很慢的解决方法
    用c#进行递归组合
    ajax,js,css 入门页面
    择日宣判此案,却常再无下文
    共享软件的明确定义
    [转]大逃亡,还没出来呢
    如何收集带有附件的网页
    送一份自家产的软件给园内的兄弟姐妹作“福利”
    [转]评蒙牛内幕
    蓝侠==la*uan,破解中国共享软件联盟著名灌水专家“蓝侠””
  • 原文地址:https://www.cnblogs.com/1by1/p/10745335.html
Copyright © 2020-2023  润新知