数据结构-查找

本文详细介绍了数据结构中的查找技术,包括顺序查找、有序表查找(如折半查找、插值查找、斐波那契查找)、线性索引查找(稠密索引、分块索引、倒排索引)、二叉排序树、平衡二叉树(AVL树)以及多路查找树(B树、B+树)。此外,还深入探讨了散列查找和处理哈希冲突的方法,如开放定址法、再散列函数法、链地址法和公共溢出区法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.查找

查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。
查找表:是由同一类型的数据元素(或记录)构成的集合。
关键字:是数据元素中某个数据项的值,又称为键值。
查找表按照查找方式来分有两种:静态查找表和动态查找表
静态查找表:只做查找操作的查找表。
(1)查询某个特定的数据元素是否在表中
(2)检索某个特定的数据元素和各种属性
动态查找表:在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素。
(1)查找时插入元素
(2)查找时删除元素

2.顺序表查找

顺序查找,又称线性查找。过程:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;如果直到最后一个(或第一个)记录,其关键字和给定值比较都不相等时,则表中没有所差的记录,查找不成功。
时间复杂度O(n)


public class Test_Search {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] array= {0,2,6,5,18,26,8,9,11,42};
	    System.out.println("普通顺序表查找:" +"\t"+sequenceSearch1(array,9));
		System.out.println("设置哨兵顺序表查找" +"\t"+sequenceSearch2(array,9));

	}
	//普通顺序表查找
	public static int sequenceSearch1(int[] array,int key) {
		int i;
		for(i=1;i<=array.length;i++) {
			if(array[i]==key) {
				return i;
			}
		}
		return 0;
	}
	//设置哨兵顺序表查找
	public static int sequenceSearch2(int[] array,int key) {
		int i;
		array[0]=key;
		i=array.length-1;
		while(array[i]!=key) {
			i--;
		}
		return i;
	}
	
}

3.有序表查找

3.1折半查找

折半查找,BinarySearch,又称二分查找。
前提条件:线性表中的记录必须是关键码有序,线性表采用顺序存储
基本思想:在有序表中,取中间记录作为比较对象,若给定值和中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。
时间复杂度O(logn)

	//二分查找
	public static int binarySearch(int[] array,int key) {
		int low,high,mid;
		low=0;
		high=array.length-1;
		while(low<=high) {
			mid=(low+high)/2;
			if(key>array[mid]) {
				low=mid+1;
			}
			else if(key<array[mid]) {
				high=mid-1;
			}
			else {
				return mid;
			}
		}
		return 0;
	}

3.2插值查找

插值查找,根据要查的关键字key与查找表中最大最小记录的关键字比较后的查找方法。
核心思想:插值的计算公式
折半查找中 ,mid=(low+high)/ 2;
变换后,mid=low+1/2(high-low);
插值查找中,mid=low+(key-array[low])*(high-low)/(array[high]-a[low]);
时间复杂度O(logn)
适用条件:表长较大或者数组中数据分布极端不均匀的情况下,插值查找的平均性能比折半查找要好得多。

3.3斐波那契查找

原理:利用黄金分割原理来实现的。

3.4三种有序查找对比

折半查找:进行加法和除法运算
插值查找:进行复杂的四则运算
斐波那契查找:加减法运算
本质上,是分隔点的选择不同

4.线性索引查找

数据结构的最终目的是提高数据的处理速度,索引是为了加快查找速度而设计的
索引:就是把一个关键字与它对应的记录相关联的过程。
索引按照结构可分为线性索引、树形索引、多级索引。
线性索引,就是将索引项集合组织和线性结构,也称为索引表。
稠密索引、分块索引、倒排索引

4.1稠密索引

稠密索引就是在线性索引中,将数据集中的每个记录对应一个索引项。对于稠密索引这个索引表来说,索引项一定是按照关键码有序的排列。
索引项有序意味着要查找关键字时,可以用到折半、插值、斐波那契等有序查找算法,比顺序查找的效率要高。(但数据集很大的时候,索引也有同样的数据集长度规模,对于内存有限的计算机来说,可能就需要反复去访问磁盘,查找性能反而会下降)

4.2分块索引

例子:图书馆的书籍分类
稠密索引因为索引项和数据集的记录个数相同,所以空间代价很大,为了减少索引项的个数,可以对数据集进行分块,使其分块有序,然后再对每一块建立一个索引项,从而减少索引项的个数。
分块有序,把数据集的记录分成了若干块,这些块满足两个条件:
(1)块内无须
(2)块间有序

4.3倒排索引

