动态规划——最优二叉检索树问题

最优二叉检索树问题

二叉检索树是二叉树当中经典的应用之一,广泛应用于实际生活的检索当中。如何构建一棵二叉树使得检索时的平均代价最低即构建最优二叉检索树,是一个问题。通过动态规划的思想可以对其进行解决。

问题描述

给定n个结点,构造一棵二叉检索树,使得检索的代价最低,即最优二叉检索树。

分析设计

二叉检索树的原理、特点、概念及代价在这里不再论述和证明,默认为已知。

要想使二叉检索树的检索代价最低,就是要使二叉树的**高度最小化。**因此我们就要选择合适的节点作为根节点。

利用动态规划的思想解决这个问题,我们首先要找到能划分的子问题,即节点减少时的二叉检索树。因此最优二叉检索树一定具有最优子结构的特征,去除根节点的剩下的部分任然是最优二叉检索树。

C ( i , j ) C(i,j) C(i,j)表示包含i…j节点的数的搜索代价,设这棵树的根节点为r,对应的左右子树分别是 i…r-1 和 r+1…j,它们对应的叶子分别为 i-1…dr-1和 r…j。树就构造完了,分为两种情况

  1. 只有一个叶子组成的子树 j=i-1, 只有i-1, 那么 C ( i , j ) = q i − 1 C(i,j)= q_i-1 C(i,j)=qi1 这个子树为1个叶节点 不再划分左右子树;
  2. 子树还包含关键字 即继续划分左右子树 i ≤ j i\leq j ij。那么 C ( i , j ) = m i n [ C ( i , r − 1 ) + C ( r + 1 , j ) + w ( i , j ) ] C(i ,j)= min[C(i, r-1) + C(r+1,j) + w(i,j) ] C(i,j)=min[C(i,r1)+C(r+1,j)+w(i,j)] 以r为根的代价中最小值,,即最优二叉检索树。

源代码

#include 


using namespace std;

//叶子结点
struct Leaf {
     
	int num;				//叶子的值
	double probability;		//叶子的概率
};

void OptimalBST(Leaf l[], int n, double **c, double **r) {
     
	double minval, sum;
	int kmin;
	//初始化树
	for (int i = 1; i < n + 1; i++) {
     
		c[i][i - 1] = 0;
		c[i][i] = l[i].probability;
		r[i][i] = i;
	}
	c[n + 1][n] = 0;
	for (int i = 1; i <= n - 1; i++) {
     
		for (int j = 1; j + i <= n; j++) {
     
			minval = INT_MAX;
			for (int k = j; k <= j + i; k++) {
     
				if (c[j][k - 1] + c[k + 1][j + i] < minval) {
     
					minval = c[j][k - 1] + c[k + 1][j + i];
					kmin = k;
				}
			}
			r[j][j + i] = kmin;
			sum = 0;
			for (int s = j; s <= j + i; s++)
				sum += l[s].probability;
			c[j][j + i] = minval + sum;
		}
	}
}

void Print(int start, int end, double **r) {
     
	if (start <= end) {
     
		int i = r[start][end];
		cout << i << " ";
		Print(start, i - 1, r);
		Print(i + 1, end, r);
	}
}

int main() {
     
	int n;
	cout << "输入叶子结点个数:";
	cin >> n;
	Leaf *l = new Leaf[n + 1];
	cout << "输入叶子结点信息;";
	for (int i = 1; i <= n; i++) {
     
		cin >> l[i].probability;
		l[i].num = i;
	}
		
	double **c = new double*[n + 2];		//主表
	for (int i = 0; i < n + 2; i++)
		c[i] = new double[n + 1];
	double **r = new double*[n + 2];		//根表
	for (int i = 0; i < n + 2; i++)
		r[i] = new double[n + 1];

	OptimalBST(l, n, c, r);
	cout << "该最优二叉检索树的期望为:" << c[1][n] << endl;
	cout << "中序遍历输出该二叉树:";
	Print(1,n,r);
	cout << endl;

	delete []l;
	for (int i = 0; i < n + 2; i++) 
		delete[]c[i];
	delete[]c;

	for (int i = 0; i < n + 2; i++)
		delete[]r[i];
	delete[]r;
	system("pause");
	return 0;
}

运行结果

动态规划——最优二叉检索树问题_第1张图片

你可能感兴趣的:(算法,#,动态规划,算法,动态规划)