数据结构系列之大话数据结构

第3章 线性表

3.2 线性表的定义

A B C…

B直接前驱元素: A

B直接后驱元素:C

3.6线性表的链式存储结构

3.6.2线性表链式存储结构定义(P57)

  • 结点(node)
    • 数据域:存储数据元素信息的域
    • 指针域:存储直接后继位置域

数据结构系列之大话数据结构_第1张图片

  • 开始结点: 是指链表中的第一个结点,它没有直接前驱
  • 头指针:链表中第一个结点的存储位置叫做头指针一个单链表可以由其头指针唯一确定,一般用其头指针来命名单链表
  • 头结点:是在链表的开始结点之前附加的一个结点

3.14双向链表

双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域

双向链表的插入和删除:

插入:
s -> prior = p;
s -> next = p -> next;
p -> next -> prior = s;
p -> next = s;

删除:
p -> prior -> next = p -> next;
p -> next -> prior = p ->prior;
free(p);

3.15 总结回顾

线性表

  • 顺序存储结构
  • 链式存储结构
    • 单链表
    • 静态链表
    • 循环链表
    • 双向链表

第4章 栈和队列

  • 栈是限定仅在表尾进行插入和删除操作的线性表
  • 队列是只允许在一端进行插入操作,而在另一段进行删除操作的线性表

4.2 栈的定义

  • 栈顶(top)
  • 栈底(bottom)
  • 空栈
  • 后进先出(LIFO结构),栈的两种操作–Push和Pop

栈的插入操作称为入栈,反之称为出栈.

数据结构系列之大话数据结构_第2张图片

4.3 栈的抽象数据类型

栈的一些基本操作:

ADT 栈(stack)
Data
	同线性表.元素具有相同的类型,相邻元素具有前驱和后继关系
Operation
	InitStack(*S)
	DestroyStack(*S)
	ClearStack(*S)
	StackEmpty(*S)判断堆栈是否为空,返回值是ture和false
	GetTop(*S)
	Push(*S, e)插入e值
	POp(*S, *e)删除栈顶元素并用e返回其值
	StackLength(S)

4.4 栈的顺序存储结构及实现(P93)

利用下标为0的数组一端作为栈的栈底

判断空栈的条件是top=-1

**销毁一个栈: **释放内存

**清空一个栈: **只改变地址

4.5两栈共享空间

两栈共享空间结构:使用数组同时实现两个栈,即栈1和栈2;栈1为空时,栈1的栈顶指针指向-1;栈2为空时,栈2 的栈顶指针指向MAXSIZE;栈1和栈2添加元素时,都会向数据中间靠拢,当栈1的指针+1等于栈2的指针的时候,栈满。数据结构系列之大话数据结构_第3张图片

数据结构系列之大话数据结构_第4张图片

数据结构系列之大话数据结构_第5张图片

数据结构系列之大话数据结构_第6张图片

数据结构系列之大话数据结构_第7张图片

4.6 栈的链式存储结构及实现

数据结构系列之大话数据结构_第8张图片

栈顶指针和单链表的头指针合二为一.

4.9 栈的应用–四则运算表达式求值

9+(3-1)*3+10/2 这是中缀表达式

9 3 1 - 3 * + 10 2 / + 这是后缀表达式

栈的四则运算最主要的就是让中缀表达式转换为后缀表达式,然后再进行一些其他的操作.

4.10 队列的定义

队列是只允许在一端进行插入操作,在另一端进行删除操作的线性表

  • 先进先出
  • 队尾: 允许插入的一端
  • 队头: 允许删除的一端

数据结构系列之大话数据结构_第9张图片

4.12 循环队列

如何判断队列是否已满?利用下面共指来判断
( r e a r − f r o n t + Q u e n e S i z e ) % Q u e n e S i z e = = f r o n t (rear-front+QueneSize) \% QueneSize == front (rearfront+QueneSize)%QueneSize==front

第5章 串

串是由零个或者多个字符组成的有限序列,又名叫字符串.

5.2 串的定义

串是由零个或者多个字符组成的有限序列,又名叫字符串