例子:搜索引擎搜索关键字
倒排索引,记录号表存储具有相同次关键字的所有记录的记录号
(举个简单的例子来说,将若干篇文章编号为1,2,3…以词语为次关键字,统计词语在文章中是否出现过,将文章编号记录在记录号表中,这样在搜索关键字的时候就可以根据记录号表得出搜索结果,当然实际上,搜索不单纯是这样子的)

5.二叉排序树

动态查找
二叉排序树,又称为二叉查找树,它或者是一棵空树,或者是具有以下性质的二叉树:
(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值
(3)它的左右子树也分别为二叉排序树
操作:
(1)二叉排序树
查找

(2)二叉排序树插入
(3)二叉排序树删除(替代法,使用删除结点的前驱或者后继替代该结点)
存储方式:链式存储

6.平衡二叉树(AVL树)

平衡二叉树(Height-Balanced Binary Search Tree),是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。
平衡因子BF(Balance Factor),二叉树上结点的左子树深度减去右子树深度的值称为平衡因子。
平衡二叉树上的平衡因子只可能为-1,0,1。

7.多路查找树(B树)

多路查找树(multi-way search tree),其每一个结点的孩子数可以多于两个,且每一个结点可以存储多个元素。由于它是查找树,所有元素之间存在某种特定的排序关系。
4种特殊形式:2-3树、2-3-4树、B树、B+树

7.1 2-3树

其中每个结点都具有两个孩子(2结点)或者三个孩子(3结点)。
一个2结点包含一个元素和两个孩子(或没有孩子),且与二叉排序树类似,左子树包含的结点小于该元素,右子树包含的元素大于该元素。(不能只有一个孩子)
一个3结点包含一小一大两个元素和三个孩子(或没有孩子)。若3结点有孩子的话,左子树包含的结点小于较小元素,右子树包含的元素大于较大元素,中间子树包含介于两元素之间的元素。
所有叶子都在同一层次上。
在这里插入图片描述

7.2 2-3-4树

2-3树的概念扩展,包括了4结点的使用。
一个4结点包含小中大三个元素和四个孩子(或没有孩子)。若4结点有孩子的话,左子树包含的结点小于最小元素;第二子树包含大于最小元素,小于第二元素的元素;第三子树包含大于第二元素,小于第三元素的元素;右子树包含的元素大于最大元素。

7.3 B树

B树是一种平衡的多路查找树,2-3树和2-3-4树都是B树的特例。结点最大的孩子数目称为B树的阶。(2-3树是3阶B树,2-3-4树是4阶B树)

7.4 B+树

B树的变形树。在B树中,每个元素在树中只出现一次,有可能在叶子结点上,也有可能在分支结点上。在B+树中,出现在分支结点中的元素会被当做它们在该分支结点位置的中序后继者(叶子结点)中再次出现,另外每一个叶子结点斗湖保存一个指向后一叶子结点的指针。

8.散列查找(哈希表)

8.1概念

存储位置=f(关键字)
f ,散列函数,又称为哈希函数。采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)。关键字所对应的记录存储位置称为散列地址。
散列技术最适合的求解问题是查找与给定值相等的记录。

哈希冲突:两个关键字key1、key2 不等,但是f(key1)=f(key2)

key1和key2称为这个散列函数的同义词。

8.2散列函数的构造方法

(1)直接定址法
取线性函数作为散列地址
f(key)=a*key+b
(2)数字分析法
比如11位手机号:前三位是接入号(对应不同运营商的子品牌);中间四位是HLR识别号(表示用户号的归属地);后四位是真正的用户号。
抽取–抽取关键字的一部分来及计算数列存储位置的方法。
适合位数较大,事先知道关键字的分布且关键字的若干位分布较均匀的情况。
(3)平方取中法
比如1234,平方为1522756,抽取中间三位就是227。
适合不知道关键字的分布,位数不是很大的情况。
(4)折叠法
将关键字从左往右分成位数相等的几部分,叠加求和,按照散列表表长取后几位作为散列地址。
(5)除留余数法
对于散列表长为m的散列函数公式为:
f(key)=key mod p(p<=m)
(6)随机数法
f(key)=random(key)

8.3处理哈希冲突的方法

(1)开放定址法
一旦发生冲突,就去寻找下一个空的散列地址。(线性探测法)
堆积:本来不是同义词却需要争夺一个地址的情况。
(2)再散列函数法
发生地址冲突时,换一个散列函数计算
(3)链地址法
在当前位置给单链表增加结点
(4)公共溢出区法
将有冲突的关键字存储到溢出表中

8.4哈希表查找实现

影响查找性能的因素
(1)散列函数是否均匀
(2)处理冲突的方法
(3)散列表的装填因子
装填因子=填入表中的记录个数 / 散列表长度
标志散列表的装满的程度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值