【C++】查找

一 二分查找

二分查找是比顺序查找效率高的一种查找算法,但它只适用于有序的数据集。

1.1 算法步骤

二分查找,也叫这折半查找,主要步骤为:
(1) 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键进行比较,如果两者相等,则查找成功;
(2) 否则,利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一个子表,否则进一步查找后一个子表;
(3) 重复以上过程,知道找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

1.2 具体实现

二分查找函数需要的参数:

  • int *array:目标数组,在这个数组中进行查找;
  • int key:待查找的关键字;
  • int lowint high:查找的区间;若在整个数组中查找,调用时指定low = 0; high = length of array
int BinarySearch(int *array, int key, int low, int high)
{	
	int mid;
	while(low <= high)
	{
		mid = (low + high) / 2;
		if(key = array[mid])
			return mid;
		else if(key < array[mid])
			high = mid - 1;
		else
		low = mid + 1;
	}
	return 0;  // 表中不存在该元素
}

二 散列查找

2.1 散列函数的构造

通常有以下几种构造方法:
(1) 直接定址法
即,采取关键字的某个线性函数值为散列地址——f(key) = a * key + b
这样的散列函数有点就是简单、均匀,也不会产生冲突,但问题是要实现知道关键字的分布情况,适合查找较小且连续的情况。现实中不常用。
(2) 数字分析法
数字分析法是在知道关键字的情况下,取关键字的尽量不重复的几位值组成散列地址。
(3) 平方取中法
即,取关键字平方后的中间即为作为散列地址。
(4) 折叠法
即,将关键字分为位数相等的几个部分,最后一部分的位数可以不等,然后把这几个部分的值(舍去进位)相加作为散列地址。
(5) 除留余数法
最为常用。对于散列表长度为m的散列函数公式为:
f(key) = key mod p (p <= m)
mod就是取模(求余数)。
显然,本方法的关键在于选择合适的p,p如果选的不好,就可能产生同义词。一个经验是,若散列表表长为m,通常p为小于或等于表长(最好接近于m)的最小质数或不包含小于20质因子的合数。实践证明,当p取小于散列表长的最大质数时,产生的散列函数较好。
(6) 随机数法
即,选择一个随机函数,取关键字的随机函数值作为散列地址。

2.2 处理冲突

前面在构造散列函数中,散列地址可能会产生冲突,通常处理冲突的方法有以下几种:
(1) 开放定址法
即,一旦发生冲突,就会寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入,公式为:
fi(key) = (f(key)+di) MOD m (di=1,2,3 ... m-1)
用开放定址法解决冲突的做法是:
当冲突发生时,使用某种探测技术在散列表中形成一个探测序列,沿此序列逐个单元地查找,直到找到给定地关键字,或者碰到一个开放地地址(即该地址单元为空)为止。查找时探测到开放的地址则表明表中无待查的关键字,即查找失败。
这种解决冲突的开放定址法称为线性探测法。
(2) 二次探测法
即,双向寻找可能的空位置。
(3) 随机探测法
对于位移量di采用随机函数(伪随机)计算得到,称为随机探测法。伪随机数即设置随机种子相同,不断调用随机函数可以生成不会重复的数列,在查找时,用同样的随机种子,每次得到的数列时相同的,相同的di得到相同的散列地址。
fi(key) = (f(key)+di) MOD m (di是一个随机数列)
(4) 再哈希法
即,当散列地址冲突时,用另外一个散列函数再计算一次,减少冲突,增加了计算时间。
(5) 链地址法
前面讨论的都是一旦发生冲突就寻找下一个空的散列地址,下面说的时原地处理。
即,将所有关键字散列地址相同的记录存储在一个单链表中,称我给同义词子表,在散列表中只存储同义词子表的头指针。
链地址法解决冲突的做法是:将所有关键字散列地址相同的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组T[0…m-1]。凡是散列地址为i的结点,均插入到以 T[i]为头指针的单链表中。T中各分量的初值均为空指针。链地址法的优势是对于可能造成很多冲突的散列函数来说,提供了绝不会出现找不到地址的保障,当然带来了遍历单链表的性能损耗,一般损耗不是大问题。
(6) 建立公共溢出区
即,将散列表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

发布了96 篇原创文章 · 获赞 19 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Thera_qing/article/details/102314530