当前位置:嗨网首页>书籍在线阅读

61-算法解析及优化拓展

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

4.10.6 算法解析及优化拓展

1.算法复杂度分析

(1)时间复杂度:算法中有3层嵌套的for循环,其时间复杂度为O(n3)。

(2)空间复杂度:使用了3个二维数组求解c[i][j]、w[i][j]、s[i][j],所以空间复杂度为O(n2)。

2.算法优化拓展

如果按照普通的区间动态规划进行求解,时间复杂度是O(n3),但可以用四边形不等式优化。

524.gif s[i][j]表示取得最优解c[i][j]的最优策略位置。

k的取值范围缩小了很多,原来是区间[i,j],现在变为区间[s[i][j−1],s[i+1][j]]。经过优化,算法时间复杂度可以减少至O(n2),时间复杂度的计算可参看4.8.6节。

优化后算法:

//program 4-8-1
#include<iostream>
#include<cmath>           //求绝对值函数需要引入该头文件
using namespace std;
const int M=1000+5;
double c[M][M],w[M][M],p[M],q[M];
int s[M][M];
int n,i,j,k;
void Optimal_BST()
{
     for(i=1;i<=n+1;i++)
     {
          c[i][i-1]=0.0;
          w[i][i-1]=q[i-1];
     }
     for(int t=1;t<=n;t++)//t为关键字的规模
          //从下标为i开始的关键字到下标为j的关键字
          for(i=1;i<=n-t+1;i++)
          {
               j=i+t-1;
               w[i][j]=w[i][j-1]+p[j]+q[j];
               int i1=s[i][j-1]>i?s[i][j-1]:i;
               int j1=s[i+1][j]<j?s[i+1][j]:j;
               c[i][j]=c[i][i1-1]+c[i1+1][j];//初始化
               s[i][j]=i1;//初始化
               //选取i1+1到j1之间的某个下标的关键字作为从i到j的根,如果组成的树的期望值当前最小,则k为从i到j的根节点
               for(k=i1+1;k<=j1;k++)
               {
                    double temp=c[i][k-1]+c[k+1][j];
                    if(temp<c[i][j]&&fabs(temp-c[i][j])>1E-6)//C++中浮点数因为精度问题不可以直接比较
                    {
                         c[i][j]=temp;
                         s[i][j]=k;//k即为从下标i到j的根节点
                    }
               }
               c[i][j]+=w[i][j];
          }
}
void Construct_Optimal_BST(int i,int j,bool flag)
{
     if(flag==0)
     {
          cout<<"S"<<s[i][j]<<" 是根"<<endl;
          flag=1;
     }
     int k=s[i][j];
     //如果左子树是叶子
     if(k-1<i)
     {
          cout<<"e"<<k-1<<" is the left child of "<<"S"<<k<<endl;
     }
     //如果左子树不是叶子
     else
     {
          cout<<"S"<<s[i][k-1]<<" is the left child of "<<"S"<<k<<endl;
          Construct_Optimal_BST(i,k-1,1);
     }
     //如果右子树是叶子
     if(k>=j)
     {
          cout<<"e"<<j<<" is the right child of "<<"S"<<k<<endl;
     }
     //如果右子树不是叶子
     else
     {
          cout<<"S"<<s[k+1][j]<<" is the right child of "<<"S"<<k<<endl;
          Construct_Optimal_BST(k+1,j,1);
     }
}
int main()
{
     cout << "请输入关键字的个数 n:";
     cin >> n;
     cout<<"请依次输入每个关键字的搜索概率:";
     for (i=1; i<=n; i++ )
           cin>>p[i];
     cout << "请依次输入每个虚结点的搜索概率:";
     for (i=0; i<=n; i++)
           cin>>q[i];
     Optimal_BST();
     // /*用于测试
     for(i=1; i<=n+1;i++)
     {
            for (j=1; j<i;j++)
              cout <<"\t" ;
            for(j=i-1;j<=n;j++)
              cout << w[i][j]<<"\t" ;
            cout << endl;
     }
      for(i=1; i<=n+1;i++)
     {
            for (j=1; j<i;j++)
              cout <<"\t" ;
            for(j=i-1; j<=n;j++)
              cout << c[i][j]<<"\t" ;
            cout << endl;
     }
     for(i=1; i<=n;i++)
     {
            for (j=1; j<i;j++)
              cout << "\t" ;
            for(j=i-1; j<=n;j++)
              cout << s[i][j]<<"\t" ;
            cout << endl;
     }
     cout << endl;
     // */用于测试
     cout<<"最小的搜索成本为:"<<c[1][n]<<endl;
     cout<<"最优二叉搜索树为:";
     Construct_Optimal_BST(1,n,0);
     return 0;
}