【算法导论】动态规划之最优二叉查找树

简介:         如果我们想写一个单词查询的软件的话,我们的目的就是让查询的总时间最短,我们首先想到用之前的二叉查找树。我们可以用红黑树或者其它的平衡二叉树来保证每个单词的搜索时间。

        如果我们想写一个单词查询的软件的话,我们的目的就是让查询的总时间最短,我们首先想到用之前的二叉查找树。我们可以用红黑树或者其它的平衡二叉树来保证每个单词的搜索时间。但是每个单词出现的频率一般不同,因此我们希望把频率较大的单词放在离根比较近的地方,频率较小的放在离叶子较近的地方。而且,我们所要查询的单词词库中没有,这也值得考虑。

              

        由上文可知,ki表示单词,di表示不能查到的情况。由上面的例子可知,一棵最优二叉树不一定是高度最小的树。我们也不一定总把频率最大的放在根部。

        和矩阵链乘法一样,穷举所有的可能行肯定不是一个好的算法。由于具有动态规划的特征,毫无疑问,我们将使用动态规划法。

        对于原序列,我们假设第k个元素(采用遍历的方法)作为根时可以得到最优解,由于是二叉查询树,则前k-1个元素在左子树,剩余元素在右子树。接下来,我们要分别在左、右子树中找到最优二叉树,于是我们可以用相同的方法:假设左、右子树中第m,n个为根时,可以得到最优解,依此类推,就可以求得整体最优解。上面的解法中,可能存在左或者右子树为空的情况:


通过推导,可以递推公式:


其中e表示搜索的代价,q[i]为d[i]的出现频率,w为子树总的概率。

具体程序实现如下:

#include<stdio.h>
#define N 7
void Optimal_Bst(float *p,float *q,int n,float e[][N],int root[][N]);

void main()
{
	float p[]={0,0.15,0.1,0.05,0.1,0.2};//关键字出现的概率
	float q[]={0.05,0.1,0.05,0.05,0.05,0.1};//搜索不到关键字的几种情况的概率
	int n=6;//关键字个数
	float e[N][N]={0};//存储搜索的代价
	int root[N][N]={0};//子树的根,便于重构最优二叉树
	Optimal_Bst(p,q,n,e,root);
	for(int i=1;i<6;i++)
		for(int j=5;j>=i;j--)
			printf("从第%d个元素到第%d个元素的最优二叉查找树的顶点为:%d\n",i,j,root[i][j]);
}

void Optimal_Bst(float *p,float *q,int n,float e[][N],int root[][N])
{
	float w[N][N]={0};
	float t=0;
	for(int i=1;i<=n;i++)//左右子树为空的情况
	{
		e[i][i-1]=q[i-1];
		w[i][i-1]=q[i-1];
	}
	for(int l=1;l<=n;l++)
		for(int i=1;i<=n-l+1;i++)
		{
			int j=0;
			j=i+l-1;
			e[i][j]=10000;//初始化为很大的值,可以随意设置
			w[i][j]=w[i][j-1]+p[j]+q[j];//
			
			for(int r=i;r<=j;r++)//r代表以下标r为根,r在所有的子树节点中遍历
			{
				t=e[i][r-1]+e[r+1][j]+w[i][j];
				if(t<e[i][j])
				{
					e[i][j]=t;
					root[i][j]=r;//得到最优二叉树时的根
					
				}
					
			}
		}
}
上述程序运行后,数组e,w,root的结果如下:


上述程序的运行时间为O(n^3),这和前面的矩阵链乘法是一样的。


原文:http://blog.csdn.net/tengweitw/article/details/16972241

作者:nineheadedbird



目录
相关文章
|
27天前
|
存储 算法
深入了解动态规划算法
深入了解动态规划算法
47 1
|
27天前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
3月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
92 1
|
4月前
|
算法 开发者 Python
惊呆了!Python算法设计与分析,分治法、贪心、动态规划...这些你都会了吗?不会?那还不快来学!
【7月更文挑战第10天】探索编程巅峰,算法至关重要。Python以其易读性成为学习算法的首选。分治法,如归并排序,将大问题拆解;贪心算法,如找零问题,每步求局部最优;动态规划,如斐波那契数列,利用子问题解。通过示例代码,理解并掌握这些算法,提升编程技能,面对挑战更加从容。动手实践,体验算法的神奇力量吧!
70 8
|
17天前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
46 2
动态规划算法学习三:0-1背包问题
|
17天前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
50 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
17天前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
69 0
动态规划算法学习二:最长公共子序列
|
20天前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
14 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
27天前
|
存储 人工智能 算法
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
|
2月前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
49 2