数据结构与算法

数据结构与算法




1.结点的度



2.树的深度

树中结点的最大层次数称为树的深度或高度

二叉树

1.定义

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

2.性质

1)第i层最多有2^(i-1) 个结点 (i>=1)
2)二叉树中如果深度为k,那么最多有2k-1个结点。(k>=1)
3)n0=n1+1 n0:度数为0的结点 n2:度数为2的结点

3.特点

由二叉树定义以及图示分析得出二叉树有以下特点:
1)每个结点最多有两颗子树,所以二叉树中不存在度大于2的结点。
2)左子树和右子树是有顺序的,次序不能任意颠倒。
3)即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。

链式二叉树


满二叉树

1.定义:

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

2.特点

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

完全二叉树

1.定义

完全二叉树是由满二叉树而引出来的,若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数(即1~h-1层为一个满二叉树),第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

顺序存储一般适用于完全二叉树,不浪费内存

堆一般都是用完全二叉树来实现的。

2.特点

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

斜树

所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫右斜



二叉链表

顺序存储不能满足二叉树的存储需求,那么考虑采用链式存储。由二叉树定义可知,二叉树的每个结点最多有两个孩子。因此,可以将结点数据结构定义为一个数据和两个指针域

typedef struct BiTNode{
    TElemType data;//数据
    struct BiTNode *lchild, *rchild;//左右孩子指针
} BiTNode, *BiTree;

树的遍历

  • 1.广度优先遍历(层次遍历)

  • 2.深度优先遍历:前中后 前中后是相对于根节点来说


二叉搜索树(BST,二叉查找树,二叉排序树)

1.定义

  二叉搜索树又称二叉查找树,亦称为二叉排序树。设x为二叉查找树中的一个节点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个节点,则key[y] <= key[x];如果y是x的右子树的一个节点,则key[y] >= key[x]

2.性质

  (1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  (2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  (3)左、右子树也分别为二叉搜索树

3.查找

查找流程:
  (1)如果树是空的,则查找结束,无匹配。
  (2)如果被查找的值和节点的值相等,查找成功。
  (3)如果被查找的值小于节点的值,递归查找左子树,
  (4)如果被查找的值大于节点的值,递归查找右子树,

4.删除

1.待删除的结点仅有一颗子树:

只需要将其唯一的子树接到其原父亲结点处,即原本指向被删除结点的指针改为指向被删除结点的子树

2.待删除的结点有两颗子树:

两种方法:

1)使待删除结点的左子树代替被删除的结点,将被删除结点的右子树放置于被删除结点的左子树的最右边。
2)用待删除结点的直接前驱或直接后继(指的是遍历顺序的)代替被删除的结点,然后再删除用以替代的原节点。
下面主要说明第一种方法:

可以看到,删除前中序遍历结果为:1345689,而删除后中序遍历结果为:145689,即元素间的顺序没有被改变。

平衡二叉查找树(AVL)

查找复杂度控制在O(logn)
3.1

1.定义

  二叉搜索树一定程度上可以提高搜索效率,但是当原序列有序,例如序列A = {1,2,3,4,5,6},构造二叉搜索树如上图。依据此序列构造的二叉搜索树为右斜树,同时二叉树退化成单链表,搜索效率降低为O(n)。


  二叉搜索树的查找效率取决于树的高度,因此保持树的高度最小,即可保证树的查找效率,改为下图
  
  可以看出当节点数目一定,保持树的左右两端保持平衡,树的查找效率最高。这种左右子树的高度相差不超过1的树为平衡二叉树。

  

2.平衡因子

  定义:某节点的左子树与右子树的高度(深度)差即为该节点的平衡因子(BF,Balance Factor),平衡二叉树中不存在平衡因子大于1的节点。在一棵平衡二叉树中,节点的平衡因子只能取-1、1或者0。


3.左旋和右旋

!!!理解:左旋就是将新根节点的左子树剪下,然后接到老根节点的右子树
右旋就是将新根节点的右子树剪下来,接到老根节点的左子树

左旋:

1)节点的右孩子替代此节点位置
  (2)右孩子的左子树变为该节点的右子树
  (3)节点本身变为右孩子的左子树



右旋(同理)

  右旋操作与左旋类似,操作流程为:
  (1)节点的左孩子代表此节点
  (2)节点的左孩子的右子树变为节点的左子树
  (3)将此节点作为左孩子节点的右子树。

  
