二叉搜索树
二叉搜索树(Binary Search Tree,BST)是一种有序的二叉树,它具有以下性质:
对于二叉搜索树中的任意节点,其左子树中的节点值都小于该节点的值,右子树中的节点值都大于该节点的值。这意味着对于任意节点,其左子树中的值都小于该节点的值,右子树中的值都大于该节点的值。
这个性质递归地应用于每个节点的子树。换句话说,对于二叉搜索树中的任意子树,其左子树中的节点值都小于根节点的值,右子树中的节点值都大于根节点的值。
这种有序性质使得在二叉搜索树上进行搜索、插入和删除等操作非常高效。具体来说:
搜索操作:从根节点开始,如果目标值等于当前节点的值,则搜索成功。如果目标值小于当前节点的值,则继续在左子树中搜索;如果目标值大于当前节点的值,则继续在右子树中搜索。通过递归或迭代,可以快速定位目标值或确定其不存在。
插入操作:从根节点开始,根据目标值与当前节点的大小关系,沿着树向下遍历,直到找到一个空位置,然后在该位置插入新节点。插入操作会保持二叉搜索树的有序性质。
删除操作:删除节点时,需要考虑不同的情况。如果要删除的节点没有子节点,可以直接删除它。如果要删除的节点只有一个子节点,可以将子节点提升到删除节点的位置。如果要删除的节点有两个子节点,可以选择用其左子树中的最大节点或右子树中的最小节点来替换删除节点,并删除相应的替换节点。删除操作后,仍然需要保持二叉搜索树的有序性质。
最优二叉搜索树
最优二叉搜索树(Optimal Binary Search Tree)是指在给定一组键和对应的搜索频率(或概率)的情况下,构建一棵二叉搜索树,使得期望搜索时间最小化。
最优二叉搜索树的构建可以通过动态规划来解决,具体步骤如下:
定义子问题:将原问题拆分为规模较小的子问题。假设有n个键,我们通过选择一个根节点将它们分为左子树和右子树,然后递归地解决左右子树的最优二叉搜索树问题。
定义状态:通常使用一个二维数组dp[i][j]来表示在键的范围[i, j]内构建的最优二叉搜索树的期望搜索时间。
状态转移方程:根据子问题的定义,可以得到以下状态转移方程:
dp[i][j] = min{dp[i][k-1] + dp[k+1][j] + sum[i][j]}
其中,k表示范围[i, j]内选择的根节点,sum[i][j]表示键的概率之和,即sum[i][j] = p[i] + p[i+1] + ... + p[j]。这个方程表示在所有可能的根节点上取最小值。
填表计算:根据状态转移方程,按照从小到大的顺序填充dp数组。
构建最优二叉搜索树:根据填表得到的dp数组,可以通过追踪选择的根节点来构建最优二叉搜索树。
最后,构建完成的最优二叉搜索树将具有最小的期望搜索时间,可以通过dp[1][n](其中n为键的总数)获得最小期望搜索时间。
代码
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
double optimalBST(vector<double>&keys, vector<double>&freq)
{
int n = keys.size();
vector<vector<double>> sum(n + 2, vector<double>(n + 1, 0.0));
vector<vector<double>> dp(n + 2, vector<double>(n + 1, 0.0));
for(int i = 1; i <= n; i++){
sum[i][i] = freq[i];
for(int j = i + 1; j <= n; j++){
sum[i][j] = sum[i][j - 1] + freq[j];
}
}
//子问题规模len
for(int len = 1; len <= n; len ++){
for(int i = 1; i <= n - len + 1; i ++){
int j = i + len - 1;
dp[i][j] = 1e9;
//k为根节点,遍历k的各种可能情况
for(int k = i; k <= j; k++)
{
double cost = dp[i][k - 1] + dp[k + 1][j] + sum[i][j];
if(cost < dp[i][j])
dp[i][j] = cost;
}
}
}
return dp[1][n];
}
int main() {
vector<double> keys = {1, 2, 3, 4, 5};
vector<double> freq = {0.1, 0.2, 0.15, 0.3, 0.25};
double minCost = optimalBST(keys, freq);
cout << "最小期望搜索时间: " << minCost << endl;
return 0;
}