#include <iostream>
#include <cstdlib>
#define MAXVEX 6 //起始顶点数默认为6,可在此直接修改
#define MAXEDGE 8 //起始边的数默认为8,可在此直接修改
using namespace std;
//该代码是邻接表拓扑排序原理
//步骤1:在有向图中选一个没有前驱(即入度为0)的顶点(用栈来保存)且输出其信息
//步骤2:从图中删除该顶点(出栈)和所有以他为尾的弧(相邻顶点的入度-1)
//步骤3:重复上述两步,直至全部顶点均已输出或当前图中已不存在无前驱的顶点为止
//注意点1:下标0的位置都不用,所以要多开辟一个空间
//注意点2:头结点信息既可以是字符A,B,C,D,也可以是字符'1','2'...
//注意点3:在创建邻接表时,使用头插法将边结点接在头结点之后
typedef struct sqstack
{
int *elem;
int top;
}SqStack; //栈
typedef struct EdgeNode
{
int adjvex;
struct EdgeNode *next;
}EdgeNode; //边结点
typedef struct
{
char vextexinfo; //存放头结点信息(如A,B,C,D)
int in; //存放头结点的入度信息
EdgeNode *firstedge; //指向该结点的临边
}VextexNode,AdjList; //头结点(即邻接表)
typedef struct
{
int vexNum; //顶点数
int edgeNum; //边数
AdjList adjlist[MAXVEX+1]; //头结点数组
}ALGraph;
/*****************初始化静态栈******************/
void InitStack(SqStack & s)
{
s.elem =new int[MAXVEX+1];
if(s.elem == NULL)
{
cout<<"内存分配失败!!!退出程序"<<endl;
exit(0); //需引入头文件<cstdlib>
}
s.top=0;
}
/******************压栈*************************/
//进栈是从下标1开始存放,0位置不存放数据
void Push(SqStack &s , int e)
{
if(s.top >= MAXVEX)
{
cout<<"栈已满!!!"<<endl;
}else
{
s.top++;
s.elem[s.top]=e;
}
}
/******************出栈*************************/
void Pop(SqStack &s , int &e)
{
e=s.elem[s.top];
s.top--;
}
/******************判断是否空栈*****************/
int Emptystack(SqStack &s)
{
if(s.top<1)
return 0;
else
return 1;
}
/******************初始化邻接表*******************/
void InitAdjList(ALGraph &g)
{
g.vexNum=MAXVEX;
g.edgeNum=MAXEDGE;
//初始化头结点数组(即表头信息)
for(int i =1; i<=MAXVEX ; i++)
{
cout<<"请输入第"<<i<<"个结点的信息:";
cin>>g.adjlist[i].vextexinfo;
g.adjlist[i].firstedge=NULL; //初始化指针指向空
}
}
//通过两个结点来确认边,并得到这两个结点的在数组的下标位置
/*********************确定邻接表数组下标的位置*********************/
void Locata(ALGraph &g,char &vex1,char &vex2, int &m, int &n)
{
for(int i =1;i<=MAXVEX;i++)
{
if(vex1 == g.adjlist[i].vextexinfo)
m=i;
if(vex2 == g.adjlist[i].vextexinfo)
n=i;
}
}
/******************建立邻接表*******************/
void SetAdjList(ALGraph &g)
{
char vex1,vex2;
int m,n;
for(int i=1;i<=MAXEDGE;i++) //有几条边就循环几次
{
cout<<"请输入第"<<i<<"条边(形如A B,表示A到B的一条边)";
cin>>vex1>>vex2; //输入边的信息(即通过输入两顶点来确认边)
Locata(g,vex1,vex2,m,n);//得到vex1和vex2在邻接表的数组下标位置m和n
EdgeNode *s1 = new EdgeNode;
s1->adjvex=n; //无向图现在m是头,n是尾
s1->next = g.adjlist[m].firstedge;
g.adjlist[m].firstedge=s1;
}
//初始化顶点的入度
for(int i=1;i<=MAXVEX;i++)
{
cout<<"请输入第"<<i<<"个顶点的入度:";
cin>>g.adjlist[i].in;
}
}
/******************显示邻接表*******************/
void ShowAdjList(ALGraph &g)
{
cout<<"该图的邻接表如下:"<<endl;
for(int i=1;i<=g.vexNum ;i++)
{
EdgeNode *p;
cout<<"结点"<<i<<" 其入度为:"<<g.adjlist[i].in<<" 其邻接点为: ";
for(p = g.adjlist[i].firstedge; p!=NULL ; p=p->next)
cout<<p->adjvex<<" ";
cout<<endl;
}
}
/*********************拓扑排序**************************/
void Topological(ALGraph &g)
{
//创建初始化一个栈
SqStack s;
InitStack(s);
//第一轮找出结点入度为0的点压栈
for(int i=1;i<=MAXVEX;i++)
{
if(g.adjlist[i].in == 0)
Push(s,i);
}
cout<<"拓扑排序如下:"<<endl;
while(Emptystack(s) != 0) //表示栈非空
{
int k;
int e; //接收出栈的结点的下标
Pop(s,e);//弹出出栈结点的下标
cout<<g.adjlist[e].vextexinfo<<"->";
EdgeNode *p = g.adjlist[e].firstedge;
while(p != NULL)
{
k=p->adjvex;
g.adjlist[k].in--; //弹出e之后,还要把e相关的边去除,就是与e相邻的结点的入度减1
if(g.adjlist[k].in == 0) //结点入度减1完之后,如果是0,就再次进栈
Push(s,k); //将入度为0的结点下标压栈
p=p->next; //指向e的下一个结点
}
}
}
int main()
{
ALGraph g;
InitAdjList(g);
SetAdjList(g);
ShowAdjList(g);
Topological(g);
return 0;
}
C++数据结构-拓扑排序
猜你喜欢
转载自blog.csdn.net/weixin_43323201/article/details/84786514
今日推荐
周排行