顺序查找表和索引查找表

查找表(search table)是由同一类型的数据元素(或记录)构成的集合。

对查找表进行的操作有:

(1)查询某个“特定的”数据元素是否存在查找表中。

(2)检索某个“特定的”数据元素的各种属性。

(3)在查找表中插入一个数据元素。

(4)从查找表中删除某个数据元素。


只做查询的操作的查找表称为静态查找表(Static Search Table)

若在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已存在的某个数据元素,则称此查找表为动态查找表(Dynamic Search Table)


关键字(Key)是数据元素(或记录)中某个数据项的值,用它可以标识一个数据元素(或记录),若此关键字可以唯一的标识一条记录,则称此关键字为主关键字(Primary Key),其他的用于识别若干记录的关键字称为次关键字(Secondary Key)。当数据元素只有一个数据项时,其关键字即为该数据元素的值。


查找(Searching)根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素。若表中存在这样的记录,则查找是成功的,若不存在,则查找不成功,给出“空”记录或空指针。


典型的关键字类型说明可以是:

typedef float KeyType; //实型
typedef int KeyType; //整型
typedef char *KeyType; //字符型

 数据元素类型定义为:

typedef struct{
    KeyType key; //关键字域
    ... //其他
}

 对两个关键字的比较的宏定义如下:

//--对数值型关键字
#define EQ(a,b) ((a) == (b))
#define LT(a,b) ((a) < (b))
#define LQ(a,b) ((a) <= (b))

...

//--对字符型关键字
#define EQ(a,b) (!strcmp((a),(b)))
#define LT(a,b) (strcmp((a),(b)) < 0)
#define LQ(a,b) (strcmp((a),(b)) <= 0)

1 静态查找表

抽象数据类型静态查找表定义如下:

ADT StaticSearchTable{
  数据对象D:D是具有相同特性的数据元素的集合,各个数据元素均含有类型相同的,可唯一标识数据元素的关键字。
  数据关系R:数据元素同属一个集合。
  基本操作P:
    Create(&ST,n);
      操作结构:构造一个含n个数据元素的静态查找表ST。
    Destroy(&ST);
      初始条件:静态查找表ST存在。
      操作结果:销毁表ST。
    Search(ST,key);
      初始条件:静态茶渣表ST存在,key为和关键字类型相同的给定值。
      操作结果:若ST中存在其关键字等于key的数据元素,则函数值为该元素的值或在表中的位置,否则为“空”。
    Traverse(ST,visit());
      初始条件:静态查找表ST存在,visit是对元素操作的应用函数。
      操作结果:按某种次序对ST的每隔元素调用函数visit()一次。
}ADT StaticSearchTable;

1.1 顺序表的查找

 

//----------- 静态查找表的顺序存储结构------------
typedef struct{
    Element *elem;//数据元素存储空间基址
    int length;
}SSTable;

顺序查找表的实现(Sequential Search)

    从表中最后一个记录开始,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值比较成功,则查找成功,反之,直到第一个记录,仍不能成功比较,则查找不成功。

 

int search_seq(SSTable ST,KeyType key){
    int i;
    //在顺序表ST中顺序查找其关键字=key的数据元素,
    //若找到,则函数值为该元素在表中的位置,否则为0.
    ST.elem[0].key = key;//哨兵
    for(i=ST.length;!ST.item[i].key == key;--i) //从后往前找
    return i; //找不到时,i =0
}//search_seq

查找操作的性能分析:

衡量一个算法好坏的量度有3条:

时间复杂度

空间复杂度(衡量算法的数据结构所占存储以及大量的附加存储)

算法的其他性能

通常以”其关键字和给定值进行过比较的记录个数的平均值“作为衡量查找算法好坏的依据。


平均查找长度(Average Search Length):为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望。

(1) 等概率的情况下顺序查找成功的平均查找长度为:

(n+1)/2

 

(2) 查找不成功的平均查找长度为

n+1

(3) 当查找不成功的概率不可以忽略时,假设查找成功和查找不成功的概率相同,则顺序查找的平均查找长度为:

