国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

學習JavaScript數據結構與算法 — AVL樹

impig33 / 3414人閱讀

摘要:可以看到,一次左單旋將右側子樹的高度減小了,而左側子樹的高度增加了。如圖,對進行右單旋,需要左子樹的右子樹的高度小于等于左子樹的高度,否則不能達到平衡的效果,只是把不平衡性從左邊轉移到了右邊。

AVL樹

普通二叉搜索樹可能出現一條分支有多層,而其他分支卻只有幾層的情況,如圖1所示,這會導致添加、移除和搜索樹具有性能問題。因此提出了自平衡二叉樹的概念,AVL樹(阿德爾森-維爾斯和蘭迪斯樹)是自平衡二叉樹的一種,AVL樹的任一子節點的左右兩側子樹的高度之差不超過1,所以它也被稱為高度平衡樹。

圖1

要將不平衡的二叉搜索樹轉換為平衡的AVL樹需要對樹進行一次或多次旋轉,旋轉方式分為左單旋、右單旋、左-右雙旋、右-左雙旋。

左單旋

對某一節點B(圖2)做左單旋,處理過程相當于,斷開B與父節點A的連接,將B的右子節點D與A連接,將B作為D的左子節點,將D的左子節點E作為B的右子節點。以圖1的二叉樹為例,對鍵值為15的節點做左單旋,首先斷開15與11的連接,再將20與11連接,將15作為20的左子節點,最后將18作為15的右子節點;可以想象為以15為中心做了一定的逆時針旋轉。結果如圖3。

圖2

圖3

再看圖2,根據搜索二叉樹的性質,肯定有D>B>A,E>B,因此旋轉過后,能夠保證 右子節點 > 父節點 > 左子節點,不會破壞樹的結構。
可以看到,一次左單旋將右側子樹的高度減小了1,而左側子樹的高度增加了1。實現代碼如下:

function roateLeft(AvlNode) {
        var node = AvlNode.right; // 保存右子節點
        AvlNode.right = node.left; // node的左子節點連接到AvlNode成為其右子節點
        node.left = AvlNode; // AvlNode連接到node成為其左子節點
        return node; // 返回node,連接到AvlNode最初的父節點
}
右單旋

右單旋與左單選類似,以某一節點B(圖4)做右單旋,首先斷開B與其父節點A的連接,將B的左子節點C與A連接,將C的右子節點F作為B的左子節點。同樣的,因為有C>A,B>F>C,因此旋轉過后,不會破壞樹的結構。可以看到,一次右單旋使節點的左側子樹高度減小了1,而右側子樹的高度增加了1。

圖4

實現代碼如下:

function roateRight(AvlNode) {
        var node = AvlNode.left; // 保存左子節點
        AvlNode.left = node.right; // 將node的右子節點連接到AvlNode成為其左子節點
        node.right = AvlNode; // AvlNode連接到node,成為其右子節點
        return node; // 返回node連接到AvlNode最初的父節點
}
左-右雙旋

左單旋、右單旋在某些情況下是不能達到平衡樹的目的的。如圖4,對B進行右單旋,需要左子樹C的右子樹F的高度小于等于左子樹E的高度,否則不能達到平衡的效果,只是把不平衡性從左邊轉移到了右邊。圖5演示了這種情況。同樣的,左單旋也有這個問題。

圖5

因此為了達到目的,需要先對旋轉節點的左子節點做左單旋,再對旋轉節點做右單旋。如圖6所示,先對節點B的左子節點C做左單旋,可以看到,這個操作,相當于將節點C的不平衡性從右側轉移到了左側,從而滿足了上述右單旋的條件;最后再對B節點做右單旋操作,最終達到了平衡的目的。

圖6

實現代碼如下:

function roateLeftRight(AvlNode) {
        AvlNode.right = roateLeft(AvlNode.right); // 對右子節點做左單旋
        return roateRight(AvlNode); // 做右單旋
}
右-左雙旋

同理,如圖2,對B進行左單旋時,需要右子樹D的右子樹F的高度大于等于左子樹E的高度,否則需要進行雙旋;即先對B的右子節點D做右單旋,再對B做左單旋。實現代碼如下:

function roateRightLeft(AvlNode) {
        AvlNode.left = roateRight(AvlNode.left); // 對左子節點做右單旋
        return roateLeft(AvlNode); // 做左單旋
}
實現樹的平衡

首先實現獲取樹高度的函數:

