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

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

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

              

        由上文可知,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



目录
相关文章
|
2月前
|
存储 算法
深入了解动态规划算法
深入了解动态规划算法
58 1
|
2月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
4月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
104 1
|
18天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
33 2
|
19天前
|
算法
树的遍历算法有哪些?
不同的遍历算法适用于不同的应用场景。深度优先搜索常用于搜索、路径查找等问题;广度优先搜索则在图的最短路径、层次相关的问题中较为常用;而二叉搜索树的遍历在数据排序、查找等方面有重要应用。
24 2
|
2月前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
69 2
动态规划算法学习三:0-1背包问题
|
2月前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
68 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
2月前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
144 0
动态规划算法学习二:最长公共子序列
|
2月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
24 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
2月前
|
存储 人工智能 算法
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)