数据结构作业笔记二

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

(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;
}
记录点点滴滴
原文地址:https://www.cnblogs.com/1by1/p/10745335.html