一般记作:
s = " a 1 a 2 a 3...... a n " s = "a1a2a3......an" s="a1a2a3......an"
所谓序列,是指相邻的字符串之间具有前驱和后继的关系

5.4 串的抽象数据类型

ADT 串 (String)

Data
	串中的元素仅由一个字符组成,相邻元素具有前驱和后继关系.
	
Operation
StrAssign (&T, chars)
	初始条件:chars是字符串常量。
	操作结果:生成一个其值等于chars的串T。
StrCopy (&T, S)
	初始条件:串S存在。
	操作结果:由串S复制得串T。
StrEmpty(S)
	初始条件:串S存在。
	操作结果:若S为空串,则返回TRUE,否则返回FALSE。 
StrCompare(S, T)
	初始条件:串S和T存在。
	操作结果:若S>T,则返回值>0;若S=T,则返回值=0;若S < T,则返回值 < 0。
StrLength(S)
	初始条件:串S存在。
	操作结果:返回S的元素个数,称为串的长度。
ClearString (&S)
	初始条件:串S存在。
	操作结果:将S清为空串。
Concat (&T, S1, S2)
	初始条件:串S1和S2存在。
	操作结果:用T返回由S1和S2联接而成的新串。
SubString(&Sub, S, pos, len)
	初始条件:串S存在,1≤pos≤StrLength(S)且0≤len≤StrLength(S)-pos+1
	操作结果:用Sub返回串S的第pos个字符长度为len的子串。
Index(S, T, pos)
	初始条件:串S和T存在,T是非空串,1≤pos≤StrLength(S)。
	操作结果:若主串S中存在和串T值相同的子串,则返回它在主串S中第pos个字符之后第一次出现的位置;否则函数值为0。
Replace (&S, T, V)
	初始条件:串S, T和V存在,T是非空串。
	操作结果:用V替换主串S中出现的所有与T相等的不重叠的子串。
StrInsert (&S, pos, T)
	初始条件:串S和T存在, 1≤pos≤StrLength(S)+1。
	操作结果:在串S的第pos个字符之前插入串T。
StrDelete (&S, pos, len)
	初始条件:串S存在, 1≤pos≤StrLength(S)-len+1。
	操作结果:从串S中删除第pos个字符起长度为len的子串。
DestroyString (&S)
	初始条件:串S存在。
	操作结果:串S被销毁。

endADT

5.6 KMP模式匹配算法

问题描述

给定一个主串S及一个模式串P,判断模式串是否为主串的子串;若是,返回匹配的第一个元素的位置(序号从1开始),否则返回0;如S=“abcd”,P=“bcd”,则返回2;S=“abcd”,P=“acb”,返回0。

KMP算法

https://blog.csdn.net/qq_37969433/article/details/82947411

朴素算法理解简单,但两个串都有依次遍历,时间复杂度为O(n*m),效率不高。由此有了KMP算法。
一般的,在一次匹配中,我们是不知道主串的内容的,而模式串是我们自己定义的。
朴素算法中,P的第j位失配,默认的把P串后移一位。
但在前一轮的比较中,我们已经知道了P的前(j-1)位与S中间对应的某(j-1)个元素已经匹配成功了。这就意味着,在一轮的尝试匹配中,我们get到了主串的部分内容,我们能否利用这些内容,让P多移几位(我认为这就是KMP算法最根本的东西),减少遍历的趟数呢?

第6章 树

6.2 树的定义

树是n个结点的有限集合.n=0时称为空树.在任意一棵非空树中:

  • 有且仅有一个特定的称为根(Root)的结点;
  • 当n>1时,其余结点可以分为m个互不相交的有限集T1,T2…Tm,其中每一个集合本身又是一课树,并且称为根的子树(SubTree)

数据结构系列之大话数据结构_第10张图片

  • 度: 结点拥有的子树的个数称为结点的度(Degree),度为0的结点称为叶节点或者终端结点.度不为0的结点称为非终端结点或者分支结点

数据结构系列之大话数据结构_第11张图片

  • 树的度是树的各个结点度的最大值
  • 深度或高度: 树中结点的最大层次称为树的深度或高度

