数据结构——查找与排序

查找

静态查找表

顺序查找(Sequential Search)

原理: 对于任意一个序列以及一个给定的元素,将给定元素与序列中元素依次比较,直到找出与给定关键字相同的元素,或者将序列中的元素与其都比较完为止。

代码实现类似于数组遍历,理解即可。

顺序查找的平均查找长度ASL = (n + 1)/2

折半查找( Binary Search )

定义:折半查找也叫二分查找。要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

查找过程:表中元素按照一定顺序进行排列,将需要查找的元素与表中间位置元素进行比较,按照查找条件判断下一次查找的方向,直至查询成功或所查询的子表不存在即可。

经典例题:

在55个互异元素构成的有序表A[1..55]中进行折半查找(或二分查找,向下取整)。若需要找的元素等于A[19],则在查找过程中参与比较的元素依次为(  )

A.A[28]、A[30]、A[15]、A[20]
B.A[28]、A[14]、A[21]、A[17]
C.A[28]、A[15]、A[22]、A[18]
D.A[28]、A[18]、A[22]、A[20] 

题解:题目采用的是二分查找,我们第一想到的就是找到这个有序表的中间值,但是中间值怎么算,这是解题非常现实的问题。教大家一种方法:(首项 + 尾项)/2。比如序列:{5,6,7},中间值6,(5+7)/2 = 6,很实用。现在回到题目,第一个查找的值 (1+55)/2 = 28,第二个查找的值 (1+27)/2=14,这里为什么是27呢?因为28已经比较了,现在的比较到27结束。第三个查找的值 (15+27)/2=21,第四个查找的值 (16+20)/2=18,虽然题目只要求四个,但是还是干完,第五个查找的值(18+20)/2=19。查询成功。

本题答案选B

顺序查找的平均查找长度ASL ~~ log2(n + 1) - 1

分块查找

定义: 分块查找也叫索引顺序查找,分块查找是折半查找和顺序查找的一种改进方法 。折半查找虽然效率比顺序查找高,但是它只适合有序表,而且只适用于顺序存储结构。顺序查找的确定就不用说了,效率低。

方法描述:

  • 官方解释: 分块查找要求把一个大的线性表分解成若干块,每块中的节点可以任意存放,但块与块之间必须排序。假设是按关键码值非递减的,那么这种块与块之间必须满足已排序要求,实际上就是对于任意的i,第i块中的所有节点的关键码值都必须小于第i+1块中的所有节点的关键码值。此外,还要建立一个索引表,把每块中的最大关键码值作为索引表的关键码值,按块的顺序存放到一个辅助数组中,显然这个辅助数组是按关键码值费递减排序的。查找时,首先在索引表中进行查找,确定要找的节点所在的块。由于索引表是排序的,因此,对索引表的查找可以采用顺序查找或折半查找;然后,在相应的块中采用顺序查找,即可找到对应的节点。

  • 个人理解:将表或序列分块,快间有序,块内无序。即块间按间每块的最大值线性顺序大小排列,块内可以是乱序排列。同时建立索引表,将每块的的最大值和块起始位置记录下来。

    | 1 2 3 7 5 10 | 11 18 23 56 33 | 57 98 100 102 142 |
    
    上面就将数据分为了三块,将上面的序列按从左到右进行标号(1,2,3,....)下面建立索引表
    
    10 56 142
    1 7 12

    查找过程:在索引表中确定等待查找记录所在的块(顺序查找或折半查找),在块内顺序查找。

遇到合适的题目再来补充示例,小伙伴们有也可以跟我讲哦

折半查找的平均查找长度 ASL = 索引表查找ASL + 块内查找ASL

动态查找表

**二叉排序数 (Binary Sort Tree) **

别名:二叉查找树,二叉搜索数

定义:

  1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 左、右子树也分别为二叉排序树;

性质:将二叉排序树进行中序遍历,所得到的数据元素序列是一个按照关键字排序的递增序列。

查找过程:二叉排序树非空时,给定值与根节点对比,相同则查找成功,小于根节点则到左子树上找,大于根节点则到右子树上找。循环往复,直至找到值或查找结果为空树。

插入操作:二叉排序树非空,需要插入的元素与根节点比较,小于根节点值那么该值插入左子树,大于根节点则插入右子树。我所说的插入是去进行比较,子树为空才插入。

