动态规划之最优二叉搜索树
2017-03-26 14:40
381 查看
目录
最优二叉搜索树简介举例以及详细分析
代码块
测试结果
最优二叉搜索树简介
1、概念引入基于统计先验知识,我们可统计出一个数表(集合)中各元素的查找概率,理解为集合各元素的出现频率。比如中文输入法字库中各词条(单字、词组等)的先验概率,针对用户习惯可以自动调整词频——所谓动态调频、高频先现原则,以减少用户翻查次数。这就是最优二叉查找树问题:查找过程中键值比较次数最少,或者说希望用最少的键值比较次数找到每个关键码(键值)。为解决这样的问题,显然需要对集合的每个元素赋予一个特殊属性——查找概率。这样我们就需要构造一颗最优二叉查找树。
2、最优二叉搜索树
最优二叉查找树:
给定n个互异的关键字组成的序列K=(k1,k2,…,kn),且关键字有序(k1小于k2小于…小于kn),我们想从这些关键字中构造一棵二叉查找树。对每个关键字ki,一次搜索搜索到的概率为pi。可能有一些搜索的值不在K内,因此还有n+1个“虚拟键”d0,d1,…,dn,他们代表不在K内的值。具体:d0代表所有小于k1的值,dn代表所有大于kn的值。而对于i = 1,2,…,n-1,虚拟键di代表所有位于ki和ki+1之间的值。对于每个虚拟键,一次搜索对应于di的概率为qi。要使得查找一个节点的期望代价(代价可以定义为:比如从根节点到目标节点的路径上节点数目)最小,就需要建立一棵最优二叉查找树。
图一显示了给定上面的概率分布pi、qi,生成的两个二叉查找树的例子。图二就是在这种情况下一棵最优二叉查找树。
举例以及详细分析
动态规划法策略是将问题分成多个阶段,逐段推进计算,后继实例解由其直接前趋实例解计算得到。对于最优BST问题,利用减一技术和最优性原则,如果前n-1个节点构成最优BST,加入一个节点an 后要求构成规模n的最优BST。按 n-1, n-2 , … , 2, 1 递归,问题可解。自底向上计算:C[1, 2]→C[1, 3] →… →C[1, n]。为不失一般性用C[i, j] 表示由{a1,a2,a3……an}构成的BST的耗费。其中1≤i ≤j ≤n。这棵树表示为Tij。从中选择一个键ak作根节点,它的左子树为Tik-1,右子树为Tk+1j。要求选择的k 使得整棵树的平均查找次数C[i, j]最小。左右子树递归执行此过程。(根的生成过程)
递推计算式如下:
基本算法:
代码块
#include<stdio.h> #include<stdlib.h> #define max 9999 void DptimalBST(int num, float *p, float **c, int **r) { int d, i, j, k, kmin, s; float temp, sum; for (i = 1; i < num + 1; i++) { c[i][i-1] = 0;//这里指的是在[i,i-1]的区间上没有空间能放k c[i][i] = p[i];//在[i,i]区间上只有i本身能当k,所以概率是自己本身 r[i][i] = i; } c[num + 1][num] = 0; for (d = 1; d <= num - 1; d++)//d是[i,j]之间的距离 { for (i = 1; i <= num - d; i++)//i是[i,j]的起始点i { j = i + d;//起始点i+距离d=终止点j temp = max; for (k = i; k <= j; k++)//在[i,j]之间寻找概率最小的 { if (c[i][k - 1] + c[k + 1][j] < temp) { temp = c[i][k - 1] + c[k + 1][j]; kmin = k; } } r[i][j] = kmin;//记录最优根 sum = p[i]; for (s = i + 1; s <= j; s++) { sum += p[s]; } c[i][j] = temp + sum; } } } void DptimalBSTPrint(int first, int last, int **r) { int k; if (first <= last) { k = r[first][last]; printf("%d ", k); DptimalBSTPrint(first, k - 1, r); DptimalBSTPrint(k + 1, last, r); } } int main(void) { int i; int num; printf("节点的个数:"); scanf("%d", &num); float *p = (float*)malloc(sizeof(float)*(num + 1)); for (i = 1; i < num+1; i++) { printf("节点%d的概率: ", i); scanf("%f",&p[i]); } float **c = (float **)malloc(sizeof(float *)*(num + 2)); for (i = 0; i < num + 2; i++) { c[i] = (float *)malloc(sizeof(float)*(num + 1)); } int **r = (int **)malloc(sizeof(int *)*(num + 2)); for (i = 0; i < num + 2; i++) { r[i] = (int *)malloc(sizeof(int)*(num + 1)); } DptimalBST(num, p, c, r); printf("该最有二叉搜索树的期望代价为:%f\n", c[1][num]); printf("构成的最优二叉查找树的中序遍历结果为:"); DptimalBSTPrint(1, num, r); system("pause"); return 0; }
测试结果
相关文章推荐
- 动态规划之最优二叉搜索树
- 动态规划之最优二叉搜索树
- 最优二叉搜索树动态规划
- 动态规划之最优二叉搜索树
- 动态规划 - 最优二叉搜索树
- 小白进阶之动态规划-最优二叉搜索树
- 动态规划-最优二叉搜索树
- 动态规划-最优二叉搜索树
- 动态规划---最优二叉搜索树问题
- 动态规划—最优二叉搜索树
- 算法导论之动态规划:最优二叉搜索树
- 动态规划---凸多边形的最优三角剖分问题
- 动态规划4-最优二叉查找树
- 动态规划方法生成最优二叉查找树
- 动态规划--凸多边形最优三角剖分
- 算法导论之动态规划(最长公共子序列和最优二叉查找树)
- 动态规划--凸多边形最优三角剖分
- 动态规划---->最优二分检索树
- 基于动态规划的矩阵连乘最优方法
- 动态规划之--生成最优二叉查找树