多次旋转情况:同理而已

step 1:对右子树执行右旋操作

step 2:对二叉树执行左旋操作



红黑树(Red-Black tree)




红黑树(RBT)的定义:它或者是一颗空树,或者是具有一下性质的二叉查找树:

1.节点非红即黑。
2.根节点是黑色。
3.所有NULL结点称为叶子节点,且认为颜色为黑。(如图标有NIL的为叶子节点)
4.所有红节点的子节点都为黑色。(即红色节点不能连续)
5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。

所有性质1-5合起来约束了该树的平衡性能--即该树上的最长路径不可能会大于2倍最短路径
原因:第1条该树上的节点非红即黑,由于第4条该树上不允许存在两个连续的红节点,那么对于从一个节点到其叶子节点的一条最长的路径一定是红黑交错的,那么最短路径一定是纯黑色的节点;而又第5条从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点,这么来说最长路径上的黑节点的数目和最短路径上的黑节点的数目相等!而又第2条根结点为黑、第3条叶子节点是黑,那么可知:最长路径<=2*最短路径。


 平衡的二叉查找树 ,时间复杂度O(log(n)),任何插入或删除能在三次旋转以内平衡
在树的结构发生改变时(插入或者删除操作),往往会破坏上述条件,需要通过调整使得查找树重新满足红黑树的条件。


插入(如果不满足平衡树就旋转,同时还要满足红色结点不能连续,按照这个来操作得到最终形态!)
红黑树旋转的关键逻辑是:确保任何一个节点的左右子树的高度差不会超过二者中较低那个的一倍

2.删除

不深究,就遵从上面的五条规则就行变化,
详解看https://www.cnblogs.com/panda28/p/11132462.html,
https://developer.51cto.com/art/201908/601688.htm,
https://segmentfault.com/a/1190000021366480?utm_source=tag-newest



3.优缺点

二叉树的遍历

递归思路很简单 不写了

非递归思路(用栈实现):

1.前序遍历:

1.先将根节点入栈
2.访问栈顶元素 ,即出栈
3.有右孩子,将右孩子入栈
4.如果根节点有左孩子,将左孩子入栈
5.当栈不为空时,循环上面2,3,4

2.中序遍历

对于每个结点都是先遍历了其左子树,所以当访问到该节点时候,只需要访问本节点和右子树

1.先将根节点入栈
2.如果根节点有左孩子,就将左孩子入栈,一直找下去,直到没有左孩子
3.将栈顶元素出栈,查看它是否有右孩子,如果有,就将右结点入栈
4.重复2,3

3.后序遍历

1.根节点入栈
2.将根节点的左子树入栈,直到叶子结点,出栈
3.查看该叶子结点的父节点是否有右结点未访问过,有的话右节点入栈
4.当一个结点的左右结点是否都已经被访问过,是的话出栈

B树 B+树(B-Tree/Balance-tree)

MySQL数据库中索引的数据结构是什么?(B树和B+树的区别)

B树(又叫平衡多路查找树)

B树的性质(一颗M阶B树的特性如下)


1、定义任意非叶子结点最多只有M个儿子,且M>2; 
2、根结点的儿子数为[2, M]; 
3、除根结点以外的非叶子结点的儿子数为[M/2, M]; 
4、每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字) 
5、非叶子结点的关键字个数=指向儿子的指针个数-1; 
6、非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1]; 
7、非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树; 
8、所有叶子结点位于同一层;

B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点;

B-树的特性:


1.关键字集合分布在整颗树中;

2.任何一个关键字出现且只出现在一个结点中;

3.搜索有可能在非叶子结点结束;

4.其搜索性能等价于在关键字全集内做一次二分查找;

B+树

(1)简介


B+树是应文件系统所需而产生的一种B树的变形树(文件的目录一级一级索引,只有最底层的叶子节点(文件)保存数据)非叶
子节点只保存索引,不保存实际的数据,数据都保存在叶子节点中,这不就是文件系统文件的查找吗?

我们就举个文件查找的例子:有3个文件夹a、b、c, a包含b,b包含c,一个文件yang.c,a、b、c就是索引(存储在非叶子
节点), a、b、c只是要找到的yang.c的key,而实际的数据yang.c存储在叶子节点上。

所有的非叶子节点都可以看成索引部分!

(2)B+树的性质(下面提到的都是和B树不相同的性质)


