概念:根据给定的值,在某个集合中确定该值所处的位置
查找算法(比较式查找算法分为):
(1)基于线性表的查找。例如:顺序查找、折半查找、分块查找
(2)基于树的查找。例如二叉排序树、B树、AVL树
平均查找长度:为确定某元素在查找表中的位置需要和给定值进行比较的关键字个数的期望值,称为该查找算法查找成功的平均查找长度。
对于长度为n的查找表,查找成功的平均查找长度如下所示:
其中 Pi 为查找表中第i个记录的概率,且 ∑ni=1Pi=1 , Ci 为找到该记录时,曾经和给定值比较的关键字的个数
基于线性表的查找
顺序表的平均查找长度是 ASLsucc=1/n(n−i+1)=(n+1)/2
折半查找:首先这种方法适用于有序的情况下,首先比较的是关键字key与给定值K的关系,可根据三种比较结果分出三种情况:
(1)如果 k=key ,则查找成功
(2)如果 k<key ,说明待查有元素在关键字key的记录之前
(3)如果 k>key ,说明待查元素在关键字key的记录之后
#include<stdio.h>
int search(int *ary, int k, int len);
int search(int *ary, int k, int len) {
int low = 0;
int high = len - 1;
int mid = 0;
while(low <= high) {
mid = (low + high) / 2;
printf("mid : %d\n", mid);
if(ary[mid] == k) {
return mid;
}else if(ary[mid] < k) {
low = mid + 1;
}else {
high = mid - 1;
}
}
return 0;
}
void main(void) {
int ary[10] = {12, 19, 25, 33, 46, 58, 64, 80};
int res = search(ary, 46, 8);
printf("%d ", res);
}
基于树的查找
1. 二叉排序树(二叉查找树)
特征如下:
- 若它的左子树不空,则左子树上所有结点的值均小于根结点的值
- 若它的右子树不空,则右子树上所有结点的值均大于根节点的值
- 它的左、右子树也都分别是二叉排序树
查找过程如下:这个查找过程是与折半查找类似的,即逐步缩小查找的范围
- 若给定值等于根节点的关键字,则查找成功
- 若给定值小于根节点的关键字,则继续在左子树上进行查找
- 若给定值大于根节点的关键字,则就继续在右子树上进行查找
2. 平衡二叉树
满足以下性质的二叉排序树:
- 二叉排序树中任何一个结点的左子树和右子树高度相差的绝对值最多为1
- 它的左右子树都是平衡二叉树
3.B树和B+树
B树在文件系统和数据库系统中使用比较多,适用于组织动态的索引结构
一个 m 阶B树的定义如下:
- 树中每个结点至多有m个子结点
- 除根结点和叶子结点之外,其他每个结点至少有
[m/2] 个子节点- 若根节点不是叶子结点,则根节点至少有两棵子树
- 所有的叶子结点在同一层,可以有 [m/2]−1 到 m−1 个关键字,并且叶子结点所在的层数为树的深度
- 有k个子节点的分支结点恰好包括 k−1 个关键字
散列
零比较次数:这类查找算法属于第二类查找方法,散列法,也被称为哈希法、杂凑法或关键字地址计算法。这是一种非常高效的查找方法。
采用散列方式进行查找时必须解决的两个问题是:
- 如何构造恰当的hash函数,使得结点“分布均匀”,尽量少的冲突
- 一旦发生冲突,如何处理冲突
几种常用的hash函数构造方法:
- 除留余数法
- 数字分析法
- 立方/平方取中法
- 分段叠加法
- 基数转换法
处理冲突的方法:
(1)开放定址法
线性探测再散列
冲突发生时,顺序查看表中下一个单元,直到查找到一个空单元或找遍全表,利用取余%运算,因而整个表可以成为一个首尾连接的循环表,在查找时,类似于循环队列,表尾的后面是表头,表头的前边是表尾
二次探测再散列
随机探测再散列
(2)链地址法
链地址法解决冲突的基本思想是:把所有具有地址冲突的关键字在同一个单链表中,若哈希表的长度为m,则可将哈希表定义为一个有m个头指针组成的指针数组,散列地址为i的记录,均插入到以指针数组第i个单元为头指针的单链表中。