数据结构系列之大话数据结构_第12张图片

  • 有序树和无序树
  • 森林是m棵互不相交的树的集合

6.4 树的存储结构(P155)

  • 双亲表示法
  • 孩子表示法
  • 孩子兄弟表示法

http://data.biancheng.net/view/30.html

6.4.1 双亲表示法

数据结构系列之大话数据结构_第13张图片

双亲表示法

6.4.2 孩子表示法

将树中的每个结点的孩子结点排列成一个线性表,用链表存储起来。对于含有 n 个结点的树来说,就会有 n 个单链表,将 n 个单链表的头指针存储在一个线性表中,这样的表示方法就是孩子表示法。

数据结构系列之大话数据结构_第14张图片

孩子表示法

使用孩子表示法存储的树结构,正好和双亲表示法相反,适用于查找某结点的孩子结点,不适用于查找其父结点。可以将两种表示方法合二为一,存储效果如图 :

数据结构系列之大话数据结构_第15张图片

孩子双亲表示法
#define TElemType int
#define Tree_Size 100
//孩子表示法
typedef struct CTNode{
    int child;//链表中每个结点存储的不是数据本身,而是数据在数组中存储的位置下标
    struct CTNode * next;
}*ChildPtr;
typedef struct {
    TElemType data;//结点的数据类型
    ChildPtr firstchild;//孩子链表的头指针
}CTBox;
typedef struct{
    CTBox nodes[Tree_Size];//存储结点的数组
    int n,r;//结点数量和树根的位置
}CTree;

6.4.3 孩子兄弟表示法

任意一棵树, 他的结点的第一个孩子如果存在就是唯一的, 他的右兄弟如果存在也是唯一的.因此我们设置两个指针,分别指向该结点的第一个孩子和此节点的右兄弟

img

data firstchild rightsib
数据域 孩子域 兄弟域

上下两个表格一个意思

数据结构系列之大话数据结构_第16张图片

这个表示方法就是把一个复杂的树变成了二叉树

6.5 二叉树的定义

https://www.jianshu.com/p/bf73c8d50dc2

二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树), 或者由一个根节点和两棵互不相交的,分别称为根节点的左子树和右子树的二叉树组成

数据结构系列之大话数据结构_第17张图片

二叉树

二叉树的特点:

  • 每个结点最多有两颗子树,所以二叉树中不存在度大于2的结点。
  • 左子树和右子树是有顺序的,次序不能任意颠倒。
  • 即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。

6.5.2特殊二叉树

斜树: 所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫右斜树。这两者统称为斜树。

数据结构系列之大话数据结构_第18张图片

左斜树

数据结构系列之大话数据结构_第19张图片

右斜树

满二叉树: 在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树

  • 叶子只能出现在最下一层。出现在其它层就不可能达成平衡
  • 非叶子结点的度一定是2
  • 在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多.并且叶子都处于同一层

数据结构系列之大话数据结构_第20张图片

满二叉树

完全二叉树: 对一颗具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树

数据结构系列之大话数据结构_第21张图片

完全二叉树

特点:

1)叶子结点只能出现在最下层和次下层。
2)最下层的叶子结点集中在树的左部。
3)倒数第二层若存在叶子结点,一定在右部连续位置。
4)如果结点度为1,则该结点只有左孩子,即没有右子树。
5)同样结点数目的二叉树,完全二叉树深度最小。
:满二叉树一定是完全二叉树,但反过来不一定成立。

6.5.3 其他重要二叉树

1.二叉排序树
二叉排序树,又叫二叉查找树,它或者是一棵空树;或者是具有以下性质的二叉树:

  1. 若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 它的所有结点的左右子树也分别为二叉排序树。
    数据结构系列之大话数据结构_第22张图片

2.平衡二叉树

(AVL)平衡二叉树是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。它是一种高度平衡的二叉排序树。意思是说,要么它是一棵空树,要么它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。

平衡二叉树是一种二叉排序树。也就是二叉排序树包含了平衡二叉排序树,其次它要满足后面的约束条件,就是每个结点的左子树和右子树的高度差不超过1
数据结构系列之大话数据结构_第23张图片

6.6 二叉树的性质

https://blog.csdn.net/why_still_confused/article/details/51532222

6.7 二叉树的存储结构

6.7.2 二叉链表

链表每个结点包含一个数据域和两个指针域:

mark

其中data是数据域,lchild和rchild都是指针域,分别指向左孩子和右孩子。

数据结构系列之大话数据结构_第24张图片

/*二叉树的二叉链表结点结构定义*/
typedef struct BiNode
{
    char data;    /*结点数据*/
    struct BiNode *lchild, *rchild; /*左右孩子指针*/
}BiNode,*BiTree;

6.8 遍历二叉树

二叉树的遍历是指从根节点出发,按照某种次序依次访问二叉树中的所有结点, 使得每个结点被访问一次且仅被访问一次。

https://blog.csdn.net/gatieme/article/details/51163010(二叉树建立和遍历的C++代码实现)

1. 前序遍历

根结点 —> 左子树 —> 右子树

2. 中序遍历

左子树 —> 根节点 —> 右子树

3. 后续遍历

左子树 —> 右子树—> 根节点

4. 层序遍历

从根节点开始访问,从上而下逐层遍历,在同一层中,按照从左到右的顺序对结点逐个访问

6.10 线索二叉树

为什么存在线索二叉树:

二叉树是一种非线性结构,遍历二叉树几乎都是通过递归或者用栈辅助实现非递归的遍历。用二叉树作为存储结构时,取到一个节点,只能获取节点的左孩子和右孩子,不能直接得到节点的任一遍历序列的前驱或者后继。为了保存这种在遍历中需要的信息,我们利用二叉树中指向左右子树的空指针来存放节点的前驱和后继信息

数据结构系列之大话数据结构_第25张图片

6.10.1 线索二叉树原理

n个节点的二叉树中含有n+1个空指针域。利用二叉树中的空指针域来存放在某种遍历次序下的前驱和后继,这种指针叫“线索”。这种加上了线索的二叉树称为线索二叉树。

img

线索二叉树节点
  • ltag为0时指向左孩子,为1时指向该节点的前驱
  • rtag为0时指向右孩子, 为1时指向该节点的后继

数据结构系列之大话数据结构_第26张图片

6.11 树,森林与二叉树的转换

https://blog.csdn.net/linraise/article/details/11745559

1. 将树转换成二叉树:
(1)加线。就是在所有兄弟结点之间加一条连线;
(2)抹线。就是对树中的每个结点,只保留他与第一个孩子结点之间的连线,删除它与其它孩子结点之间的连线;
(3)旋转。就是以树的根结点为轴心,将整棵树顺时针旋转一定角度,使之结构层次分明。

img

2. 森林转换为二叉树

森林是由若干棵树组成,可以将森林中的每棵树的根结点看作是兄弟,由于每棵树都可以转换为二叉树,所以森林也可以转换为二叉树。

将森林转换为二叉树的步骤是:
(1)先把每棵树转换为二叉树;
(2)第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子结点,用线连接起来。当所有的二叉树连接起来后得到的二叉树就是由森林转换得到的二叉树。
img

3. 二叉树转化为森林

二叉树转换为树是树转换为二叉树的逆过程,其步骤是:
(1)若某结点的左孩子结点存在,将左孩子结点的右孩子结点、右孩子结点的右孩子结点……都作为该结点的孩子结点,将该结点与这些右孩子结点用线连接起来;
(2)删除原二叉树中所有结点与其右孩子结点的连线;
(3)整理(1)和(2)两步得到的树,使之结构层次分明。
img

4. 二叉树转换为森林

二叉树转换为森林比较简单,其步骤如下:
(1)先把每个结点与右孩子结点的连线删除,得到分离的二叉树;
(2)把分离后的每棵二叉树转换为树;
(3)整理第(2)步得到的树,使之规范,这样得到森林。