1、非叶子节点的子树指针与关键字个数相同; 
2、非叶子节点的子树指针p[i],指向关键字值属于[k[i],k[i+1]]的子树.(B树是开区间,也就是说B树不允许关键字重
复,B+树允许重复); 
3、为所有叶子节点增加一个链指针; 
4、所有关键字都在叶子节点出现(稠密索引). (且链表中的关键字恰好是有序的); 
5、非叶子节点相当于是叶子节点的索引(稀疏索引),叶子节点相当于是存储(关键字)数据的数据层; 
6、更适合于文件系统;

非叶子节点(比如5,28,65)只是一个key(索引),实际的数据存在叶子节点上(5,8,9)才是真正的数据或指向真实数据的指针。

应用  

1、B和B+树主要用在文件系统以及数据库做索引,比如MySQL;(MySQL使用B+树)

B/B+树性能分析
n个节点的平衡二叉树的高度为H(即logn),而n个节点的B/B+树的高度为logt((n+1)/2)+1; 
若要作为内存中的查找表,B树却不一定比平衡二叉树好,尤其当m较大时更是如此。因为查找操作CPU的时间在B-树上
O(mlogtn)=O(lgn(m/lgt)),而m/lgt>1;所以m较大时O(mlogtn)比平衡二叉树的操作时间大得多。因此在内存中使用B
树必须取较小的m。(通常取最小值m=3,此时B-树中每个内部结点可以有2或3个孩子,这种3阶的B-树称为2-3树)。

为什么说B+树比B树更适合数据库索引?
1、 B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所
有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就
越多,相对IO读写次数就降低了。

2、B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键
字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

3、由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结
点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通
常B+树用于数据库索引。

PS:我在知乎上看到有人是这样说的,我感觉说的也挺有道理的:

他们认为数据库索引采用B+树的主要原因是:B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。

总结:

数据库使用B+树肯定是为了提升查找效率。

但是具体如何提升查找效率呢?

查找数据,最简单的方式是顺序查找。但是对于几十万上百万,甚至上亿的数据库查询就很慢了。

所以要对查找的方式进行优化,熟悉的二分查找,二叉树可以把速度提升到O(log(n,2)),查询的瓶颈在于树的深度,最坏的
情况要查找到二叉树的最深层,由于,每查找深一层,就要访问更深一层的索引文件。在多达数G的索引文件中,这将是很大的
开销。所以,尽量把数据结构设计的更为‘矮胖’一点就可以减少访问的层数。在众多的解决方案中,B-/B+树很好的适合。B-
树定义具体可以查阅,简而言之就是中间节点可以多余两个子节点,而且中间的元素可以是一个域。相比B-树,B+树的父节点
也必须存在于子节点中,是其中最大或者最小元素,B+树的节点只存储索引key值,具体信息的地址存在于叶子节点的地址中。
这就使以页为单位的索引中可以存放更多的节点。减少更多的I/O支出。因此,B+树成为了数据库比较优秀的数据结构,MySQL
中MyIsAM和InnoDB都是采用的B+树结构。不同的是前者是非聚集索引,后者主键是聚集索引,所谓聚集索引是物理地址连续
存放的索引,在取区间的时候,查找速度非常快,但同样的,插入的速度也会受到影响而降低。聚集索引的物理位置使用链表来
进行存储。

 

参考链接:
https://www.cnblogs.com/linliquan/p/11364428.html
https://www.2cto.com/net/201808/773535.html

https://www.cnblogs.com/tiancai/p/9024351.html



dfs(深度优先遍历)

bfs

看代码理解更实际

十大排序算法

图片名词解释:
n: 数据规模
k: “桶”的个数
In-place: 占用常数内存,不占用额外内存
Out-place: 占用额外内存


1.冒泡排序(Bubble Sort)


2.选择排序
selectsort


工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕
个人理解(小到大):首先默认第一个最小,然后和后面的比较,如果遇到小的就标记为最小,用这个最小值继续和后面的比较,然后把最小值放到最前面,依次循环


3.快速排序
quickSort


4.归并排序

mergeSort


5.插入排序
insertSort


6.希尔排序
shellSort


7.计数排序
countingSort


8.堆排序

heapSort


9.桶排序
bucketSort


10.基数排序
radixSort

posted @ 2020-05-14 23:01  lanvce  阅读(225)  评论(0)    收藏  举报
//小火箭