拓扑排序 php,C语言 拓扑排序算法解析

拓扑排序是对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。

0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在理解 拓扑排序的思想并用源代码加以实现;

0.2) 图论算法基础知识,

【1】图论若干相关定义

1.1)图G定义:一个图G=(V,E)由顶点及集V 和 边集E组成, 每一条边就是一个点对(v, w);

1.2)边邻接:当且仅当(v,w)∈E, 在无向图中, w和v邻接,且v也和w邻接;(还有第3中成分:边的权值)

1.3)路径: 一条路径是一个顶点序列 w1, w2,…,wn, 使得(wi,wi 1)∈E,这样一条路径长是该路径上的边数;

1.4)简单路径:其上的所有顶点都是互异的,但第一个顶点和最后一个顶点可能相同;

1.5)连通图(对于无向图而言): 如果在一个无向图中从每一个顶点到每个其他顶点都存在一条路径,则称该无向图是连通的;

1.6)强连通图(对于有向图而言):具有无向图连通性质的有向图称为是强连通的;

1.7)基础图:去掉有向图上的方向所形成的图;

1.8)弱连通图:如果有向图不是强连通的, 但基础图是连通的, 那么该图称为是弱连通的;

1.9)完全图: 是指每一对顶点间都存在一条边的图;

【2】图的表示

2.1)邻接矩阵:对于每条边(u, v), 我们设置 A[u][v]=1,否则数组的元素为0;如果边是有权的,设置A[u][v] 等于该权值 且用一个很大或者很小的权作为标记表示不存在的边;(∞)

2.1.1)邻接表的空间需求是 Θ(|V|^2);如果图是稠密的:|E| = Θ(|V|^2) , 则邻接矩阵是合适的表示方法;如果在大部分应用中,图都是稀疏的;

2.2)邻接表(图的标准表示方法):如果图是稀疏的, 则使用邻接表来表示。对每一个顶点,我们使用一个表存放所有邻接的顶点。此时的空间需求为 O(|E| |V|);

2.2.1)引入散列表:在应用中,顶点都是名字而不是数字, 这些名字在编译时是未知的。由于我们不能够通过未知名字为一个数组做索引, 因此我们必须提供从名字到数字的映射。完成这项工作最容易的 方法是使用散列表, 在该散列表中我们对每个顶点存储一个名字以及一个范围在1到 |V| 之间的内部编号;

2.2.2)邻接表的一个荔枝:

357e8f98afcefc373aff96a9d0747082.png

2612fbdfdf60e8dedc26f204b22db4c9.png

【1】拓扑排序(有向无圈图才有资格谈拓扑排序,有向且要无圈)

1.1)拓扑排序定义: 拓扑排序是对有向无圈图的顶点的一种排序, 它使得如果存在一条从 vi 到 vj的路径,那么在排序中 vj出现在 vi的后面;(有向无圈图:一个有向图没有圈, 圈:满足w1=wn 且长度至少为1个一条路径)

1.2)拓扑排序应用(有点像联机算法): 课程选修顺序, 如有向边(v, w)表明课程v 必须在课程w 选修前修完;(显然,如果图含有圈, 那么拓扑排序是不可能的)

4d5403abb180e4143742d447ced0dcc7.png

1.3)一个简单的求拓扑排序的算法是: 先找出任意一个没有入边的顶点。 然后我们显示出该顶点,并将它和他的边一起从图中删除;

1.4)改进后的求拓扑排序的算法:

1.4.1)算法描述:通过将所有入度为0 的顶点放在一个特殊的盒子中而避免这种无效的劳动。此时 FindNewVertexOfIndegreeZero 函数返回(并删除)盒子中的 任一顶点。当我们降低这些邻接顶点的入度时,检查每一个顶点并在它的入度 降为0 时把它放入盒子中;

1.4.2)实现盒子(引入了队列):为实现这个盒子,我们使用一个栈或者队列;首先, 对每一个顶点计算它的入度。然后,将所有入度为0的顶点放入一个初始为空的队列中。当队列不空时,删除一个顶点v, 并将与v 邻接的所有顶点的入度减1。只要一个顶点的入度降为0, 就把该顶点放入队列中。此时,拓扑排序就是顶点出队的顺序;

1.4.3)我们的假设:我们假设图已经被读到一个邻接表中且入度已计算并被放入一个数组内;

1.4.4)时间复杂度是: O(|E|   |V|);

823c6b1ad59b99f7c684e4c4c86177ca.png

【2】拓扑排序源代码 printing results:

810977d7a81dd291ff6416423201c313.png

253526bde9cfdb68e46340032ac9c74c.png

2.1)download source code:

https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter9/p219_topSort

2.2)source code at a glance(for full code, please download source code following the given link above):

#include "adjTable.h"

#include "queue.h"

void topSort(AdjTable* adj, int size, int* indegreeArray, Queue queue)

