數據結構與算法小結(2)

一、二叉搜索樹

1.BST試圖解決的問題:

高效的兼顧靜態的查找和動態的增刪。
在基本的數據結構中
    數組通過尋秩可實現高效的查找,但增刪效率低;
    向量通過尋位置訪問,增刪高效,但查找低效,而且因爲增刪前通常都需要先找到對應的元素,這使得其效果更差。

改進思路是改變訪問方式,使用尋關鍵碼訪問。引入關鍵碼,將數據項與其關鍵碼綁定,統一的表示爲詞條的形式,根據關鍵碼來訪問元素,用數據項保存元素。
關鍵碼需支持比較器和判等器。

2.BST的特性

順序性:任一節點均不小於/不大於其左/右後代
單調性:BST的中序遍歷序列必然單調非降。BST的充要條件
BST中,根節點中序遍歷的後繼爲右子樹中最小的節點

3.BST的接口實現

查找:類似二分查找,最後得到匹配節點(無匹配項時爲空的哨兵節點)以及其父節點_hot。

插入:查找,無雷同元素則將待插入節點作爲找到的_hot節點的子節點插入。

刪除:先查找,找到的節點只有一個子樹時,直接刪除,用其子樹替換;若有兩個子樹,找到該節點的後繼(比該節點大的最小的節點,該點必定只有一個子樹),先交換這兩個點,再刪除需刪除的節點。

這裏寫圖片描述

刪除的算法實現:
Template <typename T> static BinNodePosi(T)
removeAt( BinNodePosi(T) & x,BinNodePosi(T) & hot ){
    BinNodePosi(T) w = x;               //實際被摘除的節點,初值同x
    BinNodePost(T) succ = NULL;         //實際被刪除節點的接替者
    if(!hasLChild(*x)){
        succ = x = x->rChild;           //情形一:待刪除節點沒有左孩子,直接以右孩子接替(右孩子可爲空)。
    }else if(!hasChild(*x)){
        succ = x = x->lChild;           //這段代碼不會走到,沒有孩子時,肯定沒有左孩子,會走情形一
    }else{                              //情形二:待刪除節點有左右孩子
        w = w->succ();                  //先找到在中序遍歷中,待刪除節點的後繼(即比待刪節點大的最小節點)
        swap(x->data,w->data);          //交換待刪節點與其後繼的值
        BinNodePosi(T) u = w->parent;   //找後繼是先找右孩子,然後沿左側鏈到底,所以此處有此判斷。需注意的是,左側鏈到底,所以其必定沒有左孩子,可能由右孩子
        (u == x ? u->rChild :u->lChild) = succ = w->rChild;     
    }
    hot = w->parent;
    if(succ){        //若之前找到的後繼有右孩子
        succ->parent = hot;  //因爲其一定沒有左孩子,所以可以通情形一處理。
    }
    release(w->data);
    release(w);
    return succ;
}

4.適度平衡

理想平衡:葉節點只能出現在最底部的兩層,即完全樹甚至滿樹。
適度平衡:高度漸進地不超過o(logn),即可稱作適度平衡。即平衡二叉搜索樹BBST。
    對於每個節點,其子節點數爲偶數,即要麼沒有子節點,要麼有兩個子節點。
等價BST:上下可變(父子關係可顛倒),左右不亂(中序遍歷序列不變,全局保持單調非降)。
    等價變換、旋轉調整。zig順時針,zag逆時針

適度平衡的例子之AVL樹:

AVL樹:所有節點左右子樹的高度只差不大於1。
    高度爲h的AVL樹,至少包含S(h) = fib(h + 3) - 1個節點。
    由n的節點構成的AVL樹,高度至多爲o(logn)

AVL實現:
    每個節點需維護一個平衡因子,其值爲左子樹樹高減去右子樹樹高,每次增刪節點時,都需向上冒泡計算。所以,每個節點還需維護一個記錄其樹高的成員變量。
    插入:若要失衡,共有四種情況,因對稱的重複,可分兩種情況討論
        1.左(右)側鏈,此時單旋即可使子樹高度復原
        2.Z字鏈,此時雙旋也可使子樹高度復原
        當子樹高度復原時,其更高的祖先也必定平衡。
    刪除:同插入一樣,也可以分爲兩種情況討論,但不同的是,刪除後經過單旋或雙旋,原樹高度不一定會復原,更高祖先仍可能失衡,這就是失衡傳播現象,最壞需要做o(logn)次調整。
    雙旋:
        zigzig都在左側,順時針旋轉
        zagzag都在右側,逆時針旋轉
        zigzag 右、左,雙旋,之字形排列
        zagzig 左、右
    雙旋實現:將三個節點(a,b,c)、四顆子樹(A,B,C,D)看做單個元素做中序遍歷,傳入7個參數,最後返回一顆子樹,該子樹以b爲根,左右孩子分別爲a、c,a的孩子爲A、B,c的孩子爲C、D。此時樹高最小。
    雙旋實現的啓發:理論分析時使用的是形象的工具,實際操作時,往往有更暴力、性能更優的解,當然,這些解需要對理論的工具有更深的理解才能想到。

二、高級搜索樹

1.伸展樹:

伸展樹期望解決的問題:

更快的訪問。
它依賴於這樣一個現象:剛被訪問過的數據,很有可能會很快的被再次訪問;下一個訪問的數據極有可能在剛訪問的數據附近。這就是數據訪問的局部性。
伸展樹的策略:
    節點一旦被訪問,隨即調整至樹根。自下而上,逐層單旋,直到被推到樹根。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章