• 次优查找树的建立


      查找效率最高即平均查找长度最小,根据前面所学知识,我们可以给出有序表在非等概率情况下应遵循的两个原则:   

      1、最先访问的结点应是访问概率最大的结点; 

      2、每次访问应使结点两边尚未访问的结点的被访概率之和尽可能相等。

      这两个原则可用一句话来表示,即判定树为带权内路径长度之和最小的二叉树,亦即:PH = ∑wihi  最小,其中 n 为有序表长度,hi 为第 i 个结点在判定树上的层次数,wi = cpi,c 为某个常数,pi 为第 i 个结点的查找概率。

            这样的树称为静态最优查找树(static optimal search tree),构造这样一棵树的时间代价太大,亦即时间复杂度很大,因此我们通常是构造次优查找树(nearly optimal search tree),构造它的时间代价远远低于构造最优查找树,但查找性能只比最优查找树差1%~2%,很少差3%以上。

    次优查找树的构造: 
      
            设有序表每个记录的权值为 wl,wl+1,…,wh,第一个应访问的结点号为 i ,则有: 
    Δpi =   ∑wj - ∑wj   最小,即 Δpi = Min {Δpj } 
    再分别对 {rl,rl+1,…,ri-1} 和 {ri+1,ri+2,…,rh} 分别构造次优查找树。 
      
    为便于计算,引入累计权值swi=∑wj,并设wl-1=swl-1=0,则:

    查找构造静态次优查找树(SOST) - 蔷薇阁 - 落落工作室

        
            由于在构造次优查找树时没有考虑前面说的原则一,因此被选为根的结点的权值可能比其邻近结点的权值小,此时应对查找树作适当的调整,将相邻权值大的结点作为根结点。

              次优查找树的查找方法与折半查找类似,其平均查找长度与 log n 成正比。

    注意:利用上述算法构造好次优二叉树之后,可能并不是最优的,因为在构造过程中,没有考虑单个关键字的相应权值,则有可能出现被选为根的关键字的权值比与

        它相邻的关键字的权值小。此时应做适当的调整:选取邻近的权值较大的关键字作为次优查找树的根节点(也就是左旋和右旋子树

    #include<iostream>
    #include
    <cstring> #include<cstdio> #include<algorithm> #include<string> #include<cmath> #define N 100 #define MAXN 0x3f3f3f3f using namespace std; template<typename T> class TreeNode{ public: TreeNode* child[2]; T val; int w; TreeNode(){ child[0] = child[1] = NULL; } }; template<typename T> class NearlyOptimalSearchTree{//次优查找树 public: int n; T val[N]; int w[N]; int sw[N]; TreeNode<T> *t; void input(); void init(); void outT(TreeNode<T>* t); private: void buildT(int ld, int rd, TreeNode<T>* &t);//建立次优查找树 void adjustment(TreeNode<T>* &t);//调整次优查找树 void rotateT(TreeNode<T>* &t, int x); }; template<typename T> void NearlyOptimalSearchTree<T>::input(){ cin>>n; for(int i=1; i<=n; ++i) cin>>val[i]>>w[i]; } template<typename T> void NearlyOptimalSearchTree<T>::init(){ sw[0] = 0; for(int i=1; i<=n; ++i) sw[i] = sw[i-1]+w[i]; buildT(1, n, t); cout<<"没有调整前的先序遍历:"<<endl; outT(t); adjustment(t); cout<<endl<<"调整后的先序遍历:"<<endl; outT(t); cout<<endl; } template<typename T> void NearlyOptimalSearchTree<T>::buildT(int ld, int rd, TreeNode<T>* &t){ if(ld > rd) return; int minN = MAXN; int i; for(int j=ld; j<=rd; ++j){ int ans = sw[rd] - sw[j-1] - sw[j]; ans = abs(ans); if(minN > ans){ minN = ans; i = j; } } t = new TreeNode<T>; t->val = val[i]; t->w = w[i]; if(ld==rd) return; buildT(ld, i-1, t->child[0]); buildT(i+1, rd, t->child[1]); } template<typename T> void NearlyOptimalSearchTree<T>::adjustment(TreeNode<T>* &t){ if(!t) return; int lmax = 0, rmax = 0; if(t->child[0]) lmax = t->child[0]->w; if(t->child[1]) rmax = t->child[1]->w; int maxVal = max(lmax, rmax); if(t->w < maxVal){ if(maxVal == lmax){ rotateT(t, 1);//右旋子树 } else { rotateT(t, 0);//左旋子树 } } adjustment(t->child[0]); adjustment(t->child[1]); } template<typename T> void NearlyOptimalSearchTree<T>::rotateT(TreeNode<T>* &o, int x){ TreeNode<T>* k = o->child[x^1]; o->child[x^1] = k->child[x]; k->child[x] = o; o = k; } template<typename T> void NearlyOptimalSearchTree<T>::outT(TreeNode<T>* t){ if(!t) return; cout<<t->val<<" "; outT(t->child[0]); outT(t->child[1]); } int main(){ NearlyOptimalSearchTree<string> nost; nost.input(); nost.init(); return 0; }

    /*
      演示结果如下:

    9
    A 1
    B 1
    C 2
    D 5
    E 3
    F 4
    G 4
    H 3
    I 5
    没有调整前的先序遍历:
    F D B A C E G H I
    调整后的先序遍历:
    D C B A F E G I H

    
    

    5
    A 1
    B 30
    C 2
    D 29
    E 2
    没有调整前的先序遍历:
    C B A D E
    调整后的先序遍历:
    B A D C E


    */
    #include<iostream> 
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<string> 
    #include<iomanip>
    #include<cmath>
    #include<queue>
    #define N 100
    #define MAXN 0x3f3f3f3f
    using namespace std;
    
    template<typename T>
    class TreeNode{
        public:
            TreeNode* child[2];
            T val;
            int w; 
            int d;//距离屏幕左端的宽度 
            TreeNode(){
                child[0] = child[1] = NULL;
            }
    };
    
    template<typename T>
    class NearlyOptimalSearchTree{//次优查找树 
        public:
            int n;
            T val[N];
            int w[N];
            int sw[N];
            TreeNode<T> *t;
            void input();
            void init();
            void outT(TreeNode<T>* t);
        private:
            int width;
            int step;
            void buildT(int ld, int rd, TreeNode<T>* &t);//建立次优查找树 
            void adjustment(TreeNode<T>* &t);//调整次优查找树 
            void rotateT(TreeNode<T>* &t, int x);
            void widthT(TreeNode<T>* t);//计算每个节点到屏幕左端的距离 
    };
    
    template<typename T>
    void NearlyOptimalSearchTree<T>::input(){
        cin>>n;
        for(int i=1; i<=n; ++i)
            cin>>val[i]>>w[i];
    }
    
    template<typename T>
    void NearlyOptimalSearchTree<T>::init(){
        sw[0] = 0;
        width = 0;
        step = 2;
        for(int i=1; i<=n; ++i)    
            sw[i] = sw[i-1]+w[i];
        buildT(1, n, t);
        cout<<"没有调整前的先序遍历:"<<endl;
        outT(t);
        adjustment(t);
        cout<<endl<<"调整后的先序遍历:"<<endl;
        outT(t);
        cout<<endl;
    }
    
    template<typename T>
    void NearlyOptimalSearchTree<T>::buildT(int ld, int rd, TreeNode<T>* &t){
        if(ld > rd) return;
        int minN = MAXN;
        int i;
        for(int j=ld; j<=rd; ++j){
            int ans = sw[rd] - sw[j-1] - sw[j];    
            ans = abs(ans);
            if(minN > ans){
                minN = ans;
                i = j;
            }
        }
        t = new TreeNode<T>;
        t->val = val[i];
        t->w = w[i];
        if(ld==rd) return;
        buildT(ld, i-1, t->child[0]);
        buildT(i+1, rd, t->child[1]);
    }
    
    template<typename T>
    void NearlyOptimalSearchTree<T>::adjustment(TreeNode<T>* &t){
        if(!t) return;
        int lmax = 0, rmax = 0;
        if(t->child[0]) lmax = t->child[0]->w;
        if(t->child[1]) rmax = t->child[1]->w;
        int maxVal = max(lmax, rmax);
        if(t->w < maxVal){
            if(maxVal == lmax){
                rotateT(t, 1);//右旋子树 
            } else {
                rotateT(t, 0);//左旋子树 
            } 
        }
        adjustment(t->child[0]);
        adjustment(t->child[1]);
    }
    
    template<typename T>
    void NearlyOptimalSearchTree<T>::rotateT(TreeNode<T>* &o, int x){
        TreeNode<T>* k = o->child[x^1];
        o->child[x^1] = k->child[x];
        k->child[x] = o;
        o = k; 
    }
    
    template<typename T>
    void NearlyOptimalSearchTree<T>::widthT(TreeNode<T>* t){
        if(!t) return;
        widthT(t->child[0]);
        t->d = width;
        width+=step; 
        widthT(t->child[1]);
    }
    
    template<typename T>
    void NearlyOptimalSearchTree<T>::outT(TreeNode<T>* t){
        width=0;
         widthT(t);
         queue<TreeNode<T>*> q, qq;
         q.push(t);
         int n=1;//当前层的节点个数 
         int i=1;//当前层第几个节点 
         int nn=0;//统计下一次的节点的个数
         int pred;//前一个节点距离左屏幕的距离 
         while(!q.empty()){
             TreeNode<T>* tt = q.front();
             q.pop();
             qq.push(tt);
            if(tt != t){//不是根节点, 打印分枝竖线 
                 if(i==1){
                     printf("%*s", tt->d, "|");
                     pred = tt->d;
                 } else {
                     printf("%*s", tt->d-pred, "|");
                     pred = tt->d;
                 }
            }
             //放入孩子节点 
             if(tt->child[0]) q.push(tt->child[0]), ++nn;
             if(tt->child[1]) q.push(tt->child[1]), ++nn;
            ++i; 
            if(i>n){//上一层访问完毕 
                 i=1;
                 n = nn;
                 nn = 0;
                 printf("
    ");
                 bool first = true;//是否是这一行的第一个节点 
                 int ld, rd; 
                 while(!qq.empty()){//打印上层节点字符 
                     TreeNode<T>* tt = qq.front();
                     qq.pop();
                     if(first){
                         cout<<setw(tt->d)<<tt->val;
                         pred = tt->d;
                         ld = tt->d;
                         if(tt->child[0])
                             ld = tt->child[0]->d; 
                     } else {
                         cout<<setw(tt->d - pred)<<tt->val;
                         pred = tt->d;
                     }
                    first = false;
                    if(qq.empty()){//这一层的最后一个节点 
                        rd = tt->d+1;
                        if(tt->child[1])
                            rd = tt->child[1]->d;
                    }
                 }
                 printf("
    ");
                 if(q.empty()) break;//这是最后一层 
                 cout<<setw(ld-1)<<"";
                 for(int i=ld; i<=rd; ++i)
                     printf("-") ;
                 printf("
    ");
             }
         }
    }
    
    int main(){
        NearlyOptimalSearchTree<string> nost;
        nost.input();
        nost.init();
        return 0;
    }

    /*
      //演示结果

    9
    A 1
    B 1
    C 2
    D 5
    E 3
    F 4
    G 4
    H 3
    I 5
    没有调整前的先序遍历:

    
    

    F
    -------
    | |
    D G
    -------------
    | | |
    B E H
    -----------------
    | | |
    A C I

    
    

    调整后的先序遍历:

    
    

    D
    -------
    | |
    C F
    -----------
    | | |
    B E G
    -----------------
    | |
    A I
    ------------------
    |
    H


    */
  • 相关阅读:
    h5布局之道(最终篇)
    javascript 数组的常用方法总结
    排序算法之简单排序算法
    浅谈h5移动端页面的适配问题
    开园子啦(浅谈移动端以及h5的发展)
    Android开发(二):RelativeLayout、FrameLayout、LinearLayout、TableLayout、AbsoluteLayout各种Layout属性
    Android开发(一):android环境搭建
    为何没有人用DELPHI IDHTTP + WEB做三层应用
    Asp.net学习1-弹出消息框
    处理SQL函数IN问题
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/4657858.html
Copyright © 2020-2023  润新知