拓扑排序
概述:
拓扑排序,是将有向无环图G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)属于E(G),则u在线性序列中出现在v之前
解析:
构造有向无环图的步骤为以下两步,知道图中不存在入度为0的顶点为止
1、选择一个入读为0的顶点并输出
2、从图中删除此顶点以及所有出边,并将原本与其相连的顶点的入度减一
3、循环执行以上步骤
代码
//初始化栈操作
#define MaxSize 50 //定义栈的深度
typedef struct {
int data[MaxSize]; //栈数组
int top; //栈头
}SqStack;
//初始化
void InitStack(SqStack* S){
S->top = -1; //初始化栈顶指针
}
//判断栈是否为空
bool StackEmpty(SqStack S){
if (S.top == -1){
return true;
} else{
return false;
}
}
//进栈
bool Push(SqStack* S,int x){
if (S->top == MaxSize-1){ //栈满
return false;
}
S->data[++S->top] = x;
return true;
}
//出栈
bool Pop(SqStack* S,int* x){
if (S->top == -1){
return false; //栈空
}
*x = S->data[S->top--];
return true;
}
//读栈顶元素
bool GetTop(SqStack S,int* x){
if (S.top == -1){
return false;
}
*x = S.data[S.top];
return true;
}
//获取所有结点的入度情况
void FindInDegree(ALGraph G,int indegree[MAX_VERTEX_NUM]){
ArcNode* p;
for (int i = 0; i < G.vexnum; ++i) {
indegree[i] = 0; //初始化数组全部为0
}
//遍历邻接表,计算所有顶点的入度情况
for (int i = 0; i < G.vexnum; ++i) {
p = G.vertices[i].firstarc; //指向当前顶点的第一个连接顶点
while (p){
indegree[p->adjvex]++; //度数加一
p = p->nextarc;
}
}
}
/**
* 思路:使用邻接表来实现
* 首先获得每个结点的入度,保存在数组indegree中
* 遍历数组,将入度为0的下标压入栈中(下标为定点在顶点数组中的下标)
* 然后当栈不为空时循环执行以下操作
* 弹出栈中的第一个元素,将其加入到Topo数组中
* 然后更新入读数组,在去掉上一个入度为0的顶点之后,与其相连的其他顶点的入读必然变化,更新这些顶点的入度
* 将更新之后,入度为0的顶点加入到栈中
* 最后判断count(输出顶点的数量)与图中顶点的数量,如果小,则证明有环
* @param G
* @param Topo 用来存储拓扑排序的顶点序号
* @return
*/
bool TopologicalSort(ALGraph G,int Topo[]){
SqStack S;
int indegree[MAX_VERTEX_NUM]; //用来存储每一个顶点的入读是多少
FindInDegree(G,indegree); //统计每个顶点的入度是多少
ArcNode* p; //定义指针
//初始化栈
InitStack(&S);
//将入度为0的顶点入栈
for (int i = 0; i < G.vexnum; ++i) {
if (indegree[i]==0){
Push(&S,i); //入栈的是顶点数组中顶点的下标
}
}
int count = 0; //记录用,表示当前已经输出的顶点数
//当栈非空时
int i;
while (!StackEmpty(S)){
Pop(&S,&i); //将栈顶元素出战
Topo[count] = G.vertices[i].data; //将输出的顶点加入到拓扑数组中
count++; //输出元素之后要加一
//将i所代表的顶点指向的顶点的入读减一,并且将入读为0的元素加入到栈中
for (p = G.vertices[i].firstarc;p;p = p->nextarc) {
int k = p->adjvex;
indegree[k]--; //将该顶点的入读减一
if (indegree[k]==0){ //如果该顶点的入读为0,则压入栈
Push(&S,k); //同样,压入栈的并不是顶点,而是顶点的下标
}
}
}
if (count < G.vexnum){
return false; //证明有环
} else{
return true; //证明成功
}
}