将链表转换为树

题目来源

今天做了个题:

将一个链表里的数据组装树形结构,链表里的数据已经满足树形结构要求

这道题描述的很简单,但是有很多种情况。他只说了链表数据满足树形结构要求,并没有说明数据到底是什么样的,也就是题目参数具有多样性,这样其实我们给出一种解决方案就可以。而且也只要求将链表转换为树,并没有说是什么树。所以这道题说难也难,说简单也简单。

解题思路

最近也将平衡二叉树的原理看了一下,正好借着这道题将代码手写一下。

我写了一个平衡二叉树的插入方法。我们不管链表里面的数据是如何排序的,我们只要调用树的插入方法即可。在插入方法内部实现树的平衡。

所以我们这道题也就转换成了手写平衡二叉树的插入过程。

代码实现

平衡二叉树

首先我们需要定义平衡二叉树的数据结构,在这里我们就用 int 类型来简单实现。

/**
 * 二叉平衡树的数据类型
 */
class AVLTreeNode {
    
    int val;
    int height = -1;
    AVLTreeNode left;
    AVLTreeNode right;

    public AVLTreeNode() {
    }

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

}

接下来我们定义这个平衡二叉树中所需用到的方法:

class AVLTree {
    //定义一个变量,存储头部节点
    AVLTreeNode head;
    
    //我们在进行平衡判断时,需要知道每个节点的高度,从而进行计算
    private static int Height(AVLTreeNode avlTreeNode) {
        if (avlTreeNode == null) {
            return -1;
        } else {
            return avlTreeNode.height;
        }
    }

    //定义公共方法,实现内部封装
    public AVLTreeNode add(int value) {
        head = insert(head, value);
        return head;
    }
    //实际插入的方法
    private AVLTreeNode insert(AVLTreeNode root, int val) {
       ...
       ...
    }
    
}

我们知道,在平衡二叉树中,有四种调整情况。分别为 LL型,LR 型,RL 型,RR 型。

所以需要将这四个方法提前写明:

/*四种类型转换*/

public AVLTreeNode LL(AVLTreeNode node) {
    //反转结构
    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 看还写了一个中序遍历的方法来打印数据查看我们最终的答案是否正确:

// 中序遍历
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) {
            //左侧插入
            root.left = insert(root.left, val);
        } else if (val > root.val) {
            //右侧插入
            root.right = insert(root.right, val);
        } else {
            //更新值
            root.val = val;
        }
        //检查失衡,左右节点的高度差绝对值大于 2 即为失衡
        if (Math.abs(Height(root.left) - Height(root.right)) >= 2) {
            //当左边树高时可能为 LL 型或 LR 型
            if (Height(root.left) > Height(root.right)) {
                //当新插入的值比 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)) {
                //当右边树高时可能为 RR 型或 RL 型
                //当新插入的值比 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;
    }

    /*四种类型转换*/

    public AVLTreeNode LL(AVLTreeNode node) {
        //反转结构
        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;
        }
    }

}

/**
 * 二叉平衡树的数据类型
 */
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;
}

运行代码后发现打印出的信息也是顺序打印的,也没有缺少节点。所以我们就完成了一个平衡二叉树的插入过程。

然后这个题目的解也就自然完成了。

本文由博客一文多发平台 OpenWrite 发布!
博主邮箱:liunaijie1996@163.com,有问题可以邮箱交流。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容