第九章查找表
查找表:是由同一类型的数据元素(或记录)构成的集合。
对查找表经常进行的操作:
1) 查询某个“特定的”数据元素是否在查找表中;
2) 检索某个“特定的”数据元素的各种属性
3) 在查找表中插入一个数据元素
4) 从查找表中删去某个数据元素
静态查找表
仅作查询和检索操作的查找表
动态查找表
有时在查询之后,还需要将“查询”结果为“不再查找表中”的数据元素插入查找表;或者,从查找表中删除其“查询”结果为“在查找表中的”数据元素。
查找
根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素或(记录)
关键字
是数据元素(或记录)中某个数据项的值,用以标识(识别)一个数据元素(或记录)。
若此关键字可以识别唯一的一个记录,则称之谓“主关键字”。
若此关键字能识别若干记录,则称之谓“次关键字”。
若查找表中存在一个这样的记录,则称“查找成功”,查找结果:给出整个记录的信息,或指示该记录在查找表中的位置;否则称“查找不成功”,查找结果:给出“空记录”或“空指针”。
如何进行查找?
取决于查找表的结构。
然而,查找表本身是一种很松散的结构,因此,为了提高查找的效率,需要在查找表中的元素之间认为地附加某种确定的关系,换句话说,用另外一种结构来表示查找表。
9.1静态查找表
ADT StaticSearchTable
{
数据对象D:D是具有相同特性的数据元素的集合,每个数据元素含有类型相同的关键字,可唯一标识数据元素。
数据关系R:数据元素同属一个集合。
}ADTStaticSearchTable
基本操作:
Create(&ST, n);
Destroy(&ST);
Search(ST,key);
Traverse(ST, Visit());
Search(ST, key);
初始条件:静态查找表ST存在,key为和查找表中元素的关键字类型相同的给定值;
操作结果:若ST中存在其关键字等于key的数据元素,则函数值为该元素的值或在表中的位置,否则为“空”。
Traverse(ST,Visit());
初始条件:静态查找表ST存在,Visit()是对元素操作的应用函数;
操作结果:按某种次序对ST的每个元素调用函数Visit()一次且仅一次,一旦Visit()失败,则操作失败。
假设静态查找表的顺序存储结构为
34_001 |
typedef struct { ElemType *elem; //数据元素存储空间基址,建表时按实际长度分配,0好单元留空 int length; //表的长度 }SSTable; |
一、顺序查找表二、有序查找表三、静态查找树表四、索引顺序表
一、顺序查找表
以顺序表后线性链表表示静态查找表
Key=?ST.elem[k]
34_002 |
int location(SqList L, ElemType &e, Status(* compare)(ElemType, ElemType)) { k = 1; p = L.elem; while(k <= L.length && !(* compare)(*p ++, e))) k ++; if(k <= L.length) return k; else return 0; }//location |
人为的给位置为0的元素赋值为要查找的值。可以防止指针越界
34_003 |
int Search_Seq(SSTable ST, KeyType key) { //在顺序表ST中顺序查找其关键字等于key的数据元素,若找到, //则函数值为该元素在表中的位置,否则为0 ST.elem[0].key = key; //哨兵 for(i = ST.length; ST.elem[i].key != key; -- i); //从后往前找 return i; //找不到时,i为0 }//Search_Seq |
分析顺序查找的时间性能。
定义:查找算法的平均查找长度(AverageSearchLength)为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值,其中:n为表长,pi为查找表中第i个记录的概率为找到该记录时,称和给定值比较过的关键字的个数。
若查找表概率无法事先测定,则查找过程采取的改进办法是,在每次查找之后,将刚刚查找到的记录直接移至表尾的位置上。
一、有序查找表
上述顺序查找表的查找算法简单,但平均查找长度较大,特别不适合用于较大的查找表。
折半查找
34_004 |
int Search_Bin(SSTable ST, KeyType key) { low = 1; high = ST.length; //置区间初值 while(low <= high) { mid = (low + high) / 2; if( EQ(key, ST.elem[mid].key) ) return mid; //找到待查元素 else if( LT(key, ST.elem[mid].key) ) high = mid - 1; //继续在前半区间进行查找 else low = mid + 1; //继续在后半区间进行查找 } return 0; //顺序表中不存在待查元素 }//Search_Bin |
分析折半查找的平均查找长度
先看一下具体情况,假设n=11
一般情况下,表长为n的折半查找的判定树的深度和含有n个结点的完全二叉树的深度相同。
三、静态查找树表
不等概率查找的情况下,折半查找不是最好的查找方法
定义:
介绍一种次优二叉树的构造方法:(只考虑查找成功的情况)
构造次优二叉树的算法
35_001 |
Status SecondOptimal(BiTree &T, ElemType R[], float sw[], int low, int high) { //由有序表R[low, high]及其累计权值表sw //递归构造次优查找树T //选择最小的△pi值 if(! (T = (BiTree) malloc(sizeof(sizeof(BiTNode)))) return ERROR; T->data = R[i]; //生成结点 if(i == low) T->lchild = NULL; //左子树空 else SecondOptimal(T->lchild, R, sw, low, i-1); //构造左子树 if(i == high) T->rchild = NULL; //右子树空 else SecondOptimal(T->rchild, R, sw, i+1, high); //构造右子树 return OK; }//SecondOptimal |
四、索引顺序表
对比顺序表和有序表的查找性能之差别:
| 顺序表 | 有序表 |
表的特性 | 无序表 | 有序表 |
存储结构 | 顺序结构或链表结构 | 顺序结构 |
插删操作 | 易于进行 | 需移动元素 |
ASL值 | 大 | 小 |
索引顺序表=索引+顺序表一般情况下,索引是一个有序表
查找方法:
1) 由索引确定记录所在区间
2) 在顺序表的某个区间内进行查找
所以,这也是一种缩小区间的查找方法。
索引顺序表的平均查找长度为在索引中进行查找的平均查找长度和在顺序表中进行查找的平均查找长度之和。