删除操作:不能将以该节点为根的所有子节点均删除,只能删该节点,而且还要保证性质不变。需要注意删除时3要将因删除节点而断开的二叉链表重新链接起来,并且防止防止重新链接后树的高度增加。(数的高度决定了树的查找效率,数的高度越高,效率越差)

  1. 删除叶子节点:直接删除
  2. 删除只有左子树或只有右子树的节点,直接将他的子节点替换它即可
  3. 删除既有左子树又有右子树:用左子树的最大节点代替被删的数,然后由于这个最大节点被换走了也就相当于删除所以我们再判断这个最大节点相当于删除情况的哪一个,以此类推即可。当然也可以使用右子树的最小节点替换它,也进行判断,以此类推即可。

平均查找长度:最好情况(分布比较平均) ASL=log2(n+1)-1,最坏情况(单支树情况) ASL=(n+1)/2

平衡二叉树 (Balanced Binary Tree)

定义:平衡二叉树又称AVL树,它必须满足二叉排序树的性质,而且左子树和右子树的高度之差的绝对值小于等于1,且左子树和右子树也是平衡二叉树。

平衡因子:左子树深度减去右子树深度所得到的值。平衡二叉树的平衡因子只能是-1,0,1

平衡二叉树的调整:

  1. 失衡节点:当新插入节点时,由于节点的插入位置导致节点平衡因子的绝对值大于了1的节点就是失衡节点。

  2. 四种类型

  3. 调整原则:降低高数据结构——查找与排序_第1张图片
    度,保持二叉排序树性质。(重点是牢记二叉排序树的性质)

插入操作:也就是上面的平衡二叉树的调整。

删除操作:当删除节点的左右子树都不为空,用左子树的根节点替换该节点,然后对左子树根节点的左右子树重新进行调整,最后对被删节点到树根路径上的所有平衡因子大于1的节点进行更新。

哈希表及其查找

定义:哈希表也称为散列表,它记录存储位置与关键字之间存在的对应关系(Hash函数)

散列表术语:

  1. 散列方法:选取某个函数,依该函数按关键字计算元素的存储位置,并按此存放。当查找时,由同一个函数对给定值K进行计算地址,然后到地址单元中元素的关键码进行对比,确定查找成功。
  2. 散列函数:散列方法中使用的转换函数。
  3. 冲突:不同的关键码映射到同一个散列地址。
  4. 同义词:具有相同函数值的多个关键字。

哈希表构造:

  1. 需要解决的问题:构造好的散列函数(所选函数尽可能简单,函数关键码计算出的地址应在散列地址几种致均匀分布,以减少空间浪费),并制定一个好的解决冲突的方案。
  2. 考虑因素:执行速度,关键字长度,散列表大小,关键字分布情况,查找频率。
  3. 元素集合特性进行构造:散列查找是以空间换时间,但还是希望散列地址空间尽量少。尽量均匀存放元素以避免冲突。

构造hash表方法:

  1. 直接定值法:Hash(key) = a*key + b,以关键码key的某个线性函数值为散列地址,不会产生冲突。d但是要连续的地址空间,空间效率低。
  2. 除留余数法:Hash(key) = key mod p (p是一个整数),获取p的技巧是设表长为m,取 p<= m 且为质数。

解决冲突方法:

  1. 开放地址法:有冲突时就去寻找下一个空的散列地址。只要散列表足够大,空的散列地址总能找到。

    例如:Hi= (Hash(key) + di) mod m

    • 线性探测法:di为1,2,3,…m-1的线性序列
    • 二次探测法:di为12,-12,22,-22…q2二次序列
    • 伪随机探测法:di为伪随机序列
  2. 链地址法:相同散地址的记录链成一个单链表,m个散列地址就设m个单链表。
    数据结构——查找与排序_第2张图片

排序

定义:将一组杂乱无章的数据按照一定规律顺次排列起来。(将无序序列排列成一个有序序列)

插入排序

定义:边插入变排序,保持结果序列仍然有序。

直接插入排序

定义:顺序查找法定位插入的位置

过程:

  1. 将要插入的元素存储到一个变量中
  2. 按照升序或降序将序列的每一个元素与插入元素比较,符合条件后序列匹配元素位置后移
  3. 插入元素进行插入操作