3(n+1)/4

 

顺序查找的缺点:当n较大时,查找效率很低。

 

1.2 有序表的查找

折半查找(Binary Search):先确定待查记录所在的范围,然后逐步缩小范围直到找到或找不到记录为止。

顺序查找的查找过程如下:

(1) 确定待查记录所在的范围,设区间范围为[low,high];

(2) 求出处于该区间中间位置的值mid,mid = [low+high]/2;

(3) 将给定的key值与有序表中第mid个记录的关键字ST.item[mid].key相比较

(3.1) 若key == ST.item[mid].key,则查找成功

(3.2) 若key < ST.item[mid].key,则high=mid-1,并判断high是否小于low,若high<low,则查找不成功,否则,待查记录还是可能在新的区间[low,high]中,继续执行步骤(2)

(3.3) 若key > ST.item[mid].key,则low = mid + 1,判断high是否小于low,若high<low,则查找不成功,否则,待查记录还是可能在新的区间[low,high]中,继续执行步骤(2)。

算法实现如下:

 

int binarySearch(STable ST,KeyType key){
	int mid,low=0,high=ST.length;
	while(low <=high){
		mid = (low+high)/2;
		if(ST.item[mid].key == key) return mid;
		elseif(ST.item[mid].key < key) low = mid + 1;
		else high = mid - 1;
	}
	return 0;
}

 

折半查找的过程可以用二叉树表示,

判定树即描述查找过程的二叉树

折半查找时与给定值进行比较的次数最多为[log(2)n]+1次

(1) 查找成功时的平均查找长度:

ASL = (n+1)/n * log(2)(n+1) - 1

当n>50时,简化为

ASL = log(2)(n+1)-1

(2) 查找不成功时的平均查找长度

uASL = log(2)(n+1)


折半查找的优点:查找效率比顺序查找的高

缺点:只能适用于有序表,且顺序存储结构,不能用于线性链表

 

1.3 索引顺序表的查找

 

索引顺序表包括存储数据的顺序表(称为主表)和索引表两部分。顺序表被分为若干子表(又称块),整个顺序表有序或分块有序。将每个子表中的最大关键字取出,再加上指向该关键字记录所在子表第一个元素的指针,就构成一个索引项,将这些索引项按关键字增序排列,就构成了索引表。


对于索引顺序表可按分块进行查找,过程分为两个阶段:

(1) 确定待查记录所在的子表(块),由于索引表是按关键字有序排列的,对于索引表可按折半查找,若待查记录关键字的key值,<=第i个子表最大关键字,且大于第i-1个子表的最大关键字,即K(i-1) < key < K(i),则待查关键字位于第i个子表中。

(2) 在已确定的子表中确定待查记录的位置,由于子表中的记录不一定按关键字有序排列,只能按顺序查找法查找。


索引表类型定义如下:

 

#define MAXLEN <索引表最大长度>
typedef int keytype;
typedef struct{
    keytype key;
    int link;
}IndexType;//索引项数据类型
typedef IndexType IDX[MAXLEN+1];//索引表类型,下标从1开始

 

 索引表查找算法:

 

IndxSearch(IDX idx,int b,STable,keytype key){
    int s = ST.length / b; //b为索引表中元素个数,s为每个子表中元素个数
    int i,j;
    for(i=1;i<b+1;i++)
        if(key <= idx[i]) break;
    if(i == b+1) return 0;//从索引表中查找失败

    //注意,此处是从idx[i].link开始,不能设置0哨兵,只能用if判断j == idx[i].link-1
    for(j = idx[i].link+s-1;key!=ST.item[j].key;j--);
    if(j == idx[i].link-1) return 0;    
    else return j;
}
   

一般情况下,为进行分块查找,可以将长度为n的表均匀分成b块,每块还有s个元素,即b = [n/s],如果索引表采用顺序查找的方式,则查找成功时的平均查找长度为:

(s+b+2)/2

如果索引表采用折半查找,则成功时的平均查找长度为:

log(2)(n/s+1)+s/2

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值