静态树表的查找
对于有序表的静态查找,有两种常见的方法,一是折半查找,也就是通常所说的二分法;另外一种是次优查找树。折半查找比较简单,这里就不说了,主要是讲讲次优查找树的建立,以及查找。
说到次优查找树,很多人就会想为什么是“次优”呢,那最优呢?最优查找树确实是存在的,但是因为它的时间复杂度达到了O(n^6),所以在实际应用中很少使用。而次优查找树虽然平均查找次数多余最优查找树,但是两者性能之差仅为1%~2%,很少超过3%,而且构造次优查找树的时间复杂度为O(nlog(n)),是一种近似最右二叉查找树的有效算法。
下面以一个序列来推导构造次优查找树的方法:
已知一个按关键字有序的记录序列
(R(l), R(l+1),........R(h)) (式1-1)
其中
R(l).key < R(l+1).key<.....<R(h).key,(式1-2)
即该序列是有序的,
而且每个记录的权值为
W(l), W(l+1),......W(h) (式1-3)
现构造一棵二叉树,使其查找性能近似于最优二叉树。
构造次优二叉树的方法是:首先在(式1-1)所示的记录序列中取第i(l<=i<=h)个记录中构造根节点Ri,使得
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define NODE_SIZE 10 //节点数目
typedef struct SSTable
{
char key[NODE_SIZE]; //关键字
int weight[NODE_SIZE]; //权值
int length; //关键字数
}SSTable;
typedef struct BiTree
{
char key;
struct BiTree *lchild, *rchild;
}BiTree;
int count = 0; //记录查找次数
typedef BiTree SOSTree; //次优二叉树采用二叉链表的存储结果
void InitBTree(SOSTree *T); //构造一棵空树
void InitSSTable(SSTable *ST);
void CreateSOSTree(SOSTree *T, SSTable *ST); //SSTable 次优查找二叉树
void FindSW(int sw[], SSTable *ST);
void SecondOpiamal(SOSTree **T, SSTable *ST, int *sw, int low, int high);
void SearchNode(SOSTree **T, char key);
int main()
{
BiTree T;
SSTable ST;
int sw[NODE_SIZE] = { 0 };
InitBTree(&T);
InitSSTable(&ST);
CreateSOSTree(&T, &ST);
return 0;
}
//构造一棵空树
void InitBTree(SOSTree *T)
{
T = NULL;
}
//存放关键字的有序表
void InitSSTable(SSTable *ST)
{
int i = 0;
printf("input SSTable node num:\n");
scanf("%d", &(ST->length));
for (i = 1; i < ST->length; i++)
{
getchar();
printf("input keyword, weight:");
scanf("%c%d", &(ST->key[i]), &(ST->weight[i]));
}
}
void FindSW(int sw[], SSTable *ST)
{
int i, j;
sw[0] = 0;
for (i = 1; i < ST->length; i++)
{
sw[i] = 0;
for (j = 1; j <= i; j++) //可优化为sw[i] = sw[i - 1] + ST->weight[i];
{ //sw数组全部初始化为0
sw[i] += ST->weight[j];
}
}
}//SSTable 次优查找二叉树
void CreateSOSTree(SOSTree *T, SSTable *ST)
{
int sw[NODE_SIZE] = { 0 };
if (ST->length == 0)
T = NULL;
else
{
char key;
FindSW(sw, ST); //按照有序表ST中个数据元素的weight域求累计权值表sw
SecondOpiamal(&T, ST, sw, 1, ST->length - 1);
getchar();
printf("input search node:\n");
scanf("%c", &key);
SearchNode(&T, key);
printf("%d\n", count);
}
}
void SecondOpiamal(SOSTree **T, SSTable *ST, int *sw, int low, int high)
{
int i, j;
i = low;
//初始时原式应该为sw[high] + sw[low - 1] - sw[low] - sw[low - 1] = sw[high] - sw[low]
int min = abs(sw[high] - sw[low]);
int dw = sw[high] + sw[low - 1];
for (j = low + 1; j < high; j++)
{
if (abs(dw - sw[j] - sw[j - 1]) < min)
{
i = j;
min = abs(dw - sw[j] - sw[j - 1]);
}
}
*T = (BiTree *)malloc(sizeof(BiTree)); //为根节点分配空间
(*T)->key = ST->key[i];
if (i == low) //说明当前根节点没有左子树
{
(*T)->lchild = NULL;
}
else
{
SecondOpiamal(&(*T)->lchild, ST, sw, low, i - 1);
}
if (i == high) //说明当前根节点没有右子树
{
(*T)->rchild = NULL;
}
else
{
SecondOpiamal(&(*T)->rchild, ST, sw, i + 1, high);
}
}
void SearchNode(SOSTree **T, char key)
{
count++;
if ((*T)->key == key)
{
printf("查找成功\n");
}
else if((*T)->key < key)
{
SearchNode(&(*T)->lchild, key);
}
else
{
SearchNode(&(*T)->lchild, key);
}
}