搜索算法
平均查找长度ASL
ASL=P1C1+P2C2+...+PnCnASL = P_{1}C_{1} + P_{2}C_{2} + ...+ P_{n}C_{n}ASL=P1C1+P2C2+...+PnCn
P_{n}: 查找第n个元素的概率
C_{n}:查找第n个元素的比较次数
常见的查询算法
- 顺序查找
- 二分查找
- 索引查找
- 哈希查找
1. 顺序查找
复杂度分析:
- 最好情况: O(1)
- 最差情况: O(n)
- ASL=1n∑i=1ni=n+12ASL = \frac{1}{n}\sum_{i=1}^{n}i = \frac{n+1}{2}ASL=n1∑i=1ni=2n+1
代码:
typedef int ElemType;
int seqSearch(ElemType *table, int length, ElemType target){
int i;
for(i = 0; i < length ; i++){
if(table[i] == target){
return i;
}
}
return -1;
}
2. 二分查找(折半)
要求
有序表
复杂度分析:
- 最好情况: O(1)
- 最差情况: O(log2n+1log_{2}n +1log2n+1)
- ASL: 假设为满二叉树: 树高 h=log2(n+1)h = log_{2}(n+1)h=log2(n+1)
ASL=1n∑i=1hi∗2i−1=n+1nlog2(n+1)−1ASL = \frac{1}{n} \sum_{i = 1}^{h}i *2^{i-1} = \frac{n+1}{n}log_{2}(n+1)-1ASL=n1i=1∑hi∗2i−1=nn+1log2(n+1)−1
代码:
typedef int ElemType;
int binarySearcch(ElemType *table, int length, ElemType target) {
if(length <= 0) return -1;
int low = 0, high = length - 1, mid = (high + low) / 2;
while(low <= high) {
if(target == table[mid]) return mid;
else if(target < table[mid])
high = mid -1;
else low = mid + 1;
mid = (low + high) / 2;
}
return -1;
}
3. 索引查找
要求
- 建立索引, 根据索引定位, 每个索引划分一个块
- 索引有序, 每个块内部也有序
- 对索引表和每个块内都可以进行顺序查找或者二分查找
- 即在索引表中查找, 再到块中查找.
复杂度分析:
- 假设索引和快内都采用顺序搜索:
- ASL = ASL(索引表) + ASL(块内)
- 设表长为n, 每个块有r个元素, 可以分为s个块 , 粗略来说: r=nsr = \frac{n}{s}r=sn
ASL=1s∑i=1si+1r∑j=1rj=s+r+22=12(ns+s)+1ASL = \frac{1}{s} \sum_{i = 1}^{s}i +\frac{1}{r} \sum_{j = 1}^{r}j = \frac {s+r+2}{2} = \frac{1}{2}(\frac{n}{s}+s)+1 ASL=s1i=1∑si+r1j=1∑rj=2s+r+2=21(sn+s)+1
代码:
typedef int Elemtype;
typedef struct index{
Elemtype key;
int index;
}Index;
int indexSearch(vector <Index> indexVec, Elemtype *table, Elemtype target) {
//索引表中最后一个元素存储的index为table的最后一个元素的下标
int i = 0;
while(i < indexVec.size() - 1 && target > indexVec[i].key) i++;
if( i == indexVec.size() - 1) return -1;
int j = indexVec[i].index;
// printf("块:%d\n",i );
while(table[j] != target && j < indexVec[i+1].index) j++;
if(target == table[j]) return j;
return -1;
}