图的拓扑排序
Posted geekfx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图的拓扑排序相关的知识,希望对你有一定的参考价值。
拓扑排序
拓扑排序是对有向无圈图的顶点的一种排序,它使得如果存在一条从(v_i)到(v_j)的路径,那么在排序中(v_j)出现在(v_i)的后面。如果图含有圈,那么拓扑排序是不可能的。此外,排序不必是唯一的;任何合理的排序都是可以的。
算法思想
第1种
先找出任意一个没有入边的顶点。然后显示出该顶点,并将它和它的边一起从图中删除。然后对图的其余部分应用同样的方法处理。
伪代码
void Topsort(Graph G)
{
int Counter;
Vertex V, W;
for(Counter = 0; Counter < NumVertex; Counter++)
{
V = FindNewVertexOfIndegreeZero();
if(V == NotAVertex)
{
Error("Graph has a cycle");
break;
}
TopNum[V] = Counter; // 或打印出
for each W adjancent to V
Indegree[W]--;
}
}
函数FindNewVertexOfIndegreeZero扫描Indegree数组,寻找一个尚未被分配拓扑编号的入度为0的顶点;因为其是对Indegree数组的一个简单的顺序扫描,所以每次对它的调用都花费(O(left | V ight |))的时间.由于有(left | V ight |)这样的调用,因此该算法的运行时间为(O({left | V ight |}^2))。
第2种
首先,对每一个顶点计算它的入度(可以在输入图时就计算)。然后将所以入度为0的顶点放入一个初始为空的的队列中。当队列不空时,删除一个顶点(v),并将(v)邻接的所有的顶点的入度减1.只要1个顶点的入度将为0,就把该顶点放入队列中。此时,拓扑排序就是顶点出队的顺序。
C语言代码
void Topsort(ALGraph G)
{
Queue Q;
int Counter;
VertexType V;
ArcNode W;
Q = CreateQueue(MVNum);
Counter = 0;
for (V = 1; V <= G->vexnum; V++)
if (G->Indegree[V] == 0)
Enqueue(V, Q);
while (!IsEmpty(Q))
{
V = FrontAndDequeue(Q);
printf("%d->", V);
Counter++;
W = G->vertices[V].firstarc;
while (W != NULL)
{
if (--G->Indegree[W->adjvex] == 0)
Enqueue(W->adjvex, Q);
W = W->nextarc;
}
}
printf("^
");
if (Counter != G->vexnum)
printf("Graph has a cycle
");
DisposeQueue(Q);
}
如果使用邻接表,那么执行这个算法所用的时间为(O(left | E ight | +left | V ight | ))。
完整C语言代码
#include <stdio.h>
#include <stdlib.h>
#define NotAVertex (-1)
#define MVNum (10) // 最大顶点数
typedef int VertexType;
typedef int ArcType;
typedef struct ArcNode // 边结点
{
VertexType adjvex; // 该边所指向的顶点的位置
struct ArcNode *nextarc; // 指向下一条边的指针
ArcType weight; // 边的权值
} * ArcNode;
typedef struct VNode // 顶点信息
{
// VertexType data;
ArcNode firstarc; // 指向第一条依附该顶点的边的指针
} VNode, AdjList[MVNum]; // AdjList 表示邻接类型
typedef struct // 邻接表
{
AdjList vertices;
int vexnum, arcnum; // 图的当前定点数和边数
int Indegree[MVNum]; // 每个顶点的入度
} * ALGraph;
void CreateUDG(ALGraph G)
{
int i, j;
int v1, v2;
ArcNode p1, p2;
ArcType weight;
printf("Input vexnum: ");
scanf("%d", &G->vexnum);
printf("Input arcnum: ");
scanf("%d", &G->arcnum);
// 输入各点,构造表头结点表
for (i = 1; i <= G->vexnum; i++)
{
G->vertices[i].firstarc = NULL;
G->Indegree[i] = 0;
}
// 输入一条边依附的两个顶点
for (j = 0; j < G->arcnum; j++)
{
scanf("%d%d%d", &v1, &v2, &weight);
p1 = (ArcNode)malloc(sizeof(*p1));
if (p1 == NULL)
exit(0);
p1->adjvex = v2;
p1->weight = weight;
p1->nextarc = G->vertices[v1].firstarc;
G->vertices[v1].firstarc = p1;
G->Indegree[v2] += 1;
/*p2 = (ArcNode)malloc(sizeof(struct ArcNode));
p2->adjvex = i;
p2->nextarc = G->vertices[j].firstarc;
G->vertices[j].firstarc = p2;
G->Indegree[v1] += 1;*/
}
}
ALGraph CreateGraph(void)
{
ALGraph G;
G = (ALGraph)malloc(sizeof(*G));
if (G == NULL)
exit(0);
return G;
}
typedef VertexType ElementType;
typedef struct QueueNode *Queue;
struct QueueNode
{
ElementType Array[MVNum];
int Capacity;
int Size;
int Front;
int Rear;
};
int IsFull(Queue Q)
{
return Q->Size == Q->Capacity;
}
int IsEmpty(Queue Q)
{
return Q->Size == 0;
}
Queue CreateQueue(int Capacity)
{
Queue Q;
Q = (Queue)malloc(sizeof(struct QueueNode));
if (Q == NULL)
exit(0);
Q->Capacity = Capacity;
Q->Size = 0;
Q->Front = 1;
Q->Rear = 0;
return Q;
}
void Enqueue(ElementType X, Queue Q)
{
if (IsFull(Q))
{
printf("The queue is full
");
system("pause");
exit(0);
}
Q->Size++;
if (++Q->Rear == Q->Capacity)
Q->Rear = 0;
Q->Array[Q->Rear] = X;
}
void Dequeue(Queue Q)
{
if (IsEmpty(Q))
{
printf("The queue is empty
");
system("pause");
exit(0);
}
Q->Size--;
if (++Q->Front == Q->Capacity)
Q->Front = 0;
}
ElementType Front(Queue Q)
{
if (IsEmpty(Q))
{
printf("The queue is empty
");
system("pause");
exit(0);
}
return Q->Array[Q->Front];
}
ElementType FrontAndDequeue(Queue Q)
{
if (IsEmpty(Q))
{
printf("The queue is empty
");
system("pause");
exit(0);
}
Q->Size--;
return Q->Array[(Q->Front++) % Q->Capacity];
}
void DisposeQueue(Queue Q)
{
free(Q);
}
void Topsort(ALGraph G)
{
Queue Q;
int Counter;
VertexType V;
ArcNode W;
Q = CreateQueue(MVNum);
Counter = 0;
for (V = 1; V <= G->vexnum; V++)
if (G->Indegree[V] == 0)
Enqueue(V, Q);
while (!IsEmpty(Q))
{
V = FrontAndDequeue(Q);
printf("%d->", V);
Counter++;
W = G->vertices[V].firstarc;
while (W != NULL)
{
if (--G->Indegree[W->adjvex] == 0)
Enqueue(W->adjvex, Q);
W = W->nextarc;
}
}
printf("^
");
if (Counter != G->vexnum)
printf("Graph has a cycle
");
DisposeQueue(Q);
}
int main()
{
ALGraph G;
G = CreateGraph();
CreateUDG(G);
Topsort(G);
system("pause");
return 0;
}
输入/输出
顶点按数字编号,第3个数子为边上的权值。
Input vexnum: 7
Input arcnum: 12
1 2 1
1 3 1
3 6 1
7 6 1
5 7 1
2 5 1
1 4 1
2 4 1
5 4 1
4 7 1
4 6 1
4 3 1
1->2->5->4->3->7->6->^
请按任意键继续. . .
以上是关于图的拓扑排序的主要内容,如果未能解决你的问题,请参考以下文章