4. 数据结构进阶四静态查询之索引顺序查询
“凡是新的事情在起头总是这样一来的,起初热心的人很多,而不久就冷淡下去,撒手不做了,因为他已经明白,不经过一番苦工是做不成的,而只有想做的人,才忍得过这番痛苦。 -- 陀思妥也夫斯基”
我们继续静态查询的索引顺序查询。
1. 索引顺序查询
首先把表长为n的线性表分成b块,前b-1块记录个数为s=n/b,第b块的记录个数小于等于s。在每一块中,结点的存放不一定有序,但块与块之间必须是分块有序的(假定按结点的关键字值递增有序)。即指后一个块中所有记录的关键字值都应比前一个块中所有记录的关键字值大。为实现分块检索,还需建立一个索引表。索引表的每个元素对应一个块,其中包括该块内最大关键字值和块中第一个记录位置的地址指针。显然这个索引顺序表是一个递增有序表。如下图1
基本思想:先建立索引(最大(最小)关键字表)。要查找关键字为key的元素,先按折半查找获得key对应记录所在的块,再按线性(顺序)查找在块中找到key对应的记录。
2. 代码实现
2.1 定义结构体
structelement
{
longkey;
longdata;
};
structindex
{
longaddress;
longmaxkey;
};
定义一个元素和索引元素的结构体。
元素结构体包括一个key和一个data.
元素结构体包括一个地址和一个最大key值。
2.2 main
输入要测试数据量。Malloc分配测试数据量的内存。
调用initdata函数进行随机初始化,然后将数组按大到小进行排序。
然后调用createidxtable函数进行创建索引表。
然后输入一个key来查找,调用searchposition来查找key所在的分组,不存在则输出查找失败。
然后根据searchposition 返回的key所在的分组,调用seqencesearch函数得到key在分组中的哪个位置,并输出。结束。
如下图2
2.3 creatidxtable
输入元素指针,元素个数,两个指向LONG的指针。
根据元素个数,获得元素需要分组的个数(开方)。
将分组个数保留。
判断元素个数是否刚好可以开方,如16开方为4。
创建需要分组个数的索引个数。
然后处理每个所以的地址,从0开始,共len个(len 为数组长度的开方,或者开方加1)。
寻找该分组最大key值。分组最大值就是该分组的最后一个,因为数组已经从小到大经过的排序。
最后返回索引的指针。
2.4 searchposition
输入索引表,分组数量,查找次数的指针,以及需要查找key值。
如果key和索引表的第一个最大值相等,那么返回第一个索引地址。
如果key和索引表的第后一个的最大值相等,那么返回第后一个索引地址。
如果不是则往中间找,最后返回key值所在的分组,也即是索引最大的数组下标。
2.5 seqencesearch
输入数组指针,起始值,判断索引地址是否是最后一个分组输入不同参数,查找次数,关键key值。
如果是最后一个分组的,则输入num - (tlen - 1) * plen 表示最后一组中存在的元素个数。
如果不是最有一个分组的,则输入plen,表示正常分组中数组的个数。
如果存在该值则返回该值的数组下标。
2.6 selectionsort
将所有元素按大到小进行排序。
2.7 initdata
自动根据需要测试的数据量,自动生成需要的随机数。
2.8 output
输出排序后的所有元素。
3. 源码
#include<malloc.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
#include<stdlib.h>
#include<memory.h>
structelement
{
longkey;
longdata;
};
structindex
{
longaddress;
longmaxkey;
};
structindex*creatidxtable(structelement *elems, longelen, long *tlen, long *plen)
{
structindex*itable;
longi, step, len;
len= (long)sqrt((longdouble)elen);
*plen =len;
step= len;
len= (len * len == elen ? len : len + 1);
*tlen =len;
itable= (structindex*)malloc(sizeof(structindex)* len);
for(i = 0; i < len; ++i)
{
itable[i].address= i;
if(i < len - 1)
itable[i].maxkey= elems[ i * step + *plen -1].key;
else
itable[i].maxkey= elems[elen -1].key;
}
returnitable;
}
long searchposition(structindex *itable, longlength, long *times, longkey)
{
longi;
++(*times);
if (key<= itable[0].maxkey)
returnitable[0].address;
++(*times);
if (key>= itable[length -1].maxkey)
returnitable[length -1].address;
for(i = 0; i < length - 1; ++i)
{
(*times)+= 2;
if (key> itable[i].maxkey && key<= itable[i + 1].maxkey)
returnitable[i+ 1].address;
}
return-1;
}
long seqencesearch(structelement *elems, longstart, longlength, long *times, longkey)
{
longi;
for(i = start; i < start +length;++i)
{
++(*times);
if (elems[i].key== key)
returni;
}
return-1;
}
void selectionsort(structelement *elems, longlength)
{
longi, j, k, s = sizeof(structelement);
structelementt;
for(i = 0; i < length - 1; ++i)
{
k= i;
for(j = i + 1; j < length; ++j)
{
if (elems[k].key> elems[j].key)
{
k= j;
}
}
if(k != i)
{
memcpy(&t,elems +i, s);
memcpy(elems +i, elems + k, s);
memcpy(elems +k, &t, s);
}
}
}
void initdata(structelement *elems, intlength)
{
longi;
srand(time(NULL));
for(i = 0; i < length; ++i)
{
elems[i].data= elems[i].key = rand();
}
}
void output(structelement *elems, intlength)
{
longi;
for(i = 0; i < length; ++i)
{
printf("%-10d", elems[i].key);
if((i + 1) % 5 == 0)
printf("\n");
}
}
void main()
{
structelement *elems;
structindex*itable;
longnum, tlen, plen, times, key, start, pos;
while(1)
{
printf("请输入想要测试的数据量:");
scanf("%ld",&num);
if(num <= 0)
break;
elems= (structelement*)malloc(sizeof(structelement)* num);
initdata(elems,num);
selectionsort(elems,num);
output(elems,num);
itable= creatidxtable(elems, num, &tlen, &plen);
times= 0;
printf("\n");
printf("请输入一个查找关键字:");
scanf("%ld",&key);
if((start = searchposition(itable, tlen, ×, key)) == -1)
{
printf("查找失败1!\n");
}
else
{
pos= seqencesearch(elems, start * plen,
(start== tlen - 1 ? num - (tlen - 1) * plen :plen),×, key);
if(pos != -1)
{
printf("查找成功!\n");
printf("关键字对应的值:%ld\n",elems[pos].data);
printf("关键字比较次数:%ld\n", times);
}
elseprintf("查找失败!\n");
}
free(elems);
free(itable);
}
system("PAUSE");
}