【算法导论】邻接表存储的拓扑排序

简介:         上一篇文章中讲述了用邻接矩阵存储的图的拓扑排序,下面本文介绍用邻接表存储的图的拓扑排序。         关于拓扑排序的概念及基本思想,我在上一篇文章中已经较为详细的描述了,这里不在介绍。

        上一篇文章中讲述了用邻接矩阵存储的图的拓扑排序,下面本文介绍用邻接表存储的图的拓扑排序

        关于拓扑排序的概念及基本思想,我在上一篇文章中已经较为详细的描述了,这里不在介绍。我们知道利用邻接矩阵进行拓扑排序时,程序实现较为简单,但是效率不高,算法的复杂度为O(n^3).而利用邻接表会使入度为0的顶点的操作简化,从而提高算法的效率

在邻接表存储结构中,为了便于检查每个顶点的入度,可在顶点表中增加一个入度域(id),这样的邻接表如下图所示,这样只需对由n个元素构成的顶点表进行检查就能找出入度为0的顶点。为了避免对每个入度为0的顶点重复访问,可用一个链栈来存储所有入度为0的顶点。在进行拓扑排序前,只要对顶点表进行一次扫描,便可将所有入度为0的顶点都入栈,以后每次从栈顶取出入度为0的顶点,并将其输出。 

原始图为:


其对应的邻接表为:


邻接表存储结构中实现拓扑排序算法的步骤为:
        (1) 扫描顶点表,将入度为0的顶点入栈。

        (2) 当栈非空时执行以下操作:

1.将栈顶顶点vi的序号弹出,并输出之;

2.检查vi的出边表,将每条出边表邻接点域所对应的顶点的入度域值减1,若该顶点入度为0,则将其入栈;

        (3) 若输出的顶点数小于n,则输出“有回路”,否则拓扑排序正常结束。
        在具体实现时,链栈无须占用额外空间,只需利用顶点表中入度域值为0的入度域来存放链栈的指针(即指向下一个存放链栈指针的单元的下标),并用一个栈顶指针top指向该链栈的顶部即可。由此给出以下的具体算法:

#include<stdio.h>
#include<stdlib.h>
#define N 7//顶点个数

//邻接表的结构体
typedef struct Node
{
	int adjvex;
	struct Node *next;
}edgenode;

typedef struct
{
	char vertex;
	int id;
	edgenode *link;
}vexnode;

//进行拓扑排序
void TopoSort_AdjTable(vexnode ga[N])
{
	int i,j,k,m=0,top=-1;
	edgenode *p;
	for(i=0;i<N;i++)//将入度为0的顶点入栈
		if(ga[i].id==0)
		{
			ga[i].id=top;
			top=i;
		}
	while(top!=-1)//栈不为空
	{
		j=top;
		top=ga[top].id;//出栈
		printf("%c",ga[j].vertex);
		m++;
		p=ga[j].link;
		while(p)//删除该节点的所有出边
		{
			k=p->adjvex-1;
			ga[k].id--;
			if(ga[k].id==0)//将入度为0的顶点入栈
			{
				ga[k].id=top;
				top=k;
			}
			p=p->next;
		}
	}
	if(m<N)//当输出的顶点数小于N时,说明有环存在
		printf("该图存在环!");
}

void main()
{
	vexnode ga[N];
	char vertex[N]={'A','B','C','D','E','F','G'};
	int  ID[N]={0,1,2,0,1,1,3};
		for(int i=0;i<N;i++)
		{
			ga[i].vertex=vertex[i];
			ga[i].id=ID[i];
		}//初始化顶点表
		edgenode *s;
		
		//初始化边表
		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=2;
		ga[0].link=s;
		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=3;
		ga[0].link->next=s;
		s->next=NULL;

		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=6;
		ga[1].link=s;
		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=7;
		ga[1].link->next=s;
		s->next=NULL;


		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=7;
		ga[2].link=s;
		s->next=NULL;


		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=3;
		ga[3].link=s;
		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=5;
		ga[3].link->next=s;
		s->next=NULL;

		s=(edgenode *)malloc(sizeof(edgenode));
		s->adjvex=7;
		ga[4].link=s;
		s->next=NULL;

		ga[5].link=NULL;
		ga[6].link=NULL;
       //初始化边表结束
		TopoSort_AdjTable(ga);//进行拓扑排序
		printf("\n");


}

注:如果程序出错,可能是使用的开发平台版本不同,请点击如下链接: 解释说明


原文:http://blog.csdn.net/tengweitw/article/details/17304311

作者:nineheadedbird



目录
相关文章
|
4月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
19天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
63 8
|
19天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
58 7
|
2月前
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
53 9
|
2月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
25 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
2月前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
32 0
|
2月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
73 0
|
4月前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
44 1
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
|
4月前
|
算法 搜索推荐 Java
算法实战:手写归并排序,让复杂排序变简单!
归并排序是一种基于“分治法”的经典算法,通过递归分割和合并数组,实现O(n log n)的高效排序。本文将通过Java手写代码,详细讲解归并排序的原理及实现,帮助你快速掌握这一实用算法。
42 0
|
4月前
|
算法 关系型数据库 MySQL
揭秘MySQL中的版本号排序:这个超级算法将颠覆你的排序世界!
【8月更文挑战第8天】在软件开发与数据管理中,正确排序版本号对软件更新及数据分析至关重要。因MySQL默认按字符串排序版本号,可能出现&#39;1.20.0&#39;在&#39;1.10.0&#39;之前的不合理情况。解决办法是将版本号各部分转换为整数后排序。例如,使用`SUBSTRING_INDEX`和`CAST`函数从`software`表的`version`字段提取并转换版本号,再按这些整数排序。这种方法可确保版本号按逻辑正确排序,适用于&#39;major.minor.patch&#39;格式的版本号。对于更复杂格式,需调整处理逻辑。掌握此技巧可有效应对版本号排序需求。
197 3