关键路径+拓扑排序+递归遍历顶点+广度优先遍历图+邻接储存

// CriticalPath.cpp : 定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include<iostream>
#include<string>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
struct ArcNode//定义弧表结点
{
    int adjVex;//邻接点域
    int weight;//弧的权值
    ArcNode *next;//指向下一个弧结点的指针
};
template <class T>
struct VertexNode//定义顶点表结点
{
    T   vertexName;//顶点名称
    bool visited;// 访问标记 
    int inDegree;//顶点入度
    ArcNode *firstEdge;//弧表的头指针
};
template <class T>
class ALGraph
{
public:
    ALGraph(int* arcArray, T* nameOfVertex, int numberOfVertex, int numberOfArc);//构造函数,初始化具有 numberOfVertex 个顶点numberOfArc 条弧的图
    ~ALGraph();//析构函数
    T GetVertex(int position);//取图中第 position 个顶点数据信息
    void SetVertex(int index, T value); //将图中第 index 个顶点的数据域置为 value
    void InsertVex(int index, T value);//在图中插入一个顶点,其编号为 index,值为 value 
    void DeleteVex(int index);//删除图中第 index 个顶点
    void InsertArc(int indexFrom, int indexTo);//在图中插入一条弧,其依附的两个顶点的编号为 indexFrom 和 indexTo
    void DeleteArc(int indexFrom, int indexTo);//在图中删除一条弧,其依附的两个顶点的编号为 indexTo 和 indexTo
    void DFSTraverse(int source);//深度度优先遍历图
    void DFS(int source);//递归遍历顶点
    void BFS(int source);//广度优先遍历图
    bool TopologicalOrder();//拓扑排序
    void CriticalPath();//关键路径
    void PrintAdjacencyList();//输出邻接表
private:
    int vertexNum, arcNum;//图的顶点数和弧数
    vector<VertexNode<T> > adjacencyList;//存放图中顶点的数组
};
//**********************邻接表图操作***************************************//
/* *前置条件:图不存在 *输 入:无 *功 能:图的初始化 *输 出:无 *后置条件:得到一个有向图 */
template <class T>
ALGraph<T>::ALGraph(int* arcArray, T* nameOfVertex, int numberOfVertex, int numberOfArc)
{
    this->arcNum = numberOfArc;//弧数
    this->vertexNum = numberOfVertex;//顶点数
    VertexNode<T> tempVerNode;
    for (int i = 0; i < numberOfVertex; i++)
    {
        tempVerNode.vertexName = nameOfVertex[i];
        tempVerNode.firstEdge = NULL;
        tempVerNode.visited = false;
        adjacencyList.push_back(tempVerNode);
    }
    for (int i = 0; i < numberOfArc; i++)//给弧赋置
    {
        ArcNode *pArcNode = new ArcNode;//生成一个弧表结点 pArcNode 
        int arcTailIndex;
        arcTailIndex = *(arcArray + i);//获取弧尾编号 
        pArcNode->adjVex = *(arcArray + numberOfArc + i);//获取弧头编号 
        pArcNode->weight = *(arcArray + 2 * numberOfArc + i);//获取弧权值
        pArcNode->next = adjacencyList[arcTailIndex].firstEdge;//将结点 pArcNode 插入到结点 arcTailIndex 的弧表的表头
        adjacencyList[arcTailIndex].firstEdge = pArcNode;
    }
}
/* 前置条件:图已存在 * 输 入:无 * 功 能:销毁图 * 输 出:无 * 后置条件:释放图所占用的存储空间 */
template <class T> ALGraph<T>::~ALGraph()
{
    for (int i = 0; i < vertexNum; i++)
    {
        ArcNode *pArcNode = adjacencyList[i].firstEdge;
        while (pArcNode != NULL)//循环删除
        {
            adjacencyList[i].firstEdge = pArcNode->next;
            delete pArcNode;//释放结点空间
            pArcNode = adjacencyList[i].firstEdge;
        }
    }

}
/* *前置条件:图已存在 *输入:顶点 i *功能:输出图中顶点 i 的数据信息 *输出:图中顶点 i 的数据信息 *后置条件:图保持不变 */
template <class T>
T ALGraph<T>::GetVertex(int position)
{
    if (position > vertexNum || position < 0) throw "输入顶点的位置不正确"; //顶点 position 不存在则抛出异常
    return adjacencyList[i].vertexName;// adjlist[i].vertex;//返回第 i 个顶点的数据域
}
/* *前置条件:图已存在 *输 入:顶点 i *功 能:将图中顶点 i 的数据域置为 value *输 出:无 *后置条件:图保持不变 */
template <class T>
void ALGraph<T>::SetVertex(int i, T value)
{
    if (i > vertexNum || i < 0) throw "输入顶点的位置不正确"; //顶点 i 不存在则抛出异常 
    adjacencyList[i].vertexName = value;//第 i 个顶点的数据域置为 value
}
/* *前置条件:图已存在 *输 入:顶点 value,位置 i *功 能:在图中 i 位置插入一个顶点 name *输 出:如果插入不成功,抛出异常 *后置条件:如果插入成功,图中增加了一个顶点 */
template <class T>
void ALGraph<T>::InsertVex(int i, T value)
{

    if (i > vertexNum || i < 0) throw "输入顶点的位置不正确";//顶点 i 不存在则抛出异常
    this->vertexNum++;//顶点数加 1
    VertexNode<T> tempVertex;
    tempVertex.vertexName = value;
    tempVertex.firstEdge = NULL;
    adjacencyList.insert(adjacencyList.begin() + i, tempVertex);
}
/* *前置条件:图已存在 *输 入:顶点 i *功 能:在图中删除顶点 i *输 出:如果删除不成功,抛出异常 *后置条件:如果删除成功,图中减少了一个顶点,相应顶点所建立的弧也消去 */
template <class T>
void ALGraph<T>::DeleteVex(int position)
{
    if (position<0 || position>vertexNum) throw "位置";//顶点输入错误则抛出异常 
    for (int k = 0; k < vertexNum; k++)//删掉入度弧
        if (k != position)
            DeleteArc(k, position);
    ArcNode *curNode;
    ArcNode *priorOfCurNode;
    if (adjacencyList[position].firstEdge != NULL)
    {
        curNode = adjacencyList[position].firstEdge;
        while (curNode != NULL)
        {
            priorOfCurNode = curNode;
            //adjacencyList[i].firstEdge = curNode->next;
            curNode = curNode->next;
            delete priorOfCurNode;//删除 priorOfCurNode 结点
        }
        curNode = adjacencyList[position].firstEdge;
        adjacencyList[position].firstEdge = NULL;
        delete curNode;
    }
    if (adjacencyList.size() > position)
    {
        adjacencyList.erase(adjacencyList.begin() + position);
    }
    this->vertexNum--;//顶点标记减 1
    for (int k = 0; k < vertexNum; k++)
        if (adjacencyList[k].firstEdge != NULL)
        {
            curNode = adjacencyList[k].firstEdge;//将结点 s 插入到结点 i 的弧表的表头 
            while (curNode != NULL)
            {
                if (curNode->adjVex > position)//搜索 i 结点
                    curNode->adjVex--;
                curNode = curNode->next;
            }
        }
}
/* *前置条件:图已存在 *输 入:顶点 i、j *功 能:在图中插入顶点 i、j 及其所依附的弧 *输 出:如果插入不成功,抛出异常 *后置条件:如果插入成功,图中增加了一条弧 */
template <class T>
void ALGraph<T>::InsertArc(int arcTail, int arcHead)
{
    if (arcTail > vertexNum || arcHead > vertexNum) throw "位置";//顶点输入错误则抛出异常
    ArcNode *curNode = new ArcNode;
    curNode->adjVex = arcHead;//生成一个弧表结点 s
    curNode->next = adjacencyList[arcTail].firstEdge;//将结点 s 插入到结点 i 的弧表的表头 
    adjacencyList[arcTail].firstEdge = curNode;
}
/* *前置条件:图已存在 *输 入:顶点 i、j *功 能:在图中删除顶点 i、j 依附的弧 *输 出:如果删除不成功,抛出异常 *后置条件:如果删除成功,图中减少了一条弧 */
template <class T>
void ALGraph<T>::DeleteArc(int arcTail, int arcHead)
{
    if (arcTail > vertexNum || arcHead > vertexNum) throw "删除顶点位置错误"; //顶点输入错误则抛出异常
    ArcNode *curVerNode;
    ArcNode *priorOfCurVerNode;
    curVerNode = adjacencyList[arcTail].firstEdge;
    priorOfCurVerNode = adjacencyList[arcTail].firstEdge;
    while (curVerNode != NULL && curVerNode->adjVex != arcHead)
    {
        priorOfCurVerNode = curVerNode;
        curVerNode = curVerNode->next;
    }
    if (curVerNode != NULL)
    {
        priorOfCurVerNode->next = curVerNode->next;
        delete curVerNode;
    }
}
template <class T>
void ALGraph<T>::DFSTraverse(int source)
{
    //初始化顶点访问状态
    for (int k = 0; k < vertexNum; k++)
        adjacencyList[k].visited = false;
    DFS(source);
}
/* *前置条件:图已存在 *输 入:遍历的起始顶点 v *功 能:从顶点 v 出发深度优先遍历图 *输 出:图中顶点的一个线性排列 *后置条件:图保持不变 */
template <class T>
void ALGraph<T>::DFS(int source)
{
    ArcNode * curArcNode;
    int tempIndex;
    cout << adjacencyList[source].vertexName << " ";
    adjacencyList[source].visited = true;
    curArcNode = adjacencyList[source].firstEdge;
    while (curArcNode != NULL)
    {
        tempIndex = curArcNode->adjVex;
        if (adjacencyList[tempIndex].visited == false)
            DFS(tempIndex);//递归遍历
        curArcNode = curArcNode->next;
    }
}
/* *前置条件:图已存在 *输 入:遍历的起始顶点 v *功 能:从顶点 v 出发广度优先遍历图 *输 出:图中顶点的一个线性排列 *后置条件:图保持不变 */
template <class T>
void ALGraph<T>::BFS(int position)
{
    //顶点输入错误则抛出异常
    if (position > vertexNum) throw "广度优先遍历初始位置错误";
    ArcNode * curArcNode;//生成一个弧表结点 curNode
    int indexFrom, indexTo;
    queue <int> verQueue;//定义顶点下标队列
    for (int k = 0; k < vertexNum; k++)
        adjacencyList[k].visited = false;
    cout << adjacencyList[position].vertexName << " "; //被访问顶点入队 
    adjacencyList[position].visited = true; verQueue.push(position);//被访问顶点入队
    while (!verQueue.empty())
    {
        indexFrom = verQueue.front();
        verQueue.pop();
        //弧表中的工作指针 curArcNode 初始化
        curArcNode = adjacencyList[indexFrom].firstEdge;
        while (curArcNode != NULL)
        {
            indexTo = curArcNode->adjVex;
            if (adjacencyList[indexTo].visited == false)
            {
                cout << adjacencyList[indexTo].vertexName << " ";
                adjacencyList[indexTo].visited = true;
                verQueue.push(indexTo);
            }
            curArcNode = curArcNode->next;
        }
    }
}
template <class T>
void ALGraph<T>::PrintAdjacencyList()
{
    int index;
    ArcNode *curArcNode;
    for (int i = 0; i < adjacencyList.size(); ++i)
    {
        cout << adjacencyList[i].vertexName;
        curArcNode = adjacencyList[i].firstEdge;
        if (curArcNode != NULL)
        {
            while (curArcNode != NULL)
            {
                cout << "--->" << "(" << adjacencyList[curArcNode->adjVex].vertexName << " 权值为:" << curArcNode->weight << ")";
                curArcNode = curArcNode->next;
            }
        }
        else
            cout << "--->" << "空";
        cout << endl;
    }
}
template <class T>
bool ALGraph<T>::TopologicalOrder()
{
    stack <int> verStack;//定义顶点下标栈
    int count = 0;// 记录输出顶点个数
    int indexFrom, indexTo;
    ArcNode *curArcNode;
    //初始化入度
    for (int k = 0; k < vertexNum; k++)
        adjacencyList[k].inDegree = 0;
    //计算各顶点入度
    for (int i = 0; i < adjacencyList.size(); ++i)
    {
        curArcNode = adjacencyList[i].firstEdge;
        while (curArcNode != NULL)
        {
            adjacencyList[curArcNode->adjVex].inDegree++;
            curArcNode = curArcNode->next;
        }
    }
    //入度为 0 则入栈
    for (int i = 0; i < adjacencyList.size(); ++i)
    {
        if (adjacencyList[i].inDegree == 0)
            verStack.push(i);
    }
    while (!verStack.empty())
    {
        indexFrom = verStack.top();
        verStack.pop();
        cout << adjacencyList[indexFrom].vertexName << " "; count++;//输出顶点个数加 1
        for (curArcNode = adjacencyList[indexFrom].firstEdge; curArcNode != NULL; curArcNode = curArcNode->next)
        {
            indexTo = curArcNode->adjVex;
            adjacencyList[indexTo].inDegree--;
            if (adjacencyList[indexTo].inDegree == 0)//如果入度为 0,则入栈 
                verStack.push(indexTo);
        }
    }
    if (count < adjacencyList.size())
    {
        cout << "有回路" << endl;
        return false;
    }
    else
    {
        cout << endl;
        return true;
    }
}
template <class T>
void ALGraph<T>::CriticalPath()
{

    if (!TopologicalOrder()) throw " 有环无法求解关键路径";//顶点输入错误则抛出异常
    stack <int> order;//定义拓扑排序顶点下标栈
    stack <int> reverseOrder;//定义逆拓扑排序顶点下标栈 
    int count = 0;// 记录输出顶点个数
    int indexFrom, indexTo;
    ArcNode *curArcNode;
    vector<int> ve(vertexNum);//顶点最早发生时间
    vector<int> vl(vertexNum);//顶点最迟发生时间
                              //初始化顶点入度
    for (int k = 0; k < vertexNum; k++)
        adjacencyList[k].inDegree = 0;
    //计算顶点入度
    for (int i = 0; i < adjacencyList.size(); ++i)
    {
        curArcNode = adjacencyList[i].firstEdge;
        while (curArcNode != NULL)
        {
            adjacencyList[curArcNode->adjVex].inDegree++;
            curArcNode = curArcNode->next;
        }
    }
    //源点入栈
    for (int i = 0; i < adjacencyList.size(); ++i)
    {
        if (adjacencyList[i].inDegree == 0)
            order.push(i);
    }
    //初始化事件最早发生时间
    for (int k = 0; k < vertexNum; k++)
        ve[k] = 0;
    //计算各事件最早发生时间
    while (!order.empty())
    {
        indexFrom = order.top();
        order.pop();
        reverseOrder.push(indexFrom);
        for (curArcNode = adjacencyList[indexFrom].firstEdge;
            curArcNode != NULL; curArcNode = curArcNode->next)
        {
            indexTo = curArcNode->adjVex;
            adjacencyList[indexTo].inDegree--;
            if (adjacencyList[indexTo].inDegree == 0)
                order.push(indexTo);
            if ((ve[indexFrom] + curArcNode->weight) > ve[indexTo])
                ve[indexTo] = ve[indexFrom] + curArcNode->weight;
        }
    }
    //初始化事件最迟发生时间
    for (int k = 0; k < vertexNum; k++)
        vl[k] = ve[vertexNum - 1];
    //计算各事件最迟发生时间
    while (!reverseOrder.empty())
    {
        indexFrom = reverseOrder.top();
        reverseOrder.pop();
        for (curArcNode = adjacencyList[indexFrom].firstEdge;
            curArcNode != NULL; curArcNode = curArcNode->next)
        {
            indexTo = curArcNode->adjVex;
            if ((vl[indexTo] - curArcNode->weight) < vl[indexFrom])
                vl[indexFrom] = vl[indexTo] - curArcNode->weight;
        }
    }
    //输出事件最早发生时间
    for (int k = 0; k < vertexNum; k++)
    {
        cout << "ve[" << k << "]= " << ve[k] << " ";
    }
    cout << endl;
    //输出事件最迟发生时间
    for (int k = 0; k < vertexNum; k++)
    {
        cout << "vl[" << k << "]= " << vl[k] << " ";
    }
    cout << endl;
    //计算活动最早发生时间和最迟发生时间
    for (int indexFrom = 0; indexFrom < adjacencyList.size(); ++indexFrom)
    {
        for (curArcNode = adjacencyList[indexFrom].firstEdge;
            curArcNode != NULL; curArcNode = curArcNode->next)
        {
            indexTo = curArcNode->adjVex;
            if (ve[indexFrom] == (vl[indexTo] - curArcNode->weight))//关键活动
            {
                cout << "(" << adjacencyList[indexFrom].vertexName
                    << "," << adjacencyList[indexTo].vertexName << ")"
                    << curArcNode->weight << " ";
                //输出活动最早发生时间和最迟发生事件
                cout << "ee[" << indexFrom << "]=" << ve[indexFrom] << ","
                    << "el[" << indexFrom << "]="
                    << vl[indexTo] - curArcNode->weight << endl;
            }
        }
    }
}
int main(int argc, char* argv[])
{
    int verNum = 9;//顶点数
    int arcNum = 11;
    int choose = 1;//控制
    int which;//功能选择变量
    string name;//插入顶点的值
    int arc[3][11] =
    {//
        { 0,0,0,1,2,3,4,4,5,6,7 },//弧尾编号
        { 1,2,3,4,4,5,6,7,7,8,8 },//弧头编号
        { 6,4,5,1,1,2,9,7,4,2,4 } //弧的权值
    };
    string vertexName[9] = { "v0","v1","v2","v3","v4","v5","v6","v7","v8" }; //初始化各顶点
    int* p;//定义指针 p
    string* q;//定义指针 q
    p = &arc[0][0];//p 指针指向 cost 数组的起始位置
    q = vertexName;//q 指针指向 vname 数组
    ALGraph<string> g(p, q, verNum, arcNum);//调用 Graph 程序
    while (choose == 1)//控制
    {
        cout << "-------功能选项---------" << "\n";
        cout << "0、查看顶点信息请按 0" << "\n";//输入你要进行的操作的序号 
        cout << "1、查看弧的信息请按 1" << "\n";
        cout << "2、需要修改请按 2" << "\n";
        cout << "3、DFS 遍历请按 3" << "\n";
        cout << "4、删除某个顶点请按 4" << "\n";
        cout << "5、插入某个顶点请按 5" << "\n";
        cout << "6、删除某条弧请按 6" << "\n";
        cout << "7、插入某条弧请按 7" << "\n";
        cout << "8、BFS 遍历请按 8" << "\n";
        cout << "9、输出邻接表图请按 9" << "\n";
        cout << "10、拓扑排序请按 10" << "\n";
        cout << "11、关键路径请按 11" << "\n";
        cout << "12、退出请按 12" << "\n";
        cout << "-----------------------" << "\n";
        cin >> which;
        switch (which)//功能选择
        {
        case 0: //输出图的各顶点的值
            try
            {
                cout << "顶点信息如下:" << "\n";
            }
            catch (char*)
            {
                cout << "输出不正确!" << endl;
            }
            break;
        case 1://输出图中弧
            int i;
            int j;
            cout << "所有的弧的信息为:" << "\n";
            try
            {
                //g.GetArcInfo();
            }
            catch (char*)
            {
                cout << "输出不正确!" << endl;
            }
            break;
        case 2://修改图中的弧长
            cout << "输入定点编号:" << endl;
            cin >> i >> j;
            int length;
            cout << "输入长度:" << endl;
            cin >> length;
            try
            {
                //g.SetArc(i, j, length);
            }
            catch (char*)
            {
                cout << "输出顶点不正确!" << endl;
            }
            break;
        case 3://DFS
            cout << "请输入源顶点:" << "\n";
            int source;
            cin >> source;
            try
            {
                g.DFSTraverse(source);
            }
            catch (char*)
            {
                cout << "输出顶点不正确!" << endl;
            }
            break;
        case 4://删除顶点
            int indexToDelete;
            cout << "请输入要删除的顶点" << "\n";
            cin >> indexToDelete;
            try
            {
                g.DeleteVex(indexToDelete);
            }
            catch (char*)
            {
                cout << "删除失败!" << endl;
            }
            break;
        case 5://在 nn 位置插入值为 name 的顶点
               //int indexToDelete;
            cout << "请输入要插入的顶点的位置和名称" << "\n";
            cin >> indexToDelete >> name;
            try
            {
                g.InsertVex(indexToDelete, name);
            }
            catch (char*)
            {
                cout << "插入失败!" << endl;
            }
            break;
        case 6://删除 from 到 to 之间的距离
            int from;
            int to;
            cout << "请输入两顶点:" << "\n";
            cin >> from >> to;
            try
            {
                g.DeleteArc(from, to);
            }
            catch (char*)
            {
                cout << "插入失败!" << endl;
            }
            break;
        case 7://插入从 pos1 到 pos2 的路径
            int distance;
            cout << "请输入两顶点:" << "\n";
            cin >> from >> to;
            cout << "请输入路径长度:" << "\n";
            cin >> distance;
            try
            {
                //g.InsertArc(from, to, distance);
            }
            catch (char*)
            {
                cout << "插入失败!" << endl;
            }
            break;
        case 8://BFS 遍历
            cout << "请输入源顶点:" << "\n";
            cin >> source;
            try
            {
                g.BFS(source);
            }
            catch (char*)
            {
                cout << "输出顶点不正确!" << endl;
            }
            break;
        case 9://查看邻接表请
            try
            {
                g.PrintAdjacencyList();
            }
            catch (char*)
            {
                cout << "输出邻接矩阵失败!" << endl;
            }
            break;
        case 10://退出
            try
            {
                g.TopologicalOrder();
            }
            catch (char*)
            {
                cout << "拓扑排序失败!" << endl;
            }
            break;
        case 11://退出
            try
            {
                g.CriticalPath();
            }
            catch (char*)
            {
                cout << "关键路径失败!" << endl;
            }
            break;
        case 12://退出
            choose = 0;
            break;
        }
    }
    return 0;
}
    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/NineZc/article/details/79083840
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