目录
7.1 查找的基本概念
- 查找。在数据集合中寻找满足条件的数据元素的过程称为查找。查找的结果分为查找成功,查找失败 。
- 查找表(查找结构)。用于查找的数据集合称为查找表,它由同一类型的数据元素(或记录)组成,可以是一个数组或链表等数据类型。
- 关键字。数据元素中唯一标识该元素的某个数据项的值。使用基于关键字的查找,查找结果应该是唯一的。
- 平均查找长度。在查找过程中,一次查找的长度是指需要比较的关键字次数,而平均查找长度则是所有查找过程中进行关键字的比较次数的平均值。
,即概率×比较次数
7.2 顺序查找和折半查找
7.2.1 顺序查找
1.一般线性表的顺序查找
顺序查找也称线性查找,它对顺序表和链表都是适用的。对于顺序表,可通过数组下标递增来顺序扫描每个元素。
// 一般线性表顺序查找
typedef int Elemtype;
typedef struct {//查找表的数据结构
Elemtype* elem; //元素存储空间基址,建表时按实际长度分配,0号留空
int TableLen; //表的长度
}SSTable;
int Search_Seq(SSTable ST, Elemtype key) {
ST.elem[0] = key; //ST.elem[0]充当哨兵
for (int i = ST.TableLen; ST.elem[i] != key; i--);
return i;
}
引入“哨兵”的算法可以避免很多不必要的判断语句,可以提高程序效率。
- 查找成功时,顺序表查找的平均长度为:
- 查找不成功时,与表中关键字的比较次数显然是n+1次,故ASL=n+1。
2.有序表的顺序查找
若在查找之前就已经知道表是关键字有序的,则查找失败时就可以不用再比较到表的另一端就能返回查找失败的信息。
可以用下图所示的判定树来表述有序线性表的查找过程。
- 查找成功的平均查找长度与一般线性表相同
注意,有序线性表的顺序查找和后面的折半查找思想不一样,且有序线性表的顺序查找中的线性表可以是链式存储结构。
7.2 折半查找---二分法查找
它仅适用于有序的顺序表。代码实现如下:
// 折半查找
typedef struct {
Elemtype* elem;
int TableLen;
}SeqList;
int Binary_Search(SeqList L, Elemtype key)//key为待查找元素
{
int low = 0, high = L.TableLen - 1, mid;
while (low <= high) {
mid = (low + high) / 2;//取中间位置
if (L.elem[mid] == key)
return mid;
else if (L.elem[mid] > key)
high = mid - 1;//如果中间值比key还要大,则从前半部分继续查找
else
low = mid + 1; //如果中间值比key还要小,则从后半部分继续查找
}
return -1;
}
折半查找的过程可用如图所示的二叉树来描述,称为判定树。
很明显,判定树是一颗平衡二叉树且是一棵二叉排序树。
- 查找成功时,查找长度即为平衡二叉树树高。 树高为
运用上述可以推出对于折半查找树平均查找长度为:
- 查找不成功的查找长度为图中方框结点,查找成功为圆形结点。
注意,由于折半查找要求随机存取的特性,因此该查找发仅适合于顺序存储结构,且要求元素按照关键字有序排列。
7.2.3 分块查找
分块查找基本思想:将查找表分为若干子块,块内元素可以无序,块间必须是有序的。分块查找的过程分为两步:第一步是在索引表中确定待查记录所在的块,可以顺序查找或折半查找索引表;第二步是在块内顺序查找。
假设索引查找和块内查找的平均查找长度分别为a和b,则分块查找的平均查找长度ASL=a+b。
将长度为n的查找表均匀分为b块,每块有s个记录,在等概率情况下,块内和索引表均用顺序查找 则:
,此时若s=n^1/2,则平均查找长度取最小值为n^1/2+1
若对索引表采用折半查找时,平均查找长度为: