1. 引言
本文主要讲解静态查找表。静态查找表在查找的过程中不改变表的状态——不插不删。他适合用于不变动或不常变动的表的查
找。如高考成绩表、本单位职工信息表等。下面分别介绍顺序查找,有序表的折半查找,静态树表的查找。
2. 静态查找表
(1)顺序查找、有序表的折半查找
#include "ds.h" #define TEST_BIN #define EQ(a, b) ((a) == (b)) #define LT(a, b) ((a) < (b)) #define LQ(a, b) ((a) <= (b)) #define key number #define N 5 typedef long KeyType; struct ElemType { long number; char name[13]; int politics; int Chinese; int English; int math; int physics; int chemistry; int biology; int total; }; struct SSTable { ElemType *elem; int length; }; void Creat_Seq(SSTable &ST, ElemType r[], int n) { int i; ST.elem = (ElemType*)malloc(sizeof(ElemType)*(n+1)); if (!ST.elem) exit(OVERFLOW); for (i = 1; i <= n; ++i) { ST.elem[i] = r[i-1]; } ST.length = n; } void Ascend(SSTable &ST) { int i, j, k; for (i = 1; i <= ST.length; ++i) { k = i; ST.elem[0] = ST.elem[i]; 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]; } } } void Creat_Ord(SSTable &ST, ElemType r[], int n) { Creat_Seq(ST, r, n); Ascend(ST); } void Destroy(SSTable &ST) { if (ST.elem) free(ST.elem); ST.elem = NULL; ST.length = 0; } int Search_Seq(SSTable ST, KeyType key) { int i; for (i = ST.length; !EQ(key, ST.elem[i].key); --i); return i; } int Search_Bin(SSTable ST, KeyType key) { int low, mid, high; low = 1; high = ST.length; while (low <= high) { mid = (low + high)/2; if EQ(ST.elem[mid].key, key) return mid; else if LT(ST.elem[mid].key, key) low = mid + 1; else high = mid - 1; } return 0; } void Traverse(SSTable ST, void (*visit)(ElemType)) { int i; ElemType *p; p = ++ST.elem; for (i = 1; i <= ST.length; ++i) visit(*p++); } void print(ElemType c) // Traverse()调用的函数 { printf("%-8ld%-12s%4d%5d%5d%5d%5d%5d%5d%5d\n",c.number,c.name,c.politics, c.Chinese,c.English,c.math,c.physics,c.chemistry,c.biology,c.total); } int main() { ElemType r[N] = { {179328,"hefangfang",85,89,98,100,93,80,47}, {179325,"chenhong",85,86,88,100,92,90,45}, {179326,"luhua",78,75,90,80,95,88,37}, {179327,"zhangping",82,80,78,98,84,96,40}, {179324,"zhaoxiaoyi",76,85,94,57,77,69,44}}; // 数组不按关键字有序 SSTable st; int i; long s; for(i=0;i<N;i++) // 计算总分 r[i].total=r[i].politics+r[i].Chinese+r[i].English+r[i].math+r[i].physics+ r[i].chemistry+r[i].biology; #ifdef TEST_BIN Creat_Ord(st,r,N); // 由数组r产生非降序静态查找表st #else Creat_Seq(st,r,N); // 由数组r产生顺序静态查找表st #endif printf("准考证号 姓名 政治 语文 外语 数学 物理 化学 生物 总分\n"); Traverse(st,print); // 按顺序输出静态查找表st printf("请输入待查找人的考号: "); scanf("%ld",&s); #ifdef TEST_BIN i=Search_Bin(st,s); // 折半查找 #else i=Search_Seq(st,s); // 顺序查找 #endif if(i) print(st.elem[i]); else printf("没找到\n"); Destroy(st); }
(2)静态树表的查找
静态树表是把有序的静态查找表根据数据被查找的概率生成一棵二叉树,使得从二叉树的根结点起,查找左右子树的概率大致相等,使平均查找长度较短。若每个数据的查找的概率相等,直接使用折半法即可,不必生成二叉树。
#include "ds.h"
#define EQ(a, b) ((a) == (b))
#define LT(a, b) ((a) < (b))
#define LQ(a, b) ((a) <= (b))
#define N 9
typedef char KeyType;
struct ElemType
{
KeyType key;
int weight;
};
struct SSTable
{
ElemType *elem; // 数据元素存储空间基址,建表时按实际长度分配,0号单元留空
int length; // 表长度
};
typedef ElemType TElemType;
typedef struct BiTNode
{
TElemType data;
BiTNode *lchild, *rchild; // 左右孩子指针
}BiTNode,*BiTree;
void Creat_Seq(SSTable &ST, ElemType r[], int n)
{
int i;
ST.elem = (ElemType*)malloc(sizeof(ElemType)*(n+1));
if (!ST.elem) exit(OVERFLOW);
for (i = 1; i <= n; ++i)
{
ST.elem[i] = r[i-1];
}
ST.length = n;
}
void Ascend(SSTable &ST)
{
int i, j, k;
for (i = 1; i <= ST.length; ++i)
{
k = i;
ST.elem[0] = ST.elem[i];
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];
}
}
}
void Creat_Ord(SSTable &ST, ElemType r[], int n)
{
Creat_Seq(ST, r, n);
Ascend(ST);
}
void Destroy(SSTable &ST)
{
if (ST.elem)
free(ST.elem);
ST.elem = NULL;
ST.length = 0;
}
int Search_Seq(SSTable ST, KeyType key)
{
int i;
for (i = ST.length; !EQ(key, ST.elem[i].key); --i);
return i;
}
int Search_Bin(SSTable ST, KeyType key)
{
int low, mid, high;
low = 1;
high = ST.length;
while (low <= high)
{
mid = (low + high)/2;
if EQ(ST.elem[mid].key, key)
return mid;
else if LT(ST.elem[mid].key, key)
low = mid + 1;
else
high = mid - 1;
}
return 0;
}
void Traverse(SSTable ST, void (*visit)(ElemType))
{
int i;
ElemType *p;
p = ++ST.elem;
for (i = 1; i <= ST.length; ++i)
visit(*p++);
}
// 由有序表R[low..high]及其累计权值表sw(其中sw[0]==0)递归构造次优查找树T。算法9.3
Status SecondOptimal(BiTree &T, ElemType R[], int sw[], int low, int high)
{
int i, j;
double min, dw;
i = low;
min = fabs(sw[high] - sw[low]);
dw = sw[high] + sw[low - 1];
for (j = low + 1; j < high; ++j) // 选择最小的△Pi值
if (fabs(dw-sw[j]-sw[j-1]) < min)
{
i = j;
min = fabs(dw-sw[j]-sw[j-1]);
}
if(!(T=(BiTree)malloc(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;
}
void FindSW(int sw[], SSTable ST)
{
int i;
sw[0] = 0;
for (i = 1; i <= ST.length; i++)
sw[i] = sw[i - 1] + ST.elem[i].weight;
}
typedef BiTree SOSTree; // 次优查找树采用二叉链表的存储结构
void CreateSOSTree(SOSTree &T,SSTable ST)
{ // 由有序表ST构造一棵次优查找树T。ST的数据元素含有权域weight。算法9.4
int sw[N+1]; // 累计权值
if(ST.length==0)
T=NULL;
else
{
FindSW(sw,ST); // 按照有序表ST中各数据元素的weight域求累计权值表sw
SecondOptimal(T,ST.elem,sw,1,ST.length);
}
}
// 在次优查找树T中查找关键字等于key的元素。找到则返回OK,否则返回FALSE
Status Search_SOSTree(SOSTree &T,KeyType key)
{
while(T) // T非空
if(T->data.key==key)
return OK;
else if(T->data.key>key)
T=T->lchild;
else
T=T->rchild;
return FALSE; // 顺序表中不存在待查元素
}
void print(ElemType c) // Traverse()调用的函数
{
printf("(%c %d) ",c.key,c.weight);
}
int main()
{
SSTable st;
SOSTree t;
Status i;
KeyType s; // 以教科书例9-1的数据为例
ElemType r[N]={{'A',1},{'B',1},{'C',2},{'D',5},{'E',3},{'F',4},{'G',4},{'H',3},{'I',5}};
Creat_Ord(st,r,N); // 由全局数组产生非降序静态查找表st
Traverse(st,print);
CreateSOSTree(t,st); // 由有序表构造一棵次优查找树
printf("\n请输入待查找的字符: ");
scanf("%c",&s);
i=Search_SOSTree(t,s);
if(i)
printf("%c的权值是%d\n",s,t->data.weight);
else
printf("表中不存在此字符\n");
}