数据结构与算法分析-C++描述 第10章 算法设计技巧(动态规整之最优二叉搜索树)

算法设计技巧三:动态规整(dynamic programming)

        在上篇分治算法中看到,一个可以被数学上递归表示的问题也可以表示成递归算法,在许多情况下对朴素的穷举搜索得到显著的性能改进。由于编译器常常不能正确对待递归算法,结果产生低效的程序。将递归算法改写成非递归的方式,将子问题的答案系统地记录在一张表中,这种算法技巧称为动态规整。

用表代替递归:

        使用递归算法实现斐波拉契程序算法,每次递归将耗费存储当前结果,递归存储每次运算结果:

int fib(int N){
    if(N <= 1){
        return 1;
    }
    else{
        return fib(N-1) + fib(N-2);
    }
}

        改进的斐波拉契算法使用非递归算法,只调用一次程序,减少内存消耗:

int fib(int N){
    if(N <= 1){
        return 1;
    }
    int last = 1;
    int nextToLast = 1;
    int answer = 1;
    for(int i = 2; i <= N; i++){
        answer = last + nextToLast;
        nextToLast = last;
        last = answer;
    }
     return answer;
}

        动态规整的更多应用如矩阵乘法运算量穷举、最优二叉查找树实现以及非递归的最近点对问题。本篇将重点介绍基于动态规整的最优二叉查找树实现。

最优二叉查找树:

       给定n个互异的关键字组成的序列K=,且关键字有序(k1

最优二叉查找树子结构:

       如果一棵最优二叉查找树T有一棵包含关键字ki,..,kj的子树T',那么这可子树T'对于关键字Ki,...,kj和虚拟键di-1,...dj的子问题也必定是最优的。

    定义概率和:w(i,j) = \sum_{l=i}^jp_l +\sum_{l=i}^{j}q_l

    定义以k_r为子树的期望搜索代价:e(i,j) = p_r + (e(i,r-1)+e(r+1,j) + w(i,r-1)+w(r+1,j))

    w(i,j)的递推关系为:w(i,j) = p_r + w(i, k-1) +w(k+1,j)

    则搜索代价表达式为:e(i,j) = e(i,r-1)+e(r+1,j)+w(i,j)

    最优二叉查找树的目的在于求解最小e(i,j),其表达式为:e(i,j) = \begin{Bmatrix} q_{i-1} & j = i-1 \\ min(e(i,j))& i\leq j \end{Bmatrix}

最优二叉查找树编程实现:

//main.cpp
#include 

using namespace std;

const int MaxVal = 9999;

const int n = 5;

//pi and qi array
double p[n + 1] = {-1,0.15,0.1,0.05,0.1,0.2};
double q[n + 1] = {0.05,0.1,0.05,0.05,0.05,0.1};

int root[n + 1][n + 1];		//root array
double w[n + 2][n + 2];		//w[i][j]
double e[n + 2][n + 2];		//e[i][j]
 
void optimalBST(double *p,double *q,int n)
{
	//init w and e
	for (int i = 1;i <= n + 1;++i)
	{
		w[i][i - 1] = q[i - 1];
		e[i][i - 1] = q[i - 1];
	}
	//dynamic programming
	for (int len = 1;len <= n;++len)
	{
		for (int i = 1;i <= n - len + 1;++i)
		{
			int j = i + len - 1;
			e[i][j] = MaxVal;
			//define w[i][j]
			w[i][j] = w[i][j - 1] + p[j] + q[j];
			//find the best BST
			for (int k = i;k <= j;++k)
			{
				double temp = e[i][k - 1] + e[k + 1][j] + w[i][j];
				if (temp < e[i][j])
				{
					e[i][j] = temp;
					root[i][j] = k;
				}
			}
		}
	}
}

//printRoot
void printRoot()
{
	cout << "The root info  : " << endl;
	for (int i = 1;i <= n;++i)
	{
		for (int j = 1;j <= n;++j)
		{
			cout << root[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
}

//printOptimalBST
void printOptimalBST(int i,int j,int r)
{
	//i, j is rootChild
	int rootChild = root[i][j];
	if (rootChild == root[1][n])
	{	
		//output the root
		cout << "Root is : " << rootChild << endl;
		printOptimalBST(i,rootChild - 1,rootChild);
		printOptimalBST(rootChild + 1,j,rootChild);
		return;
	}
 
	if (j < i - 1)
	{
		return;
	}
	//when j = i - 1, the leaf is qi
	else if (j == i - 1)
	{
		if (j < r){
			cout << r << " 's leftChild : " << j << endl;
		}
		else{
			cout << r << " 's rightChild : " << j << endl;
		}
		return;
	}else{
		if (rootChild < r)
		{
			cout << r << " 's leftChild : " << rootChild << endl;
		}
		else{
			cout << r << " 's rightChild : " << rootChild << endl;
		}
	}
	printOptimalBST(i,rootChild - 1,rootChild);
	printOptimalBST(rootChild + 1,j,rootChild);
}

int main()
{
	optimalBST(p,q,n);
	printRoot();
	cout << "Optimal Binary Searckh Tree : " << endl;
	printOptimalBST(1,n,-1);
}

    实验结果:

数据结构与算法分析-C++描述 第10章 算法设计技巧(动态规整之最优二叉搜索树)_第1张图片

practice makes perfect !

参考博客:【算法学习】最优二叉查找树(动态规划)

你可能感兴趣的:(C++,数据结构与算法分析-C++描述)