大话数据结构8之查找
1.查找:查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。
2.查找概论
查找表(search table):是由同一类型的数据元素(或记录)构成的集合。
关键字(key):是数据元素中某个数据项的值,又称为键值,用它可以标识一个数据元素。
若此关键字可以唯一地标识一个记录,则称此关键字为主关键字(primary key)。
对于那些可以识别多个数据元素(或记录)的关键字,我们称为次关键字(secondary key)。
查找表按操作方式来分:静态查找表和动态查找表
静态查找表(static search table):只作查找操作的查找表
查询某个特定的数据元素是否在查找表中
检索某个特定的数据元素和各种属性
动态查找表(dynamic search table):在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素。
查找时插入数据元素
查找时删除数据元素
3.顺序表查找
顺序查找(O(n))(sequential search)又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;如果直到最后一个(或第一个)记录,其关键字和给定值比较都不相等时,则表中没有所查的记录,查找不成功。
4.有序表查找
a.折半查找(O(log n)):折半查找(binary search)技术,又称为二分查找。它的前提是线性表中的记录必须是关键码有序(通常从小到大有序),线性表必须采用顺序存储。折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所有查找区域无记录,查找失败为止。mid = (low+high)/2
b.插值查找(Interpolation search):根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式mid = (key-a[low])/(a[high]-a[low]).
对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好得多。反之,数组中如果分布极端不均匀,用插值查找未必是很合适的选择。
c.斐波那契查找(Fibonacci search):利用黄金分割原理来实现。mid = low + F[k-1]-1
5.线性索引查找
数据结构的最终目的是提高数据的处理速度,索引是为了加快查找速度而设计的一种数据结构。
索引就是把一个关键字与它对应的记录相关联的过程。
索引按照结构分为线性索引、树形索引和多级索引。
线性索引就是将索引项集合组织为线性结构,也称为索引表。
线性索引:稠密索引、分块索引和倒排索引
稠密索引:是指在线性索引中,将数据集中的每个记录对应一个索引项。对于稠密索引这个索引表来说,索引项一定是按照关键码有序的排列。
分块索引:分块有序,是把数据集的记录分成了若干块,并且这些块需要满足两个条件:块内无序,快间有序。对于分块有序的数据集,将每块对应一个索引项,这种锁引方法叫做分块索引。
倒排索引:索引项的通用结构是:次关键码、记录号表
其中记录表存储具有相同次关键字的所有记录的记录号(可以是指向记录的指针或者是该记录的主关键字)。这样的索引方法就是倒排索引(inverted index)。
倒排索引的优点是查找记录非常快,基本等于生成索引表后,查找时都不用去读取记录,就可以得到结果。但缺点是记录号不定长。
6.二叉排序树
二叉排序树(Binary sort tree),又称为二叉查找树。它或着是一棵空树,或者是具有下列性质的二叉树。
若它的左子树不空,则左子树上所有结点的值均小于它的根结构的值。
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
它的左、右子树也分别为二叉排序树。
构造一棵二叉排序树的目的,其实并不是为了排序,而是为了提高查找和插入删除关键字的速度。
二叉排序树是以链接的方式存储,保持了链接存储结构在执行插入或删除操作时不用移动元素的优点,只要找到合适的插入和删除位置后,仅需修改链接指针即可。
二叉树的查找性能取决于二叉排序树的形状。希望对一个集合按二叉排序树查找,最好是把它构建成一棵平衡的二叉排序树。
7.平衡二叉树(AVL树)
平衡二叉树(self-balancing binary search tree或height-balanced binary search tree),是一种二叉排序树,其中每一个结点的左子树和右子树的高度差至多等于1.
我们将二叉树上左子树结点的左子树深度减去右子树深度的值称为平衡因子BF(balance factor。)
距离插入结点最近点,且平衡因子的绝对值大于1的结点为根的子树,我们 称为最小不平衡树。
查找和插入和删除时间复杂度为O(log n)
8.多路查找树(B树)
多路查找树(multi-way search tree),其每一个结点的孩子数可以多于两个,且每一个结点处可以存储多个元素
4种特殊形式:2-3树、2-3-4树、B树、B+树
2-3树:其中每一个结点都具有两个孩子(我们称它为2结点)或三个孩子(我们称它为3结点)。
一个2结点包含一个元素和两个孩子(或没有孩子)
一个三结点包含一大一小两个元素和三个孩子(或没有孩子)
2-3-4树:其实是2-3树的扩展,包括了4结点的使用。一个4结点包含小中大三个元素和四个孩子(或没有孩子)。
B树:B-tree是一种平衡的多路查找树,2-3树和2-3-4树都是B树的特例。结点最大的孩子数目称为B树的阶(order),因此,2-3树是3阶B树,2-3-4树是4阶B树。
B树的数据结构就是为内外存的数据交互准备的。
B+树:为了解决所有元素遍历等基本问题,在原有B树结构基础上,加上了新的元素组织方式,这就是B+树。
9.散列表查找(哈希表)概述
散列技术 是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。f称为散列函数,又称为哈希(hash)函数。采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(hash table)。关键字对应的记录存储位置称为散列地址。
散列技术既是一种存储方法也是一种查找方法。
散列技术最适合求解的问题是查找与给定值相等的记录
会碰到两个关键字key1 ≠ key2 ,但是却有f(key1) = f(key2),这种现象我们称为冲突(collision),并把key1 和 key2 称为这个散列函数的同义词。
9.散列函数的构造方法
好的散列函数:计算简单。散列地址分布均匀
a、直接定址法:取关键字的某个线性函数值为散列地址。f(key) = a * key + b(a、b为常数)。优点是简单、均匀也不会产生冲突,但需要事先知道关键字的分布情况,适合查找表较小且连续的情况。
b、数字分析法:通常适合处理关键字位数比较大的情况,若事先知道关键字的分布且关键字的若干分布较均匀,就可以考虑这方法。
c、平方取中法:适合不知道关键字分布,而位数又不是很大的情况。
d、折叠法:事先不需要知道关键字的分布,适合关键字位数较多的情况。
e、除留余数法:最为常用 f(key) = key mod p (p≤m) 根据经验,若散列表表长为m,通常p为小于或等于表长(最好接近m)的最小质数或不包含小于20质因子的合数。
f、随机数法:选择一个随机数,取关键字的随机函数值为它的散列地址。f(key)=random(key)。
10.处理散列冲突的方法
a、开放定址法:就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
fi(key) = (f(key) + di) MOD m (d=1,2,3....,m-1)
我们把这种解决冲突的开放定址法称为线性探测法。
不是同义词却需要争夺一个地址的情况,这种现象为堆积。
增加平方运算的目的是为了不让关键字都聚集在某一块区域,我们称这方法为二次探测法。fi(key) = (f(key) + di) MOD m (di = 12,-12,22,-22,...,q2,-q2,q≤m/2)
还有一种方法是,在冲突时,对于位移量di采用随机函数计算得到,我们称为随机探测法。fi(key) = (f(key) + di) MOD m(di是一个随机数列)
b、再散列函数法:事先准备多个散列函数 fi(key) = RHi(key) (i=1,2,...,k). RHi就是不同的散列函数。
c、链地址法:将所有关键字为同义词的记录存储在一个单链表中,我们称这种表为同义词子表,在散列表中只存储所有同义词子表带头指针。
d、公共溢出区法:
11.散列表查找实现
散列表查找性能分析:散列函数是否均匀 处理冲突的方法 散列表带装填因子
索引技术被广泛的用于文件检索、数据库和搜索引擎等技术领域,是进一步学习这些技术等基础。