根据树与二叉树的转换关系以及二叉树的遍历定义可以推知,树的先序遍历与其转换的相应的二叉树的先序遍历的结果序列相同;树的后序遍历与其转换的二叉树的中序遍历的结果序列相同;树的层序遍历与其转换的二叉树的后序遍历的结果序列相同。由森林与二叉树的转换关系以及森林与二叉树的遍历定义可知,森林的先序遍历和中序遍历与所转换得到的二叉树的先序遍历和中序遍历的结果序列相同。

6.12 哈夫曼树及其应用

6.12.2 哈夫曼树定义与原理(P203)

构建哈夫曼树的步骤:

原始节点

构建Huffman树的步骤

哈夫曼编码:

Huffman编码

第7章 图

https://baozouai.com/2019/03/08/%E5%A4%A7%E8%AF%9D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-%E7%AC%AC%E4%B8%83%E7%AB%A0%20%20%E5%9B%BE/

图(Graph)是由顶点的有穷非空集合和顶点之间的边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。

7.2 图的定义

  • 无向图:若顶点Vi到Vj之间的边没有方向,则称这条边为无向边(Edge),用序偶对(Vi,Vj)表示。如果图的任意两个顶点之间的边都是无向边,则称该图是无向图。

    数据结构系列之大话数据结构_第27张图片

    上述无向图G1来说,G1=(V1, {E1}),其中顶点集合V1={A,B,C,D};边集合E1={(A,B),(B,C),(C,D),(D,A),(A,C)};

  • 有向图:若从顶点Vi到Vj的边是有方向的,则成这条边为有向边,也称为弧(Arc)。用有序对(Vi,Vj)标示,Vi称为弧尾,Vj称为弧头。如果任意两条边之间都是有向的,则称该图为有向图。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aEpVicYr-1573180530985)(https://baozou.gitbooks.io/-data-structure/content/assets/152import.png)]

    有向图G2中,G2=(V2,{E2}),顶点集合(A,B,C,D),弧集合E2={,,,}.

  • 无向完全图:在一个无向图中,任意两个顶点之间都存在边,则称该图为无向完全图。含有n个顶点的无向完全图有 n ∗ ( n + 1 ) / 2 n*(n+1)/2 n(n+1)/2 条边

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YzB97B8u-1573180530986)(https://baozou.gitbooks.io/-data-structure/content/assets/155import.png)]

  • 有向完全图:在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图。含有n个顶点的有向完全图有n×(n−1)条边

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8L4L0N2g-1573180530986)(https://baozou.gitbooks.io/-data-structure/content/assets/157import.png)]

  • 有很少条边或弧的图称为稀疏图,反之称为稠密图。稀疏和稠密是模糊的概念,是相对而言的
  • 有些图的边或弧具有与它相关的数字,这种与图的边或弧相关的数叫做权(Weight)。这些权可以表示从一个顶点到另一个顶点的距离或耗费。这种带权的图通常称为网(Network)
  • 假设有两个图G*=(V,{E})G*′=(V′,{E′}),如果V′⊆VE′⊆E*,则称G′为G的子图(Sub-graph)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOuSOE7Z-1573180530987)(https://baozou.gitbooks.io/-data-structure/content/assets/160import.png)]

7.2.2 图的顶点和边的关系

7.4 图的存储结构

7.4.1 邻接矩阵

图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二位数组(称为邻接矩阵)存储图中的边或弧的信息。

设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为:

img

  • 无向图的邻接矩阵

img

  • 有向图的邻接矩阵

img

  • 网图的邻接表

    设图G是网图,有n个顶点,则邻接矩阵是一个n*n的方阵,定义为:

img

img

7.4.2 邻接表

数组与邻接表相结合的存储方法称为邻接表

  • 无相图的邻接表

    img

  • 有向图的邻接表

    img

  • 网图(带权值)的邻接表

    img

7.4.3 十字链表

十字链表 = 邻接表 + 逆邻接表

7.4.4 邻接多重表

针对无向图(存储空间压缩时用)

7.4.5 边集数组

边集数组是由两个一维数组构成。一个是存储顶点的信息;另一个是存储边的信息,这个边数组每个数据元素由一条边的起点下标(begin)、终点下标(end)和权(weight)组成

begin是存储起点下标,end是存储终点下标,weight是存储权值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zrNe533V-1573180530987)(https://baozou.gitbooks.io/-data-structure/content/assets/import.png23)]

边集数组关注的是边的集合,在边集数组中要查找一个顶点的度需要扫描整个边数组,效率并不高。因此它更适合对边依次进行处理的操作,而不适合对顶点相关的操作

7.5 图的遍历

定义:从图的某一顶点出发访遍图中的其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历

7.5.1 深度优先遍历(P239)

从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到,以上说的只是连通图,对于非连通图,只需要对它的连通分量分别进行深度优先遍历,即在先前一个顶点进行一次深度优先遍历后,若图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作为起始点,重复上述过程,直至图中所有顶点都被访问到位置

7.5.2 广度优先算法(P242)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fDuS4knY-1573180530987)(https://baozou.gitbooks.io/-data-structure/content/assets/import.png24)]

图的深度优先遍历和广度优先遍历算法在时间复杂度上一样,不同之处仅在于对顶点的访问次序不同深度优先算法更适合目标比较明确的。以找到目标为主要目的的情况,而广度优先更适合在不断扩大遍历范围时找到相对最优解的情况

7.6 最小生成树(B站上的王卓老师讲原理讲的比较好)

生成树的特点:

  1. 生成树的顶点个数和图的顶点个数相同
  2. 生成数是图的极小联通子图,去掉一条边则非联通
  3. 一个有n个顶点的联通图的生成树有n-1条边
  4. 在生成树中再加一条边必然形成回路
  5. 生成树中任意两个顶点之间的路径是唯一的

最小成本,就是n个顶点,用n-1条边把一个连通图连接起来,并且使得权值的和最小

最小生成树:把构造联通网的最小代价生成树称为最小生成树。最小生成树不唯一,但是最小生成树的权值和一定唯一。

7.6.1 普利姆(prim)算法

https://www.bilibili.com/video/av36885391/?spm_id_from=333.788.videocard.0(B站)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DQVfGhpK-1573180530987)(https://baozou.gitbooks.io/-data-structure/content/assets/import.png25)]

算法实现(C++)
#include 
#define MAXINT 6

using namespace std;

//声明一个二维数组,C[i][j]存储的是点i到点j的边的权值,如果不可达,则用1000表示
//借此二维数组来表示一个连通带权图
int c[MAXINT][MAXINT]={{1000,6,1,5,1000,1000},{6,1000,5,1000,3,1000},{1,5,1000,5,6,4},{5,1000,5,1000,1000,2},{1000,3,6,1000,1000,6},{1000,1000,4,2,6,1000}};
void Prim(int n)
{
    int lowcost[MAXINT];//存储S中到达对应的其它各点的最小权值分别是多少
    int closest[MAXINT];//closest[]数组保存的是未在S中的点所到达S中包含的最近的点是哪一个,如:closest[i]=1表示i最靠近的S中的点是1
    bool s[MAXINT];//bool型变量的S数组表示i是否已经包括在S中
    int i,k;
    s[0]=true;//从第一个结点开始寻找,扩展
    for(i=1;i<=n;i++)//简单初始化
    {
        lowcost[i]=c[0][i];
        closest[i]=0;//现在所有的点对应的已经在S中的最近的点是1
        s[i]=false;
    }
    cout<<"0->";
    for(i=0;i";
        s[j]=true;//添加点j到集合S中
        for(k=1;k<=n;k++)//因为新加入了j点,所以要查找新加入的j点到未在S中的点K中的权值是不是可以因此更小
        {
            if((c[j][k]>c[i][j];
            cout<

7.6.2 克鲁斯卡尔(Kruskal)算法

https://www.bilibili.com/video/av36885495/?spm_id_from=333.788.videocard.0(B站)

本质就是一种贪心算法

算法思想:

  • 设联通网N=(V,E)令最小生成树初始状态为只有n个顶点而无边的非联通图T=(V,{}),每个顶点自成一个连通分量.
  • 在E中选取代价最小的边,若该边依附的顶点落在T中的不同联通分量上(即:不能形成环),则将此边加入到T中,否则,舍去此边,选取一条代价最小的边.
  • 以此类推,直到T中所有顶点都在同一个联通分量上为止.

两种算法的比较


算法名 Prime算法 Kruskal算法
算法思想 选择点 选择边
时间复杂度 O(n^2) O(eloge)
适应范围 稠密图 稀疏图

7.7 最短路径

最短路径:指两个顶点之间经过边上的权值之和最少的路径,并称第一个顶点是源点, 最后一个顶点是终点.

要解决的两类问题:

  • 两点之间的最短路径(单源最短路径(Dijkstra算法))
  • 某源点到其他各个点的最短路径(所有顶点之间的最短路径(Floyd算法))

7.7.1 Dijkstra算法

单源最短路径

https://www.bilibili.com/video/av36886088/?spm_id_from=333.788.videocard.0(B站)

按路径长度递增次序产生最短路径

7.7.2 Floyd算法

https://www.bilibili.com/video/av36886554/?spm_id_from=333.788.videocard.0(B站)

所有顶点之间的最短路径

算法思想:

  • 逐个顶点试探
  • 从Vi到Vj的所有可能存在的路径中
  • 选出一条长度最短的路径

7.8 拓扑排序

https://www.bilibili.com/video/av36886991/?spm_id_from=333.788.videocard.0(B站)

1.AOV

用一个有向图表示一个工程的各子工程及其相互制约的关系,其中以顶点表示活动,弧表示活动之间的优先制约关系,称这种有向图为顶点表示活动的网,简称AOV网.

2.AOE

用一个有向图表示一个工程的各子工程及其相互制约的关系,以弧表示活动,以顶点表示活动的开始或结束时间,称这种有向图为边表示活动的网,简称AOE网.

3.AOV网的特点:

  • 若从i到j有一条有向路径,则i是j的前驱;j是i的后继
  • 是网中的有向边, 则i是j的直接前驱, j是i的直接后继
  • AOV网中不允许有回路, 因为如果有回路存在,表明某项活动是以自己为先决条件,显然这是荒谬的.
  • 如何判断AOV网中是否存在回路?

数据结构系列之大话数据结构_第28张图片

4.什么是拓扑排序?:

在AOV网没有回路的前提下,我们将全部活动排列成一个线性序列,使得若AOV网中有弧存在, 则在这个序列中, i一定排在j的前面, 具有这种性质的线性序列称为拓扑有序序列, 相应的拓扑有序排序的算法称为拓扑排序.

5.拓扑排序的方法

数据结构系列之大话数据结构_第29张图片

一个拓扑序列并不唯一

上述拓扑序列也可以是C9, C10, C11, C6, C1, C12, C4, C2, C3, C5, C7, C8

6.拓扑排序的一个重要应用

检测AOV网中是否存在环

对有向图构造其顶点的拓扑有序序列, 若网中所有顶点都在他的拓扑有序序列中,则该AOV网必定不存在环.

7.9 关键路径

https://www.bilibili.com/video/av36907591/?spm_id_from=trigger_reload(B站)

1.AOE

用一个有向图表示一个工程的各子工程及其相互制约的关系,以弧表示活动,以顶点表示活动的开始或结束时间,称这种有向图为边表示活动的网,简称AOE网.

2.关键路径

把工程计划表示为边表示的活动的网络, 即AOE网, 用顶点表示事件, 弧表示活动, 弧的权表示活动持续时间

事件表示在他之前的活动已经完成, 在他之后的活动可以开始
数据结构系列之大话数据结构_第30张图片
数据结构系列之大话数据结构_第31张图片
数据结构系列之大话数据结构_第32张图片数据结构系列之大话数据结构_第33张图片
数据结构系列之大话数据结构_第34张图片
数据结构系列之大话数据结构_第35张图片
数据结构系列之大话数据结构_第36张图片

你可能感兴趣的:(数据结构)