第1章 绪论
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲01 绪论
概述
第一章作为绪论,主要介绍了数据结构与算法中的一些基本概念和术语。对于这些概念术语,我个人不推崇死记硬背,记住了当然好,记不住也没关系,但是一定要做到完全理解。就算嘴上说不出来,心里也一定要明白这个过程的含义。
数据结构
数据(data)是对客观事物的符号表示。在计算机科学中是指所有能输入到计算机中并被计算机程序处理的符号的总称。
数据元素(data element)是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。
数据对象(data object)是性质相同的数据元素的集合,是数据的一个子集。
数据结构(data structure)又称逻辑结构,是相互之间存在一种或多种特定关系的数据元素的集合。通常有以下四类基本结构:集合、线性结构、树形结构、图状结构或网状结构。
存储结构(物理结构)是数据结构在计算机中的表示(又称映像)。
数据类型(data type)是一个值的集合和定义在这个值集上的一组操作的总称。
抽象数据类型(AbstractData Type)是指一个数学模型以及定义在该模型上的一组操作,可细分为:原子类型、固定聚合类型、可变聚合类型。
算法
算法与数据结构密不可分,算法往往是建立在特定数据结构之上的。
一个算法有5个重要特性:有穷性、确定性、可行性、输入、输出。
而衡量一个算法是否优秀,则主要从以下几点考虑:正确性,可读性,健壮性,时间复杂度,空间复杂度。
其他
除了对数据结构和算法的简单介绍,本章还预定义了一些会被频繁使用的常量与类型,见下图所示的Status.h文件。
另外,为了之后测试数据方便,我自定义了一个从文件中读取数据的函数Scanf,使用格式与fscanf类同。
源码
文件一 ☛ Status.h
文件二 ☛ Scanf.c
第2章 线性表 - 单链表顺序存储结构
——《数据结构》-严蔚敏.吴伟民版
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\01 SequenceList
概述
数据结构的学习当然要从线性表学起,而线性表里首先需要学习单链表,这里从单链表最简单的顺序存储结构(本质就是可变数组存储)开始。
解析
单链表强调元素在逻辑上紧密相邻,所以首先想到用数组存储。但是普通数组有着无法克服的容量限制,在不知道输入有多少的情况下,很难确定出一个合适的容量。对此,一个较好的解决方案就是使用动态数组。首先用malloc申请一块拥有指定初始容量的内存,这块内存用作存储单链表元素,当录入的内容不断增加,以至于超出了初始容量时,就用calloc扩展内存容量,这样就做到了既不浪费内存,又可以让单链表容量随输入的增加而自适应大小。
单链表顺序存储结构如下图:
可能涉及到的语法难点
刚接触数据结构的同学,单链表顺序存储结构可能会是其面对的第一个坎。这里涉及到了结构体、动态数组、结构指针,甚至还有函数变量(函数做参数,本质是函数指针),所以需要有相对扎实的语言语法基础。当然,这也并不是说一定得掌握了高级语法才能开始学习数据结构,可以先将语言学到入门(入门意味着学会了提问),再边学数据结构边巩固语法。一定要亲自动手写一写,否则,肯定学不好。
源码
文件一 ☛ SequenceList.h
文件二 ☛ SequenceList.c
文件三 ☛ SequenceList-main.c (测试文档)
测试结果展示
第2章 线性表 - 求并集A=A∪B
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\02 Union
概述
求并集A=AUB是数学集合中最常用的操作之一。
解析
求并集的思路很简单,大致可分为三步:
第一:找到A的链表尾部;
第二:开始遍历B,判断B的每个元素是否在A中存在;
第三:如果B中元素不在A中,则将其插入到A中,并继续向前探索,直至遍历完B中全部元素。
可能涉及到的语法难点
通过这个小示例。进一步体会多函数协作的优点。把不同功能的函数分开写,把不同职责的文件分开写,有利于程序的可读性与健壮性。
源码
文件一 ☛ Union.h
文件二 ☛ Union.c
文件三 ☛ Union-main.c (测试文档)
测试结果展示
第2章 线性表 - 归并单链表(顺序表)
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\03 MergeSqList
概述
单链表(顺序表)归并算法,将两个顺序表合并到一个新的顺序表中,要求合并前后顺序表均有序排列。
解析
顺序表的归并有两种方案,一种使用指针,另一种利用数组下标实现。两种方案都还是通过调用单链表顺序存储结构中封装的各个函数的来实现的,理解上并无难度。
源码
文件一 ☛ MergeSqList.h
文件二 ☛ MergeSqList.c
文件三 ☛ MergeSqList-main.c (测试文档)
测试结果展示
第2章 线性表 - 单链表链式存储
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\04 SinglyLinkedList
概述
比起之前顺序存储的单链表,链式存储有很多优点,比如删除与插入更方便,不用来回移动大量元素。但与此对应的是存取指定位置元素时将变得费劲,因为顺序存储结构中,通过数组下标就可以获取第i个元素,但是在链式存储中,必须由头指针或尾指针(如果有的话)开始遍历整个链表直至寻找到需要的元素。在元素的查找效率方面,此两种存储结构无明显差异。
解析
单链表链式存储结构引入了链表的概念,链表由一个个小的结点组成,每个结点都包含一个数据域和指针域,指针域指向的是紧邻的下一个结点,最后一个结点指针通常为NULL。如果将最后一个结点的指针指向开头,那么这个链表就成了循环单链表。
值得注意的是,这儿所示的链表都是有头结点的单链表。有头结点意味着头结点指针指向的结点数据域为空,头结点的存在仅仅是作为标记单链表的开始,有头结点的单链表在操作时更加方便,不用专门为头结点的增删情况写额外代码,这一点可以在实际应用中加以体会。
单链表链式结构如下图:
可能涉及到的语法难点
单链表链式存储也用到了动态分配内存。值得注意的是,由于头结点的指针本身就是个结构指针,所以在初始化、创建、销毁等需要改变头结点指针的地方,则要注意函数形参为二级指针,即指向头指针的指针。新手很容易犯的错误是该用二级指针的地方使用了一级指针,这样做的后果就是明明函数内分配了所需内存,但是外面却访问不到,也可能明明函数内销毁掉的内存,外面还可以访问到。这样不仅会引起内存访问差错,甚至会引起程序崩溃,所以,这一点很值得引起重视。
源码
文件一 ☛ SinglyLinkedList.h
文件二 ☛ SinglyLinkedList.c
文件三 ☛ SinglyLinkedList-main.c (测试文档)
文件四 ☛ TestData_HL.txt (头插法数据文档)
文件五 ☛ TestData_TL.txt (尾插法数据文档)
测试结果展示
第2章 线性表 - 归并单链表(链式存储)
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\05 MergeList
概述
链式单链表的归并,与算法思想一致。
解析
归并单链表时会涉及到插入操作。在顺序存储的单链表里,插入一个元素意味着要将插入点之后的元素整体后移。但是在链式存储的单链表里,只需改变插入点附近的指针即可,节省了大量时间。
链式存储的单链表插入一个元素的方式如下图:
源码
文件一 ☛ MergeList.h
文件二 ☛ MergeList.c
文件三 ☛ MergeList-main.c (测试文档)
文件四 ☛ TestData_HL.txt (头插法数据文档)
文件五 ☛ TestData_TL.txt (尾插法数据文档)
测试结果展示
第2章 线性表 - 静态链表
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\06 StaticLinkedList
概述
静态链表用数组存放数据,存取方式模拟了系统的malloc分配和free回收机制。
解析
在《数据结构》原书中,对静态链表的表述是有些复杂的,这里对其进行了适当简化,但中心思想不变。
静态链表是特殊的顺序表,它从数组(一块连续的内存)中孕育,但行为却类似于单链表,它反映出了链式单链表在系统中实现的本质。静态链表依靠自身的一个游标来实现单链表中结构指针的作用,所以,在存取元素时,一方面要考虑静态链表内部的游标变动,另一方面也要考虑整个空间中剩余内存的游标变化,因为整个内存块同样也是通过游标来链接的。
静态链表存储结构及存取机制如下图:
可能涉及到的语法难点
灵活应用typedef来创造新类型,比如在静态空间SPACE定义时,将整个结构数组看做了一个新的类型Component。
源码
文件一 ☛ StaticLinkedList.h
文件二 ☛ StaticLinkedList.c
文件三 ☛ StaticLinkedList-main.c (测试文档)
测试结果展示
第2章 线性表 - 集合运算(A-B)∪(B-A)
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\07 Difference
概述
利用静态链表求集合(A-B)∪(B-A)。
解析
思路很简单,先建立包含集合A中元素的静态链表,然后遍历集合B,若B中元素不在A中,将其加入静态链表,否则,将其从静态链表中删掉,注意头、尾指针的修改。
源码
文件一 ☛ Difference.h
文件二 ☛ Difference.c
文件三 ☛ Difference-main.c (测试文档)
文件四 ☛ TestData.txt (集合A和B的数据文档)
测试结果展示
第2章 线性表 - 双循环链表链式存储
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\08 DualCycleLinkedList
概述
双循环链表就是头尾相连,并且每一个结点都可以指向它的前驱和后继的链表。
解析
双循环链表解决了单链表无法回溯的问题,即在双循环链表中,从任一结点出发都可以顺序或者逆序遍历完整个链表。双循环链表的操作中,插入和删除较为重要,要注意改变各指针指向时的次序。另外要特别留意头、尾结点指针的改变。
双链表插入、删除如下图:
源码
文件一 ☛ DualCycleLinkedList.h
文件二 ☛ DualCycleLinkedList.c
文件三 ☛ DualCycleLinkedList-main.c (测试文档)
测试结果展示
第2章 线性表 - 扩展的线性单链表
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\09 ExtenLinkedList
概述
扩展的线性单链表即在普通的单链表上增设了尾指针,并保存了链表的长度。
解析
扩展的线性单链表重新定义了单链表,并增设了一系列常用操作,如DelFirst、Append、Remove等函数。此处的线性单链表只是对原单链表数据域和操作集的扩充,其链表本质并无变化。
源码
文件一 ☛ ExtenLinkedList.h
文件二 ☛ ExtenLinkedList.c
文件三 ☛ ExtenLinkedList-main.c (测试文档)
测试结果展示
第2章 线性表 - 归并扩展的线性链表
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\10 MergeEList
概述
依然是线性表归并算法,不过这次归并的是经过扩展的线性表。
解析
本次归并应用的都是扩展的线性表里的操作,使整个归并算法更加高效。
源码
文件一 ☛ MergeEList.h
文件二 ☛ MergeEList.c
文件三 ☛ MergeEList-main.c (测试文档)
文件四 ☛ TestData_La.txt (线性单链表La数据文件)
文件五 ☛ TestData_Lb.txt (线性单链表Lb数据文件)
测试结果展示
第2章 线性表 - 一元多项式运算
——《数据结构》-严蔚敏.吴伟民版
★有疑问先阅读★
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲02 线性表\11 Polynomial
概述
一元多项式的运算,采用的存储结构是扩展的线性表。
解析
一元多项式的运算本质是对扩展的线性表进行插入,删除操作,理解上并无难度,遇到想不通的地方,可以画示意图辅助理解。
源码
文件一 ☛ Polynomial.h
文件二 ☛ Polynomial.c
文件三 ☛ Polynomial-main.c (测试文档)
文件四 ☛ TestData_Pa.txt (一元多项式Pa数据文件)
文件五 ☛ TestData_Pb.txt (一元多项式Pb数据文件)
测试结果展示
第3章 栈和队列 - 栈的顺序存储
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\01 SequenceStack
概述
栈仍然是一种顺序存储结构。它的最大特点是“先进后出,后进先出”。
解析
栈在定义中,是一种只允许一端进行插入和删除的数据结构。先入栈的元素,必须在比它入栈晚的元素全部出栈后,它才能出栈。栈可以保存暂时不用的“元素”,以便将来回溯时候使用,在寻路算法中很常见。
栈的顺序存储结构如下图:
源码
文件一 ☛ SequenceStack.h
文件二 ☛ SequenceStack.c
文件三 ☛ SequenceStack-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 进制转换(十进制转八进制)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\02 Conversion
概述
进制转换是“栈”结构的典型用法,所有的进制转换原理都一样。
解析
由高进制向低进制转换时,用栈存储初始的余数是最好的选择。
以十进制转八进制为例,其转换过程如下图:
源码
文件一 ☛ Conversion.h
文件二 ☛ Conversion.c
文件三 ☛ Conversion-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 行编辑程序
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\03 LineEdit
概述
行编辑程序是模拟文本输入的过程,对输入中的退格、替换等操作要做出响应。
解析
在文本输入中,不能确保所有的输入都正确,这时候就需要一个缓冲区来存放输入的字符串,以便之后进行增删操作。在增删过程中,总是先从缓冲区的末尾开始修改,无疑,栈是这个缓冲区的最佳选择。
注:原书的代码实现了人机互动,为了解决手动输入文本的麻烦,这儿采取的策略是先将输入预先保存到一个字符串中,然后对字符串进行处理之后再输出,这样可以简化测试流程。
源码
文件一 ☛ LineEdit.h
文件二 ☛ LineEdit.c
文件三 ☛ LineEdit-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 迷宫寻路
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\04 Maze
概述
迷宫寻路的经典解法便是穷举法。
解析
迷宫寻路的穷举法即是对每一种可能的通道都做出探索,直到找到第一条完全畅通的路径。
穷举法的缺点是操作比较费时,而优点是算法相对简洁,易于理解。在穷举遍历中,需要保存来时的路径,如果在某个方向遇到错误的路径,则需要退回到上一次正确的状态,并尝试对下一个方向进行遍历。由于遍历中需要经常用到这些“回溯”操作,所以栈就成了穷举法最佳的数据结构,栈的每一个元素便是加入路径的结点(包括位置、状态信息):
源码
文件一 ☛ Maze.h
文件二 ☛ Maze.c
文件三 ☛ Maze-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 表达式求值
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\05 Expression
概述
表达式求值最重要的是分析各运算符的优先级。
解析
表达式求值中需要用到两个栈,一个操作数栈,一个运算符栈。核心思想是优先处理具有最高优先级的运算符,其他的先入栈,特别注意两个符号在实际运算中优先级相同时,在本问题中的表述有所区别。
常见的运算符优先级如下图(#是结束标记):
源码
文件一 ☛ Expression.h
文件二 ☛ Expression.c
文件三 ☛ Expression-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 汉诺塔(Hanoi Tower)问题
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 无外链
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\06 Hanoi
概述
汉诺塔是递归的经典应用。
解析
栈在定义中,是一种只允许一端进行插入和删除的数据结构。先入栈的元素,必须在比它入栈晚的元素全部出栈后,它才能出栈。栈可以保存暂时不用的“元素”,以便将来回溯时候使用,在寻路算法中很常见。
汉诺塔问题如下图:
问题描述为将塔X上的圆盘全部移动到塔Z,且移动过程中,小盘始终位于大盘上方。解决思路就是欲将n个圆盘从X移动到Z,只需先移动前n-1个圆盘到辅助塔Y,再将剩下的一个圆盘从X移动到Z,最后再以X作为辅助塔,将余下的n-1个圆盘从Y移动到Z。
源码
文件一 ☛ Hanoi.h
文件二 ☛ Hanoi.c
文件三 ☛ Hanoi-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 队列的链式存储
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\07 LinkQueue
概述
队列也是一种逻辑顺序存储结构,它的最大特点是“先进先出,后进后出”,队列操作其实就是一个排队过程。
解析
队列在定义中,有两个端点,一端只允许增加元素,另一端只允许删除元素,这很类似于去排队办事,先来的可以先办,后来的只能在队列中等待。
与栈类似,队列也可以用顺序存储或者链式存储,而且队列也有很多变体,此处仅讨论链式存储的,带头结点的经典队列模型。
源码
文件一 ☛ LinkQueue.h
文件二 ☛ LinkQueue.c
文件三 ☛ LinkQueue-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 循环队列
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\08 CylSeqQueue
概述
循环队列是队列的一种变体,它仍然遵循队列“先进先出,后进后出”的特性。
解析
当队列用顺序存储结构时,容易造成空间浪费,用链式存储结构时,操作会显得不便(涉及到空间的申请、释放)。所以,在队列所需容量可以预估的前提下,一种折衷的存储方案是用数组作为存储结构,但逻辑上采用循环队列这种变体。
循环队列的难点在于对队列空、队列满、队列长度的判断上,结合图例会更容易理解。
循环队列存储方式如下图(用数组存放其元素):
源码
文件一 ☛ CylSeqQueue.h
文件二 ☛ CylSeqQueue.c
文件三 ☛ CylSeqQueue-main.c (测试文档)
测试结果展示
第3章 栈和队列 - 模拟银行排队过程
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲03 栈和队列\09 BankQueuing
概述
用队列这种数据结构模拟银行的排队过程。
解析
通过对银行排队过程的模拟,可以计算出每天到达银行的客户数量,以及客户的平均逗留时间。
本次模拟中,将动态演示在一定时间段内,银行的客户排队办理业务的过程,银行的营业时间、办理业务的持续时间、每两个客户到达的时间间隔都是可以自定义的。默认新来的客户总是排在人数较少的队伍中,且优先进入号码小的柜台排队。
源码
文件一 ☛ BankQueuing.h
文件二 ☛ BankQueuing.c
文件三 ☛ BankQueuing-main.c (测试文档)
测试结果展示
第4章 串 - 顺序串
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲04 串\01 SequenceString
概述
串可以用多种存储方式表示,顺序存储是最简单的一种,类似于数组。
解析
串的顺序存储方式即是在一个字符数组中存放各字符,注意此存储方式并不包含空字符,存储字串的数组的0号单元用来标识字串长度。其存储结构如下图:
源码
文件一 ☛ SequenceString.h
文件二 ☛ SequenceString.c
文件三 ☛ SequenceString-main.c (测试文档)
测试结果展示
第4章 串 - 堆串
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲04 串\02 HeapString
概述
堆串的本质还是顺序存储,只不过内存是动态分配的。
解析
堆串是个结构体,char指针指向动态分配的内存来存储字符,length用来存储串的长度。也正是因为需要使用malloc动态分配串的空间,所分配的内存均位于“堆”上,所以这种存储结构被称为“堆串”。
堆串存储结构如下图:
源码
文件一 ☛ HeapString.h
文件二 ☛ HeapString.c
文件三 ☛ HeapString-main.c (测试文档)
测试结果展示
第4章 串 - 块链串
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲04 串\03 BlockChainString
概述
块链串的本质依然是顺序存储,每个字串用数组接纳,各内存块用指针顺序链接。
解析
块链串的重点在于“块”和“链”。块链串用链表的思维存储字串,但每个结点并不是存储一个字符,还是存储多个字符,不用的“块”之间用指针相“链”。
块链串存储结构如下图:
源码
文件一 ☛ BlockChainString.h
文件二 ☛ BlockChainString.c
文件三 ☛ BlockChainString-main.c (测试文档)
测试结果展示
第4章 串 - KMP匹配算法
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲04 串\04 KMP
概述
KMP匹配算法是普通匹配算法的改进,它提高了串匹配过程中的效率。
解析
KMP匹配算法的重点在于利用模式串自身的重复部分,在匹配中消除那些重复的匹配过程。如下图,当模式串匹配与主串在Si和Pj处失配时,此时如果模式串的两个黄色区域重复,那么只需将模式串右移一定位置,让主串的黄色区域与模式串的第一个黄色区域做比较即可。也就是说,Pj处失配后,只需让主串的Si与Pk继续比较,而不必退回到P1处。KMP算法就是用来计算模式串某个字符处失配后,应该退回的下一个用来比较的字符位置。
匹配算法如下图:
源码
文件一 ☛ KMP.h
文件二 ☛ KMP.c
文件三 ☛ KMP-main.c (测试文档)
测试结果展示
第4章 串 - 创建索引表
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲04 串\05 WordIndexTable
概述
创建索引表就是从一个文档中提取关键词,并将关键词与其编号提取出来,经过对应后生成便于查找的索引表。
解析
创建索引表的过程比较繁琐,但原理是简单的,无非就是一些串的操作和文件的操作,操作过程的描述可参见原教材。
创建索引表中涉及的数据结构如下图:
源码
文件一 ☛ WordIndexTable.h
文件二 ☛ WordIndexTable.c
文件三 ☛ WordIndexTable-main.c (测试文档)
文件四 ☛ BookInfo.txt(书目信息)
测试结果展示
第5章 数组和广义表 - 数组的顺序存储结构
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲05 数组和广义表\01 SequenceArray
概述
数组是应用广泛,易于理解的线性存储结构,几乎所有的程序设计语言都把数组类型设定为固有类型。
解析
手动实现数组的关键在于理解各维度的含义,这里可借助数组元素的循环遍历来理解。由于数组维度的任意性,故需要使用可变参数技术来实现维度和行列信息的动态改变。
一维数组、二维数组、三维数组的存储结构如下图:
源码
文件一 ☛ SequenceArray.h
文件二 ☛ SequenceArray.c
文件三 ☛ SequenceArray-main.c (测试文档)
测试结果展示
第5章 数组和广义表 - 三元组顺序表(稀疏矩阵)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲05 数组和广义表\02 TripleSparseMatrix
概述
三元组是存储稀疏矩阵的一种方式,对于非零元较多的矩阵,可以节省很大一部分空间。
解析
三元组中只存储矩阵元素不为0(空)的项,每项标出其行、列、值信息,最后要指出矩阵中行数、列数以及非零元的个数。对于此数据结构,比较重要的算法是矩阵快速转置。
源码
文件一 ☛ TripleSparseMatrix.h
文件二 ☛ TripleSparseMatrix.c
文件三 ☛ TripleSparseMatrix-main.c (测试文档)
文件四 ☛ TestData_TSMatrix.txt (三元组顺序表测试数据)
测试结果展示
第5章 数组和广义表 - 行逻辑链接的顺序表(稀疏矩阵)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲05 数组和广义表\03 RowLinkSparseMatrix
概述
行逻辑链接的顺序表是三元组顺序表的改进,在三元组顺序表的存储结构中加入“行链接”信息。
解析
用行逻辑链接的顺序表便于随机存取任意一行的非零元,利用此“行链接”信息可以降低稀疏矩阵乘法的时间复杂度,但是代码量会增多。
源码
文件一 ☛ RowLinkSparseMatrix.h
文件二 ☛ RowLinkSparseMatrix.c
文件三 ☛ RowLinkSparseMatrix-main.c (测试文档)
文件四 ☛ TestData_RLSMatrix.txt (行逻辑链接的顺序表测试数据)
测试结果展示
第5章 数组和广义表 - 十字链表(稀疏矩阵)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲05 数组和广义表\04 CrossList
概述
十字链表是稀疏矩阵较复杂的一种存储方式。
解析
十字链表将矩阵的每一行每一列都视为一个链表,通过指针,将每一个非零的矩阵元素串接起来,形成一个稀疏的“网格”。此种存储结构也易于理解,但是在操作上略显繁琐。
源码
文件一 ☛ CrossList.h
文件二 ☛ CrossList.c
文件三 ☛ CrossList-main.c (测试文档)
文件四 ☛ TestData_CrossList.txt (十字链表测试数据)
测试结果展示
第5章 数组和广义表 - 广义表(头尾链表存储表示)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲05 数组和广义表\05 GeneralizedList-H&T
概述
头尾链表存储表示的广义表。
解析
分析头尾链表存储表示的广义表时要先去外层括号,然后分离表头和表尾。
头尾链表存储表示的广义表如下图:
源码
文件一 ☛ GeneralizedList-H-T.h
文件二 ☛ GeneralizedList-H-T.c
文件三 ☛ GeneralizedList-H-T-main.c (测试文档)
测试结果展示
第5章 数组和广义表 - 广义表(扩展线性链表存储表示)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲05 数组和广义表\06 GeneralizedList-E
概述
扩展线性链表存储表示的广义表。
解析
分析扩展线性链表存储表示的广义表时要带上外层括号,然后观察表头和表尾。
扩展线性链表存储表示的广义表如下图:
源码
文件一 ☛ GeneralizedList-E.h
文件二 ☛ GeneralizedList-E.c
文件三 ☛ GeneralizedList-E-main.c (测试文档)
测试结果展示
第6章 树和二叉树 - 二叉树顺序存储结构
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\01 SeqBinaryTree
概述
二叉树的顺序存储结构即用一个数组按一定次序存储二叉树中的各元素。
解析
二叉树的顺序存储结构易于理解,但不常用。二叉树中的各元素映射到此顺序结构中的位置是固定的,所以如果是完全二叉树,则空间利用率会较高。操作时的难点在于找出“树”中各元素的位置和顺序存储中各元素下标的一一对应关系。
二叉树顺序存储结构如下图:
源码
文件一 ☛ SeqBinaryTree.h
文件二 ☛ SeqBinaryTree.c
文件三 ☛ SeqBinaryTree-main.c (测试文档)
文件四、文件五 ☛ TestData_Le.txt、TestData_Pre.txt (二叉树顺序存储结构测试数据)
测试结果展示
第6章 树和二叉树 - 二叉树(二叉链表存储)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\02 BinaryTree
概述
二叉树的二叉链表存储是二叉树最常用的一种存储结构。
解析
在对二叉树的二叉链表存储结构操作中,运用了很多递归算法,可以说递归是二叉树操作的核心技术。
二叉树的二叉链表存储结构如下:
源码
文件一 ☛ BinaryTree.h
文件二 ☛ BinaryTree.c
文件三 ☛ BinaryTree-main.c (测试文档)
文件四、文件五 ☛ TestData_T.txt、TestData_T0 (二叉树二叉链表存储结构测试数据)
测试结果展示
第6章 树和二叉树 - 二叉树(三叉链表存储)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\03 Tri_BinaryTree
概述
二叉树的三叉链表存储结构是二叉树二叉链表存储结构的改进。
解析
二叉树的三叉链表存储结构在二叉树的二叉链表存储结构上增设了一个parent域指向双亲结点,便于回溯。
二叉树三叉链表存储结构如下图:
源码
文件一 ☛ Tri_BinaryTree.h
文件二 ☛ Tri_BinaryTree.c
文件三 ☛ Tri_BinaryTree-main.c (测试文档)
文件四、文件五 ☛ TestData_T.txt、TestData_T0 (二叉树三叉链表存储结构测试数据)
测试结果展示
第6章 树和二叉树 - 线索二叉树
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\04 ThreadBinaryTree
概述
线索二叉树的常用结构有:先/中/后序前驱/全/后继线索二叉树,这里讨论先序后继线索二叉树、中序全线索二叉树、后序后继线索二叉树。
解析
线索二叉树是将普通二叉树左右孩子中的空链域利用起来,将左孩子空链域指向当前节点的线性遍历前驱,将右孩子空链域指向当前节点的线性遍历后继,指向该线性序列中的前驱或后继被称为“线索”。由于在线索链表中添加了遍历中得到的“前驱”和“后继”的信息,从而简化了遍历的算法。
中序全线索二叉树结构如下:
源码
文件一 ☛ ThreadBinaryTree.h
文件二 ☛ ThreadBinaryTree.c
文件三 ☛ ThreadBinaryTree-main.c (测试文档)
文件四、文件五 ☛ TestData_T.txt(线索二叉树测试数据)
测试结果展示
第6章 树和二叉树 - 树的双亲表示法
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\05 ParentTree
概述
树的双亲表示法也是一种顺序存储结构,且增设了双亲域,便于找到每个结点的双亲节点,回溯方便。注意此处是树而不是二叉树。
解析
树的双亲表示法可应用于并查集中,快速判定两个元素是否属于同一个集合。创建时注意数据的录入方式(看代码是一件痛苦的事...)。
树的双亲表示法结构如下图:
源码
文件一 ☛ ParentTree.h
文件二 ☛ ParentTree.c
文件三 ☛ ParentTree-main.c (测试文档)
文件四、文件五 ☛ TestData_T.txt、TestData_T0.txt(树的双亲表示法测试数据)
测试结果展示
第6章 树和二叉树 - 树的孩子链表(带双亲)存储表示
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\06 ChildTree
概述
树的孩子链表存储表示中可以很方便地查找到每个结点的子结点以及兄弟结点,带上双亲域后,还可以很方便地找出其双亲结点,比树的双亲表示法更胜一筹。
解析
树的孩子链表存储表示操作起来较为繁琐,主要原因是其中既涉及顺序表操作,又涉及链表操作。
树的孩子链表存储(带双亲)表示如下图:
源码
文件一 ☛ ChildTree.h
文件二 ☛ ChildTree.c
文件三 ☛ ChildTree-main.c (测试文档)
文件四、文件五 ☛ TestData_T.txt、TestData_T0.txt(树的孩子链表存储表示法测试数据)
测试结果展示
第6章 树和二叉树 - 树的二叉链表(孩子-兄弟)存储表示
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\07 ChildSiblingTree
概述
树的孩子-兄弟存储结构也是一个二叉链表,不过它的左分支为孩子结点,右分支为兄弟结点。
解析
树的孩子-兄弟存储结构可用于树和森林的转换,查找某结点的子结点或兄弟结点都比较容易。
树的孩子-兄弟存储结构如下图:
源码
文件一 ☛ ChildSiblingTree.h
文件二 ☛ ChildSiblingTree.c
文件三 ☛ ChildSiblingTree-main.c (测试文档)
文件四、文件五 ☛ TestData_T.txt、TestData_T0.txt(树的二叉链表(孩子-兄弟)存储表示法测试数据)
测试结果展示
第6章 树和二叉树 - 并查集(等价类)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\08 MFSet
概述
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
解析
这里介绍并查集的一种简单实现,使用的存储结构是树的双亲表示法。
源码
文件一 ☛ MFSet.h
文件二 ☛ MFSet.c
文件三 ☛ MFSet-main.c (测试文档)
文件四、文件五、文件六 ☛ TestData_R1.txt、TestData_R2.txt、TestData_S.txt(并查集(等价类)测试数据)
测试结果展示
第6章 树和二叉树 - 哈夫曼树(HuffmanTree)
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\09 HuffmanTree
概述
给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
解析
哈夫曼树常用于在通信中构造哈夫曼编码,减少数据传输量。
源码
文件一 ☛ HuffmanTree.h
文件二 ☛ HuffmanTree.c
文件三 ☛ HuffmanTree-main.c (测试文档)
文件四 ☛ TestData_HT.txt(哈夫曼树测试数据)
测试结果展示
第6章 树和二叉树 - 幂集
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\10 PowerSet
概述
幂集(Power Set), 就是原集合中所有的子集(包括全集和空集)构成的集族。
解析
注意幂集运算中对递归的应用。
源码
文件一 ☛ PowerSet.h
文件二 ☛ PowerSet.c
文件三 ☛ PowerSet-main.c (测试文档)
文件四 ☛ TestData_A.txt(幂集测试数据)
测试结果展示
第6章 树和二叉树 - N皇后问题
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲06 树和二叉树\11 NQueens
概述
N皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。其问题描述为N×N格的国际象棋上摆放N个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
解析
这里令N=8,解决八皇后问题。
源码
文件一 ☛ NQueens.h
文件二 ☛ NQueens.c
文件三 ☛ NQueens-main.c (测试文档)
测试结果展示
第7章 图 - 图、表的数组(邻接矩阵)表示法
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\01 MGraph
概述
图、表的数组(邻接矩阵)表示法适用范围广泛,可以用来描述有向图、有向表、无向图、无向表。
解析
在图的邻接矩阵表示法中,用邻接矩阵表示顶点间的相邻关系,而用一个顺序表来存储顶点信息。
图、表的存储方式很多,适用范围不同,其对应的算法实现也各不相同,需多加练习。
源码
文件一 ☛ MGraph.h
文件二 ☛ MGraph.c
文件三 ☛ MGraph-main.c (测试文档)
文件四、文件五、文件六、文件七 ☛ TestData_DG_M.txt、TestData_DN_M.txt、TestData_UDG_M.txt、TestData_UDN_M.txt(图、表测试数据)
测试结果展示
第7章 图 - 图的邻接表存储表示
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\02 ALGraph
概述
邻接表是图的常用储存结构之一。邻接表由表头结点和表结点两部分组成,其中图中每个顶点均对应一个存储在数组中的表头结点。
解析
邻接表是图的一种最主要存储结构,用来描述图上的每一个点。对图的每个顶点建立一个容器(n个顶点建立n个容器),第i个容器中的结点包含顶点Vi的所有邻接顶点。实际上我们常用的邻接矩阵就是一种未离散化每个点的边集的邻接表。
源码
文件一 ☛ ALGraph.h
文件二 ☛ ALGraph.c
文件三 ☛ ALGraph-main.c (测试文档)
文件四、文件五 ☛ TestData_DG_AL.txt、TestData_UDG_AL.txt(图的邻接表测试数据)
测试结果展示
第7章 图 - 有向图的十字链表存储结构
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\03 OLGraph
概述
有向图十字链表存储结构是有向图的一种链式存储结构,可看成邻接表和逆邻接表结合而成。
解析
十字链表之于有向图,类似于邻接表之于无向图。在十字链表中,对应于有向图中每一条弧都有一个结点,对应于每个定顶点也有一个结点。
源码
文件一 ☛ OLGraph.h
文件二 ☛ OLGraph.c
文件三 ☛ OLGraph-main.c (测试文档)
文件四 ☛ TestData_DG_OL.txt(有向图的十字链表存储结构测试数据)
测试结果展示
第7章 图 - 无向图的邻接多重表存储结构
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\04 AMLGraph
概述
邻接多重表主要用于存储无向图,其存储结构和十字链表类似,也是由顶点表和边表组成,每一条边用一个结点表示。
解析
如果用邻接表存储无向图,每条边的两个边结点分别在以该边所依附的两个顶点为头结点的链表中,这给图的某些操作带来不便。例如,对已访问过的边做标记,或者要删除图中某一条边等,都需要找到表示同一条边的两个结点。因此,在进行这一类操作的无向图的问题中采用邻接多重表作存储结构更为适宜。
源码
文件一 ☛ AMLGraph.h
文件二 ☛ AMLGraph.c
文件三 ☛ AMLGraph-main.c (测试文档)
文件四 ☛ TestData_UDG_AML.txt(无向图的邻接多重表存储结构测试数据)
测试结果展示
第7章 图 - 无向图生成树
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\05 SpanningTree
概述
无向图生成树有两个概念:第一是分离出无向图中各个连通的子图,第二是将各个连通的子图转换成孩子-兄弟存储形式的二叉树。
解析
采用深度优先遍历策略来生成无向图的生成树或森林。
源码
文件一 ☛ SpanningTree.h
文件二 ☛ SpanningTree.c
文件三 ☛ SpanningTree-main.c (测试文档)
文件四 ☛ TestData_UDG_M.txt(无向图生成树测试数据)
测试结果展示
第7章 图 - 有向图强连通分量的Kosaraju算法
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\06 StronglyConnectedComponents
概述
用Kosaraju算法生成有向图的强连通分量时,需要用到十字链表存储有向图,因为这种结构方便逆置有向图。
解析
有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。
求有向图强连通分量的通用算法是Kosaraju算法,其比较关键的部分是同时应用了原图G和反图GT。步骤一:先用对原图G进行深搜形成森林(树),步骤二:任选一棵树对其进行深搜(注意这次深搜节点A能往子节点B走的要求是EAB存在于反图GT),能遍历到的顶点就是一个强连通分量。余下部分和原来的森林一起组成一个新的森林,继续步骤2直到 没有顶点为止。
源码
文件一 ☛ SCC.h
文件二 ☛ SCC.c
文件三 ☛ SCC-main.c (测试文档)
文件四 ☛ TestData_DG_OL.txt(有向图的强连通分量测试数据)
测试结果展示
第7章 图 - 无向网的最小生成树
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\07 MiniSpanningTree
概述
普里姆(prim)算法和克鲁斯卡尔(kruskal)算法是计算无向网最小生成树的常用算法。
解析
简单地说,就是从n个结点的无向网中,选出n-1条权值最小的边组成一颗树。
普里姆算法的策略简述为以点带边,而克鲁斯科尔算法的策略简述为以边定点,不管哪种策略,都要选择当前最小权值的边,且不能构成回路。
源码
文件一 ☛ MST.h
文件二 ☛ MST.c
文件三 ☛ MST-main.c (测试文档)
文件四 ☛ TestData_UDN_M.txt(无向网的最小生成树测试数据)
测试结果展示
第7章 图 - 无向图的关节点
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\08 ArticulationPoint
概述
图的关节点被描述为:如果去掉图中某个结点后,剩下的结点无法再构成完整的连通图,那么这个去掉的结点就是关节点。
解析
计算关节点关键是在深搜建立图的生成树过程中对各结点的访问次序进行编号,以下两种情况可分辨出关节点:
1.若生成树的根有两颗及两棵以上的子树,那么此根结点为必为关节点。
2.若某个结点v既非根结点,也非叶子结点,那么以v为根的树中,如果存在某棵子树的根或者子树的其他结点均没有指向v的祖先的回边,则v为关节点。
源码
文件一 ☛ ArticulationPoint.h
文件二 ☛ ArticulationPoint.c
文件三 ☛ ArticulationPoint-main.c (测试文档)
文件四 ☛ TestData_UDG_AL.txt(无向图的关节点测试数据)
测试结果展示
第7章 图 - 有向无环图拓扑排序
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\09 TopologicalSort
概述
拓扑排序,是将有向无环图G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。
解析
构造一个有向无环图的拓扑序列的步骤主要是循环执行以下两步,直到不存在入度为0的顶点为止:
(1) 选择一个入度为0的顶点并输出之;
(2) 从图中删除此顶点及所有的出边。
注意,拓扑排序的线性序列不唯一。
源码
文件一 ☛ TopologicalSort.h
文件二 ☛ TopologicalSort.c
文件三 ☛ TopologicalSort-main.c (测试文档)
文件四 ☛ TestData_DG_AL.txt(有向无环图拓扑排序测试数据)
测试结果展示
第7章 图 - 有向网关键路径
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\10 CriticalPath
概述
关键路径通常(但并非总是)是决定项目工期的进度活动序列,它是项目中最长的路径,即使很小浮动也可能直接影响整个项目的最早完成时间。
解析
用顶点表示事件,弧表示活动,弧上的权值表示活动持续的时间的有向图叫AOE(Activity On Edge Network)网,在建筑学中也称为关键路线。AOE网常用于估算工程完成时间。
关键路径的算法建立在拓扑排序的基础之上,其计算方法简述为:
1.输入e条弧<j,k>,建立AOE-网的存储结构。
2.拓扑排序,并求得ve[]。从源点V0出发,令ve[0]=0,按拓扑有序求其余各顶点的最早发生时间ve[i]。如果得到的拓扑有序序列中顶点个数小于网中顶点数n,则说明网中存在环,不能求关键路径,算法终止;否则执行步骤3。
3.拓扑逆序,求得vl[]。从汇点Vn出发,令vl[n-1] = ve[n-1],按逆拓扑有序求其余各顶点的最迟发生时间vl[i]。
4.求得关键路径。根据各顶点的ve和vl值,求每条弧s的最早开始时间e(s)和最迟开始时间l(s)。若某条弧满足条件e(s) = l(s),则为关键活动。
注:此有向网使用了图的邻接表存储结构是为了方便进行拓扑排序。由于此处的邻接表存储结构中无结点的权值信息,故将有向网的权值信息放到了"弧的附加信息"中,也算是变通吧。当然,也可以通过修改原来的邻接表存储结构来应对此处的算法。
源码
文件一 ☛ CriticalPath.h
文件二 ☛ CriticalPath.c
文件三 ☛ CriticalPath-main.c (测试文档)
文件四 ☛ TestData_DG_AL.txt(有向网关键路径测试数据)
测试结果展示
第7章 图 - 最短路径算法
——《数据结构》-严蔚敏.吴伟民版
源码使用说明 链接☛☛☛
课本源码合辑 链接☛☛☛
习题集全解析 链接☛☛☛
本源码引入的文件 链接☛ 、
文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲07 图\11 ShortestPath
概述
计算最短路径的常用算法是弗洛伊德(Floyd)算法和迪杰斯特拉(Dijkstra)算法。
解析
在有向网中,Dijkstra算法用来计算网中某一点到其它各顶点的最短路径,Floyd算法用来计算任意一对顶点间的最短路径。
Dijkstra算法应用了贪心算法模式,其主要特点是每次迭代时选择的下一个顶点是标记点之外距离源点最近的顶点。由于Dijkstra算法主要计算从源点到其他所有点的最短路径,所以算法的效率较低。
Floyd算法应用了动态规划策略,其特点是不断对新加入的结点构成的路径与之前的路径做对比,看是否可以使之前找到的路径更优。
源码
文件一 ☛ ShortestPath.h
文件二 ☛ ShortestPath.c
文件三 ☛ ShortestPath-main.c (测试文档)
文件四、文件五 ☛ TestData_DN_M_DIJ.txt、TestData_DN_M_Floyd.txt(最短路径算法测试数据)
测试结果展示
-------------本文转载至osted @ 迷路的国王