{

int i;

int counter;

ElementType vertex;

ElementType adjVertex;

AdjTable temp;

AdjTable temp1;

for(i=0; i

if(!indegreeArray[i]) // find the element who has zero indegree in adjoining table

enQueue(queue, i); //let the element enter the queue

printf("\t topSorting sequence is as follows: ");

counter = 0;

while(!isEmpty(queue))

{

vertex = deQueue(queue); // if the queue is empty, conducting departing queue

temp = adj[vertex]->next;

while(temp)

{

adjVertex = temp->index; // each adjVertex adjacent to vertex

if(--indegreeArray[adjVertex] == 0)

enQueue(queue, adjVertex);

temp1 = temp->next;

free(temp);

temp = temp1;

}

printf("vertex[%d] ", vertex 1);

counter ;

}

if(counter != size)

Error("failed top sorting, for graph has a cycle, from func topSort !");

disposeQueue(queue);

printf("\n\t");

}

// initializing indegree array with given size

int *initIndegree(int size)

{

int *indegreeArray;

int i;

indegreeArray = (int*)malloc(sizeof(int) * size);

if(!indegreeArray)

{

Error("failed intialization ,for out of space ,from func initIndegree");

return NULL;

}

for(i=0; i < size; i )

indegreeArray[i] = 0;

return indegreeArray;

}

int main()

{

AdjTable* adj;

int *indegreeArray;

Queue queue;

int size = 7;

int i;

int j;

int column = 3;

int adjTable[7][3] =

{

{2, 4, 3},

{4, 5, 0},

{6, 0, 0},

{6, 7, 3},

{4, 7, 0},

{0, 0, 0},

{6, 0, 0}

};

printf("\n\n\t ====== test for topological sorting with adjoining table ======\n");

adj = initAdjTable(size);

indegreeArray = initIndegree(size);

queue = initQueue(size);

printf("\n\n\t ====== the initial adjoining table is as follows:======\n");

for(i = 0; i < size; i )

for(j = 0; j < column; j )

if(adjTable[i][j])

{

insertAdj(adj, adjTable[i][j]-1, i); // insertAdj the adjoining table over

indegreeArray[adjTable[i][j]-1] ; // update indegree of elements

}

printAdjTable(adj, size);

// topSorting starts

//void topSort(AdjTable* adj, int size, int* indegreeArray, Queue queue)

topSort(adj, size, indegreeArray, queue);

return 0;

}

2.3)printing results:

e1a5f6066535d06be7271ed23eea2296.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是逆拓扑排序算法C语言实现: ```c #include <stdio.h> #define MAXVEX 100 // 最大顶点数 typedef struct EdgeNode { // 边表节点 int adjvex; // 邻接点域,存储该顶点对应的下标 struct EdgeNode *next; // 链域,指向下一个邻接点 } EdgeNode; typedef struct VertexNode { // 顶点表结构 int in; // 顶点入度 int data; // 顶点域,存储顶点信息 EdgeNode *firstedge; // 边表头指针 } VertexNode, AdjList[MAXVEX]; typedef struct { // 图结构 AdjList adjList; int numVertexes, numEdges; // 图中当前顶点数和边数 } GraphAdjList; void CreateALGraph(GraphAdjList *G) { // 建立图的邻接表结构 int i, j, k; EdgeNode *e; printf("请输入顶点数和边数:\n"); scanf("%d%d", &G->numVertexes, &G->numEdges); for (i = 0; i < G->numVertexes; i++) { // 输入顶点信息,建立顶点表 printf("请输入第%d个顶点:", i + 1); scanf("%d", &G->adjList[i].data); G->adjList[i].in = 0; // 初始化所有顶点入度为0 G->adjList[i].firstedge = NULL; // 初始化所有边表为空 } for (k = 0; k < G->numEdges; k++) { // 建立边表 printf("请输入边(vi, vj)上的顶点序号:\n"); scanf("%d%d", &i, &j); e = (EdgeNode *)malloc(sizeof(EdgeNode)); e->adjvex = j; e->next = G->adjList[i].firstedge; G->adjList[i].firstedge = e; G->adjList[j].in++; // 对应顶点入度加1 } } void TopologicalSort(GraphAdjList G) { // 拓扑排序 int i, j, k, top = 0; int *stack; // 存储入度为0的顶点 EdgeNode *e; stack = (int *)malloc(G.numVertexes * sizeof(int)); for (i = 0; i < G.numVertexes; i++) { // 将所有入度为0的顶点入栈 if (G.adjList[i].in == 0) { stack[++top] = i; } } while (top != 0) { // 栈不为空 j = stack[top--]; // 出栈一个顶点 printf("%d ", G.adjList[j].data); // 输出该顶点 for (e = G.adjList[j].firstedge; e; e = e->next) { // 将该顶点的所有邻接点入度减1 k = e->adjvex; if (--G.adjList[k].in == 0) { // 若邻接点入度为0,则入栈 stack[++top] = k; } } } } int main() { GraphAdjList G; CreateALGraph(&G); printf("拓扑排序结果为:"); TopologicalSort(G); printf("\n"); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值