索引查找
索引的基本思想与字典类似,比如英文字典会提供一个目录,例如这样:A(01),B(13)…。这样能迅速定位到某个单词开头字母对应的页数以及开头字母结束的页数,迅速缩小了检索范围。使用索引查找,需要先构建索引表,分以下三步进行:
- 把表中的数据的关键字分成若干块:R1,R2,…,RL,这些块要满足Rk所有关键字小于Rk+1,k=1,2,3…,L-1,称为“分块有序”。
- 对每块建立一个索引项,成员包括关键字项(块中最大关键字的值),指针项(块的第一个记录在表中的位置),结构如下。
typedef struct IndexType
{
KeyType key;
int Link;
}IndexType;
- 所有索引项组成索引表。
索引查找分两步进行:
- 查找目录,定位元素所在的索引块。
- 将该数据块调入内存,查找数据。
索引表的顺序查找算法
注意,若将索引表分为m块,需要在索引数组的m+1位置传入一个key为空的索引项,作为第m块元素的停止位。
#include<stdio.h>
#include<stdlib.h>
typedef int KeyType;
typedef struct DataType
{
KeyType key;
}DataType;
typedef struct IndexType
{
KeyType key;
int Link;
}IndexType;
int IndexSearch(IndexType* ls, DataType* s, int m, KeyType key)
{
int i = 0;
int j;
while (i < m && key > ls[i].key)
{
i++;
}
if (i == m)
{
return -1;
}
j = ls[i].Link;
while (key != s[j].key&& j < ls[i + 1].Link)
{
j++;
}
if (key == s[j].key)
{
return j;
}
else
{
return -1;
}
}
//s必须满足前一个块的元素比后一个块的元素小
IndexType* GetIndexTable(DataType* s, int n, int m)
{
IndexType* ls = (IndexType*)malloc(sizeof(IndexType) * (m+1)); //预留一个停止位
int block_len = n / m;
for (int i = 0; i < m; i++)
{
KeyType max = 0;
for (int j = i * block_len; j < block_len * (i + 1); j++)
{
if (s[j].key > max)
{
max = s[j].key;
}
}
ls[i].key = max;
ls[i].Link = i * block_len;
}
ls[m].key = -1;
ls[m].Link = n;
return ls;
}
int main()
{
DataType s[] = { 10,50,40, 60,55,53,70,80,90 };
IndexType* ls = GetIndexTable(s, 9, 3);
int j;
j = IndexSearch(ls, s, 3, 80);
printf("%d\n", j);
free(ls);
return 0;
}
性能分析
若索引块和索引块之间都采用顺序查找,则平均查找长度为索引块内部和索引块之间的平均查找长度之和,有:
n为表长,b为数据块数目。