// 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
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
原文地址: https://blog.csdn.net/NineZc/article/details/79083840
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。