一、线性表查找算法
1.顺序查找
•顺序查找无视待查表的有序与否。
2.折半查找
•折半查找只能用于顺序存储的线性表。
•表的各个元素在判定树中所在的树高就是其比较次数。对于失败情况所在的叶节点,其比较次数为其所在树高-1。判定树高度计算式与完全二叉树一致——里上外下。
•求ASL:画判定树,然后利用ASL定义计算。
•画判定树:别像个乌龟一样脑海中模拟一遍折半查找才画完树,用简便方法——逐个往树上添加结点,若是mid = (l + r)/2,要求使判定树中的每个子树的左子树结点数=右子树结点数,或左子树结点数+1=右子树结点数(因为当l与r之间有奇数个表项,mid算出来就是中间那个,其左右子树结点相等;当l与r之间有偶数个表项,mid的左子树就会比右子树少一个结点)。最后画完时,为树中原有的每个空链域添加一个叶结点表示失败情况。
3.分块查找/索引顺序查找
•求ASL:
-通过定义求:每一个表项的查找次数 = 其所在块在索引表的位置 + 其在块中的位置。通过定义求和所有块的所有表项即可(很麻烦)。
-简便方法:ASL = 索引表的ASL + 单个块的ASL。索引表的ASL和单个块的ASL由定义求出。
4.散列表(哈希表)
•求ASL:
•开放寻址解决冲突的散列表的相邻地址不一定存储同义词,是交错排列的。
•链地址法(拉链法)不可能造成聚集现象。(聚集——多个不同初地址关键字抢夺同一个地址进行插入)
•散列表的ASL或时间复杂度与装填因子直接相关,与不直接依赖于关键字数或散列表容量。
二、树形查找
1.二叉排序树(BST, Binary Search Tree)
1.1 查找:
——循环实现:使用游离指针T指向根结点,开始循环,当游离指针指向的结点为待找结点(找到)或游离指针指向NULL(没有该结点)时退出循环,否则让T指向该结点的左右孩子结点(待查找值小于T时让T指向T的左孩子,当待查找值大于T时让T指向T的右孩子)。
——递归实现:递归函数是递归结束函数的条件仍然是找到或当前传入的结点已经为NULL,此时返回T。递归函数是递归中间函数的条件相反,即传入的结点不为空,但又不与待找结点相同,那就分小于与大于,待找结点小于当前传入函数的结点时,返回递归调用左子树的结果,反之递归调用右子树的结果。
1.2 插入(递归实现):递归函数是递归结束函数的条件是找到相同的或当前传入的结点为NULL,相同则返回错误,为NULL则修改该结点为malloc新建结点的返回值。递归函数是递归中间函数的条件相反,即传入的结点不为空,那就分小于,大于与等于,待找结点小于当前传入函数的结点时,返回递归调用左子树的结果,反之则递归调用右子树的结果。
1.3 构造:从头遍历关键字序列,对每一个序列调用插入操作。
1.4 删除:查找该结点在树中的位置。
——若该结点是叶节点,则直接删除。
——若该结点只有左子树或只有右子树,则直接让其子树的根节点代替它。
——若该结点既有左子树又有右子树,则需要让其直接前驱或直接后继复制给它。找直接前驱:中序遍历其左子树,最后遍历到的即其直接前驱。找直接后继:中序遍历其右子树,最先遍历到的即其直接后继。然后删除其直接前驱或直接后继的所处的结点(该结点肯定是叶节点或只有左子树/右子树)。
•中序遍历即可得到一个二叉排序树的有序序列。同一个序列的所有二叉排序树中序序列相同,且这些二叉树的中序序列就是该序列。
•卡特兰数 = n个结点构造的不同二叉排序树的个数 = 中序确定,不同先序序列的个数。计算式在王道书p301。
2.平衡二叉树(AVL树,取名为开发者名字首字母)
•平衡二叉树用于二叉排序树,使得查找时间为O(logn),更快。
2.1 插入与删除:
(1)直接插入,删除。
(2)从插入/删除的点向上找最小不平衡树的根结点r。
(3)找到该根结点r的高度最高的儿子结点x,结点x高度最高的儿子结点y。
(4)分以下四种情况:
a.x,y都是左孩子——r相对x右(下)旋
b.x,y都是右孩子——r相对x左(下)旋
c.x左y右——x相对y左(下)旋,然后r相对y右(下)旋
a.x右y左——x相对y右(下)旋,然后r相对y左(下)旋
•ab情况是x成为最终根结点,cd情况是y成为最终根结点。
(5)若是删除操作,则需要继续向上找有没有不平衡的结点。
•因为插入操作的插入操作本身及其后的四种平衡处理最终不会影响最小不平衡树的树高,而删除操作的删除操作本身及其后的四种平衡处理可能会使最小不平衡树的树高 - 1导致其祖先结点不平衡。
2.2 结点数分析
•平衡二叉树达到树高h的最少结点数:n(h) = n(h-2) + n(h-1) + 1,即树高为h所需的最少结点为将树高为h-1与树高为h-2的结点用一个根结点相连即可。
•平衡二叉树不超过树高h的最多结点数:满二叉树。
•平衡二叉树给定结点数的树高最低为里上外下,但可以更高。不同于完全二叉树给定结点数它就是一定是里上外下的树高。但是若从空树开始,插入序列是升序的,则产生的平衡二叉树的高度就是结点数对应的完全二叉树高度。
•平衡二叉树的一个结点的两个孩子平衡因子都为0,该结点平衡因子不一定为0。
3.红黑树(RBT)
3.1 原则:左根右,不红红,根叶黑,黑路同。
3.2 树形/时间复杂度分析:
结点黑高——结点到任意叶节点的路径上的黑结点数(不计该结点)。
树的黑高——根结点到任意叶节点的路径上的黑结点数(不计根结点)。
•树高(不算叶节点)最少为树黑高(全黑),最多为树黑高的两倍(黑红相间)——这是红黑树较平衡二叉树放宽松的地方。
•一个红黑树的黑高为bh,则该二叉树结点最少的情况为该树是高度为bh的满二叉树且全为黑结点,最多为该满二叉树两两黑结点之间添加红结点成为高度为2bh的满二叉树。
•n个结点可以生成的红黑树的最大高度为2log(n+1) (记住即可)(尝试解释:对于一颗全黑满树,挑一条路径,两两黑结点之间插入红结点以增加树高,最后得到的树就是达到该树高对结点量需求最少的树。此时树高为h,黑结点数为2^(h/2)-1,红结点数为h,该结点需求最少的树拥有2^(h/2)-1+h个结点。)
•AVL树与红黑树的查找,删除,插入的时间复杂度都为O(logn)。
3.3 插入:(直接插入+维护不红红条件)
a.插入结点。若插入结点将作为根结点,设为黑色,结束,否则设为红色(维护“黑路同”条件)。
b.看父结点是否是黑色,黑色表明不与“不红红”冲突,结束,否则进行接下来的维护操作。
c.看叔结点的颜色决定维护操作:
c.1 叔结点为红色:叔父爷变色,将爷视为插入结点重复a步骤。
c.2 叔结点为黑色或不存在:旋转+染色。旋转同AVL树,将其爷节点视为“最小不平衡子树根结点”r,将其父结点视为r的“最高子树”。染色时LL与RR旋,则父爷换色,LR与RL旋,则爷与插入结点换色。
•红黑树的任意子树不一定为红黑树,因为不一定满足根结点必黑的条件。
•红黑树的删除操作的旋转次数可能超过两次,插入操作最多两次旋转。
4.B树
4.1 树形/时间复杂度分析
给定关键字数n,树的阶数m。
•为了树尽量矮,规定每个非根结点至少有⌈m/2⌉个子树,至少包含⌈m/2⌉-1个关键字。根结点若不为叶节点至少有一个关键字即两个子树。
•树的高度最大时,根结点仅包含一个关键字,每个非根结点仅包含(⌈m/2⌉-1)个关键字,射出⌈m/2⌉条边(即充分伸高),关键字数为n = f(h) = 1+(⌈m/2⌉-1)(2+2⌈m/2⌉+2⌈m/2⌉^2+2⌈m/2⌉^3...+2⌈m/2⌉^(h-2))。那么可以求得不同h下所需要的最少关键字。题目给你关键字数numkey,仅需列出不同h需要的最少关键字数,当列出f(h0)<numkey而f(h0+1)>numkey时,numkey才够组成h0高度的B树,h0就是给定关键字下最高树高。
•树的高度最小时,每个结点包括根结点都有(m-1)个关键字,射出m条边(即充分长胖),关键字数n = f(h) = (m-1)(1+m+m^2+m^(h-1)),那么可以求得不同h下可容纳的最多关键字。题目给你关键字数numkey,仅需列出不同h支持的最多关键字数,当列出f(h0-1)<numkey而f(h0)>numkey时,h0才能容纳这么多的关键字,那么h0就是给定关键字下最低树高。
•实际做题时上述求最高最低树高的,现推太慢,太耗时间,现在花时间背公式考场少花时间。
•n个关键字的B数必定具有n-1个叶节点。因为n个关键字将(-∞,+∞)分为n+1个区间,落在这些区间上都是失败,落在分割点上都是成功的,失败结点即叶结点。
•408的叶节点指的是终端结点而非虚构NULL失败结点。
4.2 插入
将待插入关键字插入底部的终端结点,若插入后该终端结点的关键字超出m-1,即该结点目前拥有m个关键字。
若m为偶数,前m/2-1个留在结点,m/2号关键字插入到父结点,后面剩下的m/2个关键字新分配一个兄弟结点存储。
若m是奇数,则取中间的关键字插入到父结点,其左右各成一个结点。父结点若超了,则进行同样的操作。
ps:只要记住谁给父结点就行,m为偶数是刚好一半,m为奇数是刚好中间。
4.3删除
a.将待删除关键字直接删除。
b.被删关键字不在终端结点。用其直接前驱或后继代替它在该结点的位置即可。以c方式删除在终端结点中的直接前驱或后继。
c.被删关键字在终端结点。
c.1 此时终端结点关键字数量满足最低要求⌈m/2⌉-1个,则无需任何操作。
c.2 此时终端结点关键字数量低于最低要求⌈m/2⌉-1个,则需要看左右兄弟。若右兄弟够借,则父给它,兄给父。若左右兄弟都不够借,则父给它,它与一个兄弟合并。
d.最后若父结点是根结点且为空,抹去;不是根结点但关键字数低于限制,将该结点视为被删关键字的结点从b操作开始。
5.B+树
•广泛用于磁盘文件系统,磁盘的一个块即B+树的一个结点。所有记录指针都存在终端结点上,其余非终端结点存储的都是索引指针。这样使得一个磁盘块能够存更多的关键字索引,使B+树的阶达到最大。从而使B+树的高度最小,磁头在块之间转换的次数非常稳定,且最少。(B树也有概率很少,即待查关键字在树的前几行,但是由于B树每个关键字都附带一个很大的记录指针,树的阶明显小,树高明显更大,导致性能很多情况下是很差的。)