时间复杂度:

  1. 最坏情况下(输入数据时逆有序的) Tw(n) = O(n2)
  2. 最好情况下:Tw(n) = O(n)
  3. 平均情况下:Tw(n) = O(n2)

空间复杂度:O(1)

二分插入排序

定义:查找插入位置时使用折半查找法

过程:折半查找的查找过程,插入位置 为(hight + low)/2,减少了比较次数,但没有减少移动次数

时间复杂度:O(n2)

空间复杂度:O(1)

希尔排序

思想:将整个待排序序列分成若干子序列,分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体记录进行一次直接插入排序。

理解:跳跃式的排序方式,也就是将每个子序列的看成一个数组,将每个数组中相同下标值的数进行排序,而选取的数组长度就是增量序列,这个长度最后必须为1且互为质数。

希尔排序是一种不稳定的排序算法,因为它在排序过程中,序列中相等的值相对位置可能发生改变。

交换排序

思想:两两比较,发生逆序则交换,知道所有记录都排序好位置

冒泡排序

定义:每趟不断将记录进行比较,并按照前小后大进行排列。

理解:冒泡排序就是从前往后将相邻两个元素进行比较,小的排到前面,每一趟可以选择出一个最大的值排到最后。也就是每一次排序后下一次进行排序的数会减少一个,新排出的最大的数不参与下一轮比较。

时间复杂度:最好情况下是O(n),最坏和一般情况下是Tw(n) = O(n2)

冒泡排序是稳定的。

快速排序

定义:任取一个元素为中心,其余所有元素与它进行比较,小的放前面大的放后面。然后将根据这个中心元素的所分成的两个子序列重新进行选取中心元素再排序,循环往复直至每个子表只剩一个元素。

选取中心点:可以选择序列的第一个元素,然后一次比较同序列中它后面的元素,元素的插入采用联投向中间交替逼近法。即给定一个空间,比中间元素大的从后往前放,比中间元素小的从前往后放

时间复杂度:平均时间Tw(n) = O(nlog2n),最坏情况是O(n2)

空间复杂度:O(nlog2n)

快速排序不是稳定的,而且并不适用与原本有序或基本有序的记录序列进行排序。

选择排序

简单选择排序

思想:在待选择的数据中选出最大(小)的元素放在其最终的位置。

理解:每一次,通过 n-1 次关键字比较,从n个关键字中找到最小的这次的值上的数进行交换。如第一次找到的最小值与第一个交换,第二次与第二个值交换…

时间复杂度:最好最坏平均三种情况下都是O(n2)

堆排序

定义:若n个元素的序列{a1,aaa2,a3…}满足 {ai <= a2i ; ai <= a2i+1}或{ai >= a2i ; ai >= a2i+1},则分别称该序列为小根堆和大根堆。

本质:堆性质是满足如下性质的完全二叉树(二叉树中任一非叶子节点均小于(大于)它的孩子节点)

堆的建立:

  1. 单节点的二叉树是堆
  2. 完全二叉树的所有叶子节点为根的子树是堆
  3. 建立的话自己查资料,我讲不清

时间复杂度:最好最坏平均时间复杂度都是O(nlog2n)

归并排序

定义:将一个有n个记录的无序文件看成是由n个长度为1的有序子文件组成,然后两两贵宾,如此重复,最终形成一个包含n个记录的有序文件为止。

基数排序

定义:为序列准备与序列元素个数相同的桶,按序列元素尾部元素开始分到各自的桶中,每一次获取到新的序列,将新的序列的倒数第二位也分配到各自的桶中,一直到最大元素的顶部。最后就会出现一个有序序列。

例题

堆排序

数据结构——查找与排序_第3张图片

题解:根据堆排序的性质,每个有子节点的节点他的两个子树的值都遵循着一种规则,整个树中的子节点的值相对于它本身的根节点来说要么同大,要么同小。这里我们直接将选项中的序列按照层序遍历的方式构建二叉树,然后判断每一个节点他的子节点对他的根节点的比较是否一直是大于的,如果不是,那就是它不符合条件。最后我们可以看到D选项的39比它的根节点要小,而条件是大于的,所以D选项是错误的。

归并排序

题目: 用插入排序和归并排序算法对数组<3,1,4,1,5,9,6,5>进行从小到大排序,则分别需要进行( )次数组元素之间的比较。

解题:首先我们使用插入排序:
数据结构——查找与排序_第4张图片

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