查找表:同一类型元素或记录构成的集合。
对查找表的常用操作:
1)查找某个元素是否在表中;
2)检查某个元素的各个属性;
3)插入一个新数据元素;
4)删除某个数据元素。
静态查找表:只有前面两种查找操作的查找表;
动态查找表:除了静态功能之外在查找过程中可以插入不存在的元素或者删除已存在的数据元素。
关键字:数据元素或记录中某个数据项的值。若关键字标识具有唯一性,则称为主关键字。若是标识若干条记录不具有一对一特性,称为次关键字。
平均查找长度(ASL):为确定记录在查找表中的位置,需要和定值进行比较的关键字个数的期望值。
如顺序查找表:查找第一个元素比较n次;
查找最后一个元素,比较一次;
ASL=查找到的概率*比较次数;
若n=ST.length,则顺序查找的平均长度为
ASL=nP1+(n-1)P2+............2Pn-1+Pn;
【静态查找表】
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
// bo9-1.cpp 静态查找表(顺序表和有序表)的基本操作(7个)
Status Creat_Seq(SSTable &ST,int n)
{ // 操作结果: 构造一个含n个数据元素的静态顺序查找表ST(数据来自全局数组r)
int i;
ST.elem=(ElemType*)calloc(n+1,sizeof(ElemType)); // 动态生成n个数据元素空间(0号单元不用)
if(!ST.elem)
return ERROR;
for(i=1;i<=n;i++)
*(ST.elem+i)=r[i-1]; // 将全局数组r的值依次赋给ST
ST.length=n;
return OK;
}
void Ascend(SSTable &ST)
{ // 重建静态查找表为按关键字非降序排序
int i,j,k;
for(i=1;i<ST.length;i++)
{
k=i;
ST.elem[0]=ST.elem[i]; // 待比较值存[0]单元
for(j=i+1;j<=ST.length;j++)
if LT(ST.elem[j].key,ST.elem[0].key)
{
k=j;
ST.elem[0]=ST.elem[j];
}
if(k!=i) // 有更小的值则交换
{
ST.elem[k]=ST.elem[i];
ST.elem[i]=ST.elem[0];
}
}
}
Status Creat_Ord(SSTable &ST,int n)
{ // 操作结果: 构造一个含n个数据元素的静态按关键字非降序查找表ST
// 数据来自全局数组r
Status f;
f=Creat_Seq(ST,n);
if(f)
Ascend(ST);
return f;
}
Status Destroy(SSTable &ST)
{ // 初始条件: 静态查找表ST存在。操作结果: 销毁表ST
free(ST.elem);
ST.elem=NULL;
ST.length=0;
return OK;
}
int Search_Seq(SSTable ST,KeyType key)
{ // 在顺序表ST中顺序查找其关键字等于key的数据元素。若找到,则函数值为
// 该元素在表中的位置,否则为0。算法9.1
int i;
ST.elem[0].key=key; // 哨兵
for(i=ST.length;!EQ(ST.elem[i].key,key);--i); // 从后往前找
return i; // 找不到时,i为0
}
int Search_Bin(SSTable ST,KeyType key)
{ // 在有序表ST中折半查找其关键字等于key的数据元素。若找到,则函数值为
// 该元素在表中的位置,否则为0。算法9.2
int low,high,mid;
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; // 顺序表中不存在待查元素
}
Status Traverse(SSTable ST,void(*Visit)(ElemType))
{ // 初始条件: 静态查找表ST存在,Visit()是对元素操作的应用函数
// 操作结果: 按顺序对ST的每个元素调用函数Visit()一次且仅一次。
// 一旦Visit()失败,则操作失败
ElemType *p;
int i;
p=++ST.elem; // p指向第一个元素
for(i=1;i<=ST.length;i++)
Visit(*p++);
return OK;
}
【动态查找表】
typedef struct BiTNode
{
TElemType data;
BiTNode *lchild,*rchild; // 左右孩子指针
}BiTNode,*BiTree;
Status InitDSTable(BiTree &DT) // 同bo6-2.cpp
{ // 操作结果: 构造一个空的动态查找表DT
DT=NULL;
return OK;
}
void DestroyDSTable(BiTree &DT) // 同bo6-2.cpp
{ // 初始条件: 动态查找表DT存在。操作结果: 销毁动态查找表DT
if(DT) // 非空树
{
if(DT->lchild) // 有左孩子
DestroyDSTable(DT->lchild); // 销毁左孩子子树
if(DT->rchild) // 有右孩子
DestroyDSTable(DT->rchild); // 销毁右孩子子树
free(DT); // 释放根结点
DT=NULL; // 空指针赋0
}
}
BiTree SearchBST(BiTree T,KeyType key)
{ // 在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素,
// 若查找成功,则返回指向该数据元素结点的指针,否则返回空指针。算法9.5(a)
if((!T)||EQ(key,T->data.key))
return T; // 查找结束
else if LT(key,T->data.key) // 在左子树中继续查找
return SearchBST(T->lchild,key);
else
return SearchBST(T->rchild,key); // 在右子树中继续查找
}
void SearchBST(BiTree &T,KeyType key,BiTree f,BiTree &p,Status &flag) // 算法9.5(b)改
{ // 在根指针T所指二叉排序树中递归地查找其关键字等于key的数据元素,若查找
// 成功,则指针p指向该数据元素结点,并返回TRUE,否则指针p指向查找路径上
// 访问的最后一个结点并返回FALSE,指针f指向T的双亲,其初始调用值为NULL
if(!T) // 查找不成功
{
p=f;
flag=FALSE;
}
else if EQ(key,T->data.key) // 查找成功
{
p=T;
flag=TRUE;
}
else if LT(key,T->data.key)
SearchBST(T->lchild,key,T,p,flag); // 在左子树中继续查找
else
SearchBST(T->rchild,key,T,p,flag); // 在右子树中继续查找
}
Status InsertBST(BiTree &T, ElemType e)
{ // 当二叉排序树T中不存在关键字等于e.key的数据元素时,插入e并返回TRUE,
// 否则返回FALSE。算法9.6(改)
BiTree p,s;
Status flag;
SearchBST(T,e.key,NULL,p,flag);
if(!flag) // 查找不成功
{
s=(BiTree)malloc(sizeof(BiTNode));
s->data=e;
s->lchild=s->rchild=NULL;
if(!p)
T=s; // 被插结点*s为新的根结点
else if LT(e.key,p->data.key)
p->lchild=s; // 被插结点*s为左孩子
else
p->rchild=s; // 被插结点*s为右孩子
return TRUE;
}
else
return FALSE; // 树中已有关键字相同的结点,不再插入
}
void Delete(BiTree &p)
{ // 从二叉排序树中删除结点p,并重接它的左或右子树。算法9.8
BiTree q,s;
if(!p->rchild) // 右子树空则只需重接它的左子树(待删结点是叶子也走此分支)
{
q=p;
p=p->lchild;
free(q);
}
else if(!p->lchild) // 只需重接它的右子树
{
q=p;
p=p->rchild;
free(q);
}
else // 左右子树均不空
{
q=p;
s=p->lchild;
while(s->rchild) // 转左,然后向右到尽头(找待删结点的前驱)
{
q=s;
s=s->rchild;
}
p->data=s->data; // s指向被删结点的"前驱"(将被删结点前驱的值取代被删结点的值)
if(q!=p)
q->rchild=s->lchild; // 重接*q的右子树
else
q->lchild=s->lchild; // 重接*q的左子树
free(s);
}
}
Status DeleteBST(BiTree &T,KeyType key)
{ // 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点,
// 并返回TRUE;否则返回FALSE。算法9.7
if(!T) // 不存在关键字等于key的数据元素
return FALSE;
else
{
if EQ(key,T->data.key) // 找到关键字等于key的数据元素
Delete(T);
else if LT(key,T->data.key)
DeleteBST(T->lchild,key);
else
DeleteBST(T->rchild,key);
return TRUE;
}
}
void TraverseDSTable(BiTree DT,void(*Visit)(ElemType))
{ // 初始条件: 动态查找表DT存在,Visit是对结点操作的应用函数
// 操作结果: 按关键字的顺序对DT的每个结点调用函数Visit()一次且至多一次
if(DT)
{
TraverseDSTable(DT->lchild,Visit); // 先中序遍历左子树
Visit(DT->data); // 再访问根结点
TraverseDSTable(DT->rchild,Visit); // 最后中序遍历右子树
}
}