【查找思想】
前提条件:查找表中的所有记录是按关键字有序(升序或降序) 。
用 、 和 表示待查找区间的下界、上界和中间位置指针,初值为 , 。
-
取中间位置 : ;
-
比较中间位置记录的关键字与给定的 值:
- 相等: 查找成功;
- 大于:待查记录在区间的前半段,修改上界指针: ,转⑴ ;
- 小于:待查记录在区间的后半段,修改下界指针: ,转⑴ ;
-
直到越界 ,查找失败。
【算法实现】
#include<stdio.h>
#include<stdlib.h>
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a) < (b))
/* 数据元素类型定义 */
typedef int KeyType; //关键字类型
typedef struct
{
KeyType key; //关键字域
//float weight; //其他域(此处可设为权重)
}ElemType;
/* 静态查找表的顺序存储结构 */
typedef struct
{
ElemType *elem; //数据元素存储空间基址,0号单元弃用
int length; //表长度
}SSTable;
//创建查找表
void Create(SSTable *ST)
{
printf("请输入查找表的长度:");
scanf("%d", &ST->length);
ST->elem = (ElemType *)malloc(ST->length*sizeof(ElemType));
printf("请依次输入表中数据元素的关键字:");
for(int i = 1; i <= ST->length; i++)
scanf("%d", &ST->elem[i].key);
}
//折半查找
int Bin_Search(SSTable ST, KeyType key)
{
int low = 1;
int high = ST.length;
int mid;
while(low<=high)
{
mid = (low + high) / 2;
if(EQ(key, ST.elem[mid].key))
return mid;
else if(LT(key, ST.elem[mid].key))
high = mid - 1;
else
low = mid + 1;
}
return 0;
}
int main()
{
SSTable ST;
KeyType key;
Create(&ST);
printf("请输入待查找数据元素的关键字:");
scanf("%d", &key);
printf("查找位置为:%d\n", Bin_Search(ST, key));
return 0;
}
【算法分析】
- 折半查找可用折半查找判定树来描述,例如,含有11个元素的有序表的判定树如下:
注意:折半查找判定树的形态只与表元素个数个数n相关,而与输入实例中key的取值无关。
-
在 个元素的折半查找判定树中,显然有 种查找成功的情况,对应的内部结点有 个。
成功的折半查找过程恰好是走了一条从判定树的根到被查结点(内部结点)的路径,经历比较的关键字次数恰好为该元素在树中的层数,所以查找成功的平均查找长度为
其中,查找 的概率为 , 表示关键字 对应内部结点的层次。 -
有 种查找失败的情况,对应的外部结点有 个。
失败的折半查找过程是经历了一条从判定树根到某个外部结点的路径,所需的关键字比较次数是该路径上内部结点的总数,所以不成功的平均查找长度为
其中, 是查找外部结点集合中关键字的概率, 表示对应外部结点的层次。 -
为讨论方便,不妨将二叉判定树的第 层上的结点补齐就成为一棵满二叉树,深度不变, 。由满二叉树性质知,第 层上的结点数为 ,设表中每个记录的查找概率相等,即 ,查找成功时的平均查找长度ASL: