將鏈表轉(zhuǎn)換為樹

題目來源

今天做了個題:

將一個鏈表里的數(shù)據(jù)組裝樹形結(jié)構(gòu)剩瓶,鏈表里的數(shù)據(jù)已經(jīng)滿足樹形結(jié)構(gòu)要求

這道題描述的很簡單,但是有很多種情況辐脖。他只說了鏈表數(shù)據(jù)滿足樹形結(jié)構(gòu)要求狭莱,并沒有說明數(shù)據(jù)到底是什么樣的僵娃,也就是題目參數(shù)具有多樣性,這樣其實我們給出一種解決方案就可以腋妙。而且也只要求將鏈表轉(zhuǎn)換為樹默怨,并沒有說是什么樹。所以這道題說難也難骤素,說簡單也簡單匙睹。

解題思路

最近也將平衡二叉樹的原理看了一下,正好借著這道題將代碼手寫一下济竹。

我寫了一個平衡二叉樹的插入方法痕檬。我們不管鏈表里面的數(shù)據(jù)是如何排序的,我們只要調(diào)用樹的插入方法即可规辱。在插入方法內(nèi)部實現(xiàn)樹的平衡谆棺。

所以我們這道題也就轉(zhuǎn)換成了手寫平衡二叉樹的插入過程。

代碼實現(xiàn)

平衡二叉樹

首先我們需要定義平衡二叉樹的數(shù)據(jù)結(jié)構(gòu)罕袋,在這里我們就用 int 類型來簡單實現(xiàn)改淑。

/**
 * 二叉平衡樹的數(shù)據(jù)類型
 */
class AVLTreeNode {
    
    int val;
    int height = -1;
    AVLTreeNode left;
    AVLTreeNode right;

    public AVLTreeNode() {
    }

    public AVLTreeNode(int val) {
        this.val = val;
    }

}

接下來我們定義這個平衡二叉樹中所需用到的方法:

class AVLTree {
    //定義一個變量,存儲頭部節(jié)點
    AVLTreeNode head;
    
    //我們在進行平衡判斷時浴讯,需要知道每個節(jié)點的高度朵夏,從而進行計算
    private static int Height(AVLTreeNode avlTreeNode) {
        if (avlTreeNode == null) {
            return -1;
        } else {
            return avlTreeNode.height;
        }
    }

    //定義公共方法,實現(xiàn)內(nèi)部封裝
    public AVLTreeNode add(int value) {
        head = insert(head, value);
        return head;
    }
    //實際插入的方法
    private AVLTreeNode insert(AVLTreeNode root, int val) {
       ...
       ...
    }
    
}

我們知道榆纽,在平衡二叉樹中仰猖,有四種調(diào)整情況。分別為 LL型奈籽,LR 型饥侵,RL 型,RR 型衣屏。

所以需要將這四個方法提前寫明:

/*四種類型轉(zhuǎn)換*/

public AVLTreeNode LL(AVLTreeNode node) {
    //反轉(zhuǎn)結(jié)構(gòu)
    AVLTreeNode result = node.left;
    node.left = result.right;
    result.right = node;
    //修改高度
    node.height = Math.max(Height(node.left), Height(node.right)) + 1;
    result.height = Math.max(Height(result.left), Height(result.right)) + 1;
    return result;
}

public AVLTreeNode LR(AVLTreeNode node) {
    AVLTreeNode result = node.left.right;
    node.left.right = result.left;
    result.left = node.left;
    node.left = result.right;
    result.right = node;
    //修改高度
    node.height = Math.max(Height(node.left), Height(node.right)) + 1;
    result.height = Math.max(Height(result.left), Height(result.right)) + 1;
    return result;
}

public AVLTreeNode RL(AVLTreeNode node) {
    AVLTreeNode result = node.right.left;
    node.right.left = result.right;
    result.right = node.right;
    node.right = result.left;
    result.left = node;
    //修改高度
    node.height = Math.max(Height(node.left), Height(node.right)) + 1;
    result.height = Math.max(Height(result.left), Height(result.right)) + 1;
    return result;
}

private AVLTreeNode RR(AVLTreeNode node) {
    AVLTreeNode result = node.right;
    node.right = result.left;
    result.left = node;
    //修改高度
    node.height = Math.max(Height(node.left), Height(node.right)) + 1;
    result.height = Math.max(Height(result.left), Height(result.right)) + 1;
    return result;
}

為了驗證最終答案是否正確躏升,除了從 debug 看還寫了一個中序遍歷的方法來打印數(shù)據(jù)查看我們最終的答案是否正確:

// 中序遍歷
public void print(AVLTreeNode node) {
    if (node == null) {
        return;
    }
    print(node.left);
    System.out.print(node.val + " ");
    print(node.right);
}

我們最終的代碼如下:

/**
 * 平衡二叉樹
 */
class AVLTree {

    AVLTreeNode head;

    public AVLTreeNode add(int value) {
        head = insert(head, value);
        return head;
    }

    private AVLTreeNode insert(AVLTreeNode root, int val) {
        if (root == null) {
            root = new AVLTreeNode(val);
            root.height = 0;
            return root;
        }
        if (val < root.val) {
            //左側(cè)插入
            root.left = insert(root.left, val);
        } else if (val > root.val) {
            //右側(cè)插入
            root.right = insert(root.right, val);
        } else {
            //更新值
            root.val = val;
        }
        //檢查失衡,左右節(jié)點的高度差絕對值大于 2 即為失衡
        if (Math.abs(Height(root.left) - Height(root.right)) >= 2) {
            //當(dāng)左邊樹高時可能為 LL 型或 LR 型
            if (Height(root.left) > Height(root.right)) {
                //當(dāng)新插入的值比 root.left 值小時為 LL 型,比 root.left 值大時為 LR 型
                if (val < root.left.val) {
                    root = LL(root);
                } else if (val > root.left.val) {
                    root = LR(root);
                }
            } else if (Height(root.right) > Height(root.left)) {
                //當(dāng)右邊樹高時可能為 RR 型或 RL 型
                //當(dāng)新插入的值比 root.right 值大時為 RR 型狼忱,比 root.right 值小時為 RL 型
                if (val > root.right.val) {
                    root = RR(root);
                } else if (val < root.right.val) {
                    root = RL(root);
                }
            }
        }
        root.height = Math.max(Height(root.left), Height(root.right)) + 1;
        return root;
    }

    /*四種類型轉(zhuǎn)換*/

    public AVLTreeNode LL(AVLTreeNode node) {
        //反轉(zhuǎn)結(jié)構(gòu)
        AVLTreeNode result = node.left;
        node.left = result.right;
        result.right = node;
        //修改高度
        node.height = Math.max(Height(node.left), Height(node.right)) + 1;
        result.height = Math.max(Height(result.left), Height(result.right)) + 1;
        return result;
    }

    public AVLTreeNode LR(AVLTreeNode node) {
        AVLTreeNode result = node.left.right;
        node.left.right = result.left;
        result.left = node.left;
        node.left = result.right;
        result.right = node;
        //修改高度
        node.height = Math.max(Height(node.left), Height(node.right)) + 1;
        result.height = Math.max(Height(result.left), Height(result.right)) + 1;
        return result;
    }

    public AVLTreeNode RL(AVLTreeNode node) {
        AVLTreeNode result = node.right.left;
        node.right.left = result.right;
        result.right = node.right;
        node.right = result.left;
        result.left = node;
        //修改高度
        node.height = Math.max(Height(node.left), Height(node.right)) + 1;
        result.height = Math.max(Height(result.left), Height(result.right)) + 1;
        return result;
    }

    private AVLTreeNode RR(AVLTreeNode node) {
        AVLTreeNode result = node.right;
        node.right = result.left;
        result.left = node;
        //修改高度
        node.height = Math.max(Height(node.left), Height(node.right)) + 1;
        result.height = Math.max(Height(result.left), Height(result.right)) + 1;
        return result;
    }

    // 中序遍歷
    public void print(AVLTreeNode node) {
        if (node == null) {
            return;
        }
        print(node.left);
        System.out.print(node.val + " ");
        print(node.right);
    }

    private int Height(AVLTreeNode avlTreeNode) {
        if (avlTreeNode == null) {
            return -1;
        } else {
            return avlTreeNode.height;
        }
    }

}

/**
 * 二叉平衡樹的數(shù)據(jù)類型
 */
class AVLTreeNode {

    int val;
    int height = -1;
    AVLTreeNode left;
    AVLTreeNode right;

    public AVLTreeNode() {
    }

    public AVLTreeNode(int val) {
        this.val = val;
    }

}

我們寫一個 main 方法來檢查一下:

public static void main(String[] args) {
    ListNode head = new ListNode(1);
    ListNode head1 = new ListNode(2);
    ListNode head2 = new ListNode(3);
    ListNode head3 = new ListNode(4);
    ListNode head4 = new ListNode(5);
    ListNode head5 = new ListNode(6);
    head.next = head1;
    head1.next = head2;
    head2.next = head3;
    head3.next = head4;
    head4.next = head5;
    AVLTreeNode root = sortedListToBST(head);
    new AVLTree().print(root);
}

public static AVLTreeNode sortedListToBST(ListNode head) {
    AVLTreeNode root = null;
    while (head != null) {
        root = new AVLTree().add(head.val);
        head = head.next;
    }
    return root;
}

運行代碼后發(fā)現(xiàn)打印出的信息也是順序打印的膨疏,也沒有缺少節(jié)點。所以我們就完成了一個平衡二叉樹的插入過程钻弄。

然后這個題目的解也就自然完成了佃却。

本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!
博主郵箱:liunaijie1996@163.com窘俺,有問題可以郵箱交流饲帅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子洒闸,更是在濱河造成了極大的恐慌染坯,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丘逸,死亡現(xiàn)場離奇詭異单鹿,居然都是意外死亡,警方通過查閱死者的電腦和手機深纲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門仲锄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人湃鹊,你說我怎么就攤上這事儒喊。” “怎么了币呵?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵怀愧,是天一觀的道長。 經(jīng)常有香客問我余赢,道長芯义,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任妻柒,我火速辦了婚禮扛拨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘举塔。我一直安慰自己绑警,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布央渣。 她就那樣靜靜地躺著计盒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芽丹。 梳的紋絲不亂的頭發(fā)上章郁,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音志衍,去河邊找鬼。 笑死聊替,一個胖子當(dāng)著我的面吹牛楼肪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惹悄,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼春叫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起暂殖,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤价匠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后呛每,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踩窖,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年晨横,在試婚紗的時候發(fā)現(xiàn)自己被綠了洋腮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡手形,死狀恐怖啥供,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情库糠,我是刑警寧澤伙狐,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站瞬欧,受9級特大地震影響贷屎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜黍判,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一豫尽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧顷帖,春花似錦美旧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至陶舞,卻和暖如春嗽测,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肿孵。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工唠粥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人停做。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓晤愧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蛉腌。 傳聞我的和親對象是個殘疾皇子官份,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容