function getAvlTreeHeight(node) {
        if (node == null) {
            // node不存在返回0
            return 0;
        } else {
            var leftHeight = getAvlTreeHeight(node.left);
            var rightHeight = getAvlTreeHeight(node.right);
            // 返回左子樹、右子樹中的最大高度
            return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1;
        }
}

實現平衡樹的函數:

function balance(node) {
    if (node == null) {
        return node;
    }
    // 左子樹高度比右子樹高度大1以上
    if (getAvlTreeHeight(node.left) - getAvlTreeHeight(node.right) > 1) {
        if (getAvlTreeHeight(node.left.left) >= getAvlTreeHeight(node.left.right)) {
            // 如果左子樹的左子樹高度大于等于左子樹的右子樹高度
            // 直接進行右單旋
            node = roateRight(node);
        } else {
            // 否則需要右-左雙旋
            node = roateRightLeft(node);
        }
        // 右子樹高度比左子樹高度大1以上
    } else if (getAvlTreeHeight(node.right) - getAvlTreeHeight(node.left) > 1) {
        if (getAvlTreeHeight(node.right.right) >= getAvlTreeHeight(node.right.left)) {
            // 如果右子樹的右子樹高度大于等于右子樹的左子樹高度
            // 直接進行左單旋
            node = roateLeft(node);
        } else {
            // 否則需要左-右雙旋
            node = roateLeftRight(node);
        }
    }
    return node;
}

在二叉搜索樹的基礎上,每次插入節點,都需要做一次樹的平衡處理:

var insertNode = function(node, newNode){
    if (newNode.key < node.key){
        if (node.left === null){
            node.left = newNode;
            // 插入節點后,做樹的平衡處理
            node.left = balance(node.left);
        } else {
            insertNode(node.left, newNode);
        }
    } else {
        if (node.right === null){
            node.right = newNode;
            // 插入節點后,做樹的平衡處理
            node.right = balance(node.right);
        } else {
            insertNode(node.right, newNode);
        }
    }
}

綜上,一顆自平衡AVL樹的原理及實現就完成了。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86807.html

相關文章

  • JavaScript數據結構算法(十)自平衡

    摘要:為了解決這類問題,我們進行自平衡樹的學習。自平衡樹常見有兩種樹和紅黑樹。自平衡樹準備知識節點的高度和平衡因子節點高度從節點到任意子節點的彼岸的最大值。 前面介紹了二叉樹和二叉樹搜索樹的創建和使用,接下來我們繼續學習關于樹的更多知識。BST存在一個問題,就是當我們多次添加節點數,有可能造成一種情況,樹的一條邊可能會非常深,有非常多的層,而另一條分支卻只有幾層。當我們需要進行添加、移除和搜...

    msup 評論0 收藏0
  • 學習javascript數據結構(四)——

    摘要:原文博客地址學習數據結構四樹知乎專欄簡書專題前端進擊者知乎前端進擊者簡書博主博客地址的個人博客人之所能,不能兼備,棄其所短,取其所長。通常子樹被稱作左子樹和右子樹。敬請期待數據結構篇最后一篇文章學習數據結構五圖參考文章樹數據結構二叉樹 前言 總括: 本文講解了數據結構中的[樹]的概念,盡可能通俗易懂的解釋樹這種數據結構的概念,使用javascript實現了樹,如有紕漏,歡迎批評指正。 ...

    Dean 評論0 收藏0
  • 一文掌握關于Java數據結構所有知識點(歡迎一起完善)

    摘要:是棧,它繼承于。滿二叉樹除了葉結點外每一個結點都有左右子葉且葉子結點都處在最底層的二叉樹。沒有鍵值相等的節點。這是數據庫選用樹的最主要原因。 在我們學習Java的時候,很多人會面臨我不知道繼續學什么或者面試會問什么的尷尬情況(我本人之前就很迷茫)。所以,我決定通過這個開源平臺來幫助一些有需要的人,通過下面的內容,你會掌握系統的Java學習以及面試的相關知識。本來是想通過Gitbook的...

    keithxiaoy 評論0 收藏0
  • 二叉排序

    摘要:節點的構造函數默認為其初始化都是。二叉排序樹插入插入節點只要遵循一個原則就好大與就向中插入,小于就向插入。初始化數據樹現在來試試實例化一個來看看效果。 JavaScript 數據結構篇 之 BST 前言 有段時間沒有寫文章了,整個人感覺變得有點懶散了,大家可不要向我一樣哦~今天開始 seaconch 打算開始記錄 JavaScript 數據結構的學習經歷。至此,開始。 課本:《學習J...

    Soarkey 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<