次优查找树(Nearly Optimal Search Tree)

静态树表的查找
          对于有序表的静态查找,有两种常见的方法,一是折半查找,也就是通常所说的二分法;另外一种是次优查找树。折半查找比较简单,这里就不说了,主要是讲讲次优查找树的建立,以及查找。
       说到次优查找树,很多人就会想为什么是“次优”呢,那最优呢?最优查找树确实是存在的,但是因为它的时间复杂度达到了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);
	}
}










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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值