我的 AVL 树代码(实现)有问题

问题描述 投票:0回答:1

最近在学习树,遇到了AVL树。我在学习这些概念时参考了 YouTube 上的 Kunal Kushwaha。我已经在下面的代码中实现了 AVL 树,我正在粘贴我的完整 AVL java 类

问题是当我尝试通过 Main 方法向树中添加 1000 个元素(值)时,高度应该为 3,因为高度为 log(n) -> log (1000) -> 3 但我得到12 作为输出而不是 3,但在 Kunal 的视频中,他实现的代码产生了 3,而我几乎实现了相同的代码却得到了不同的输出。我花了两个小时找出错误所在,但找不到任何错误。我什至提到了 ChatGPT 但我没用。非常感谢您帮助找出错误。

我发布了下面的 2 个代码

  1. 我的代码:
public class AVL_Trees {
    //i dont know why code when i insert 1000 elements
    //expected height is 3 but i get 12 i tried via ChatGPT and cross checked my self but still can't find the solution on where the error is
    //post on reddit or stackoverflow
    private class Node{
        private int value;
        private Node left;
        private Node right;
        private int height;
        public Node(int value){
            this.value = value;
        }

        public int getValue() {
            return value;
        }

    }

    private Node root;
    public AVL_Trees(){} //constructor
    public int height() {
        return height(root);
    }
    public int height(Node node) { //helper function
        if (node == null) {
            return -1;
        }
        return node.height;
    }

    public boolean isEmpty(Node node){
        return node == null;
    }

    public void prettyDisplay(){
        prettyDisplay(root,0);
        System.out.println("Height "+height(root));
    }
    private void prettyDisplay(Node node,int level){
        if(node == null){
            return;
        }
        prettyDisplay(node.right,level+1);
        if(level!=0){
            for(int i=0;i<level;i++){
                System.out.print("|\t\t");
            }
            System.out.println("|--->" + node.value);
        }
        else {
            System.out.println("|--->" + node.value);
        }

        prettyDisplay(node.left,level+1);
    }

    public void insert(int value){
        root = insert(root,value);
    }
    private Node insert(Node node, int value){
        if(node==null){
            return new Node(value);
        }
        if(value < node.value){
            node.left = insert(node.left,value);
        }
        if(value > node.value){
            node.right = insert(node.right,value);
        }
        node.height = Math.max(height(node.left),height(node.right)) + 1;
        return rotate(node);
    }

    //for arrays as input
    public void populate(int[] nums){
        for(int i : nums){
            insert(i);
        }
    }


    public void populateSorted(int[] nums){ //incase if input array is sorted
        populateSorted(nums,0, nums.length);
    }
    private void populateSorted(int[] nums,int start,int end){
        if(start>=end){
            return;
        }
        int mid = start + (end - start)/2;
        insert(nums[mid]);
        populateSorted(nums,0,mid);
        populateSorted(nums,mid+1,end);
    }

    public boolean balanced(){
        return balanced(this.root);
    }
    private boolean balanced(Node node){
        if(node == null){
            return true;
        }
        // condition for balance is both child node's height difference 
        //should be less than or equal to 1
        return Math.abs(height(node.left) - height(node.right)) <=1 && balanced(node.left) && balanced(node.right);
    }

    public void display(){
        display(root,"The root Node is ");
    }
    private void display(Node node , String details){ //just a way of representing
        if(node == null){
            return;
        }
        System.out.println(details + node.value);
        display(node.left,"The left node of "+node.value+" is: ");
        display(node.right,"The right node of "+node.value+" is: ");
    }

    private Node rotate(Node node){
        if(height(node.left) - height(node.right) > 1){
            //left heavy
            if(height(node.left.left) - height(node.left.right) > 0 ){ 
              //put 0, not 1 or -1 think about it!
                //left-left case
                return rightRotate(node);
            }
            if(height(node.left.left) - height(node.left.right) < 0){
                //left-right case
                node.left =  leftRotate(node.left);
                return rightRotate(node);
            }
        }

        if(height(node.left) - height(node.right) < -1){
            //right heavy
            if(height(node.right.left) - height(node.right.right) < 0){
                //right-right case
                return leftRotate(node);
            }
            if(height(node.right.left) - height(node.right.right) > 0){
                //right-left case
                node.right = rightRotate(node.right);
                return leftRotate(node);
            }
        }
        return node;
    }

    private Node rightRotate(Node p){
        Node c = p.left;
        Node t = c.right;
        c.right = p;
        p.left = t;
        //updating heights
        p.height = Math.max(height(p.left),height(p.right))+1;
        c.height = Math.max(height(c.left),height(c.right))+1;
        return c;
    }

    private Node leftRotate(Node c){
        Node p = c.right;
        Node t = p.left;
        p.left = c;
        c.right = t;
        //updating heights
        p.height = Math.max(height(p.left),height(p.right))+1;
        c.height = Math.max(height(c.left),height(c.right))+1;
        return p;
    }
}

2.Kunal的正确代码:

//this is the correct code for AVL tree where it can balance and height is 3 when adding 1000 elements
public class KunalAVL {
        public class Node {
            private int value;
            private Node left;
            private Node right;
            private int height;
            public Node(int value) {
                this.value = value;
            }

            public int getValue() {
                return value;
            }
        }

        private Node root;
        public KunalAVL() {

        }

        public int height() {
            return height(root);
        }
        private int height(Node node) {
            if (node == null) {
                return -1;
            }
            return node.height;
        }

        public void insert(int value) {
            root = insert(value, root);
        }

        private Node insert(int value, Node node) {
            if (node == null) {
                node = new Node(value);
                return node;
            }

            if (value < node.value) {
                node.left = insert(value, node.left);
            }

            if (value > node.value) {
                node.right = insert(value, node.right);
            }

            node.height = Math.max(height(node.left), height(node.right)) + 1;
            return rotate(node);
        }

        private Node rotate(Node node) {
            if (height(node.left) - height(node.right) > 1) {
                // left heavy
                if(height(node.left.left) - height(node.left.right) > 0) {
                    // left left case
                    return rightRotate(node);
                }
                if(height(node.left.left) - height(node.left.right) < 0) {
                    // left right case
                    node.left = leftRotate(node.left);
                    return rightRotate(node);
                }
            }

            if (height(node.left) - height(node.right) < -1) {
                // right heavy
                if(height(node.right.left) - height(node.right.right) < 0) {
                    // right right case
                    return leftRotate(node);
                }
                if(height(node.right.left) - height(node.right.right) > 0) {
                    // left right case
                    node.right = rightRotate(node.right);
                    return leftRotate(node);
                }
            }

            return node;
        }

        public Node rightRotate(Node p) {
            Node c = p.left;
            Node t = c.right;
            c.right = p;
            p.left = t;
            p.height = Math.max(height(p.left), height(p.right) + 1);
            c.height = Math.max(height(c.left), height(c.right) + 1);
            return c;
        }

        public Node leftRotate(Node c) {
            Node p = c.right;
            Node t = p.left;
            p.left = c;
            c.right = t;
            p.height = Math.max(height(p.left), height(p.right) + 1);
            c.height = Math.max(height(c.left), height(c.right) + 1);
            return p;
        }

        public void populate(int[] nums) {
            for (int i = 0; i < nums.length; i++) {
                this.insert(nums[i]);
            }
        }

        public void populatedSorted(int[] nums) {
            populatedSorted(nums, 0, nums.length);
        }

        private void populatedSorted(int[] nums, int start, int end) {
            if (start >= end) {
                return;
            }

            int mid = (start + end) / 2;
            this.insert(nums[mid]);
            populatedSorted(nums, start, mid);
            populatedSorted(nums, mid + 1, end);
        }

        public void display() {
            display(this.root, "Root Node: ");
        }

        private void display(Node node, String details) {
            if (node == null) {
                return;
            }
            System.out.println(details + node.value);
            display(node.left, "Left child of " + node.value + " : ");
            display(node.right, "Right child of " + node.value + " : ");
        }

        public boolean isEmpty() {
            return root == null;
        }

        public boolean balanced() {
            return balanced(root);
        }

        private boolean balanced(Node node) {
            if (node == null) {
                return true;
            }
            return Math.abs(height(node.left) - height(node.right)) <= 1 && balanced(node.left) && balanced(node.right);
        }


}
java data-structures avl-tree
1个回答
0
投票

当我尝试通过 Main 方法向树中添加 1000 个元素(值)时,高度应该是 3

请注意,在高度为 3 的二叉树(即 AVL)中,您只能容纳 15 个元素。

对于高度1,最多可以存储3个节点。对于高度 2,即 7 个节点,对于高度 3,最大值为 15:

height=1      height=2            height=3 

  O               O                ____O____
 / \            /   \             /         \
O   O          O     O           O           O
              / \   / \        /   \       /   \
             O   O O   O      O     O     O     O
                             / \   / \   / \   / \
                            O   O O   O O   O O   O

显然你无法在高度为 3 的二叉树中存储 1000 个元素。

...因为高度是 log(n) -> log (1000) -> 3 但我得到 12 作为输出而不是 3

您似乎误解了 log𝑛 的意图。它不是 log10𝑛,而是 log2𝑛。更准确地说,𝑛 节点的 AVL 树可以具有的最大高度以 1.44 log2𝑛为界。

如果你有一个有 1000 个节点的 AVL 树,它的高度可能高达 13。

但在 Kunal 的视频中,他实现的代码产生了 3

那是因为您作为 Kunal 的代码提供的代码存在错误。事实上它输出了 3,但如上所示,这不可能是正确的。

代码中的问题

您提供的第二个版本在旋转功能

leftRotate
rightRotate
中存在错误。它错误地计算了新高度,因为它仅将 1 添加到
max
的第二个参数,如下所示:

p.height = Math.max(height(p.left), height(p.right) + 1);
//                                                 ^^^^^^ 

...而 1 应该添加到 max 调用的

result
中。在您提供的第一个版本中,这是正确完成的(对您有好处!)。

两个版本的代码中

leftRotate
都存在另一个错误。
leftRotate
以错误的顺序重新校准节点
p
c
的高度。您应该首先对两个节点中最深的节点执行此操作,其中
leftRotate
中的节点是
c
- 因为它是
p
的子节点。

因此将其修复为:

    private Node leftRotate(Node c){
        Node p = c.right;
        Node t = p.left;
        p.left = c;
        c.right = t;
        //updating heights: *** but first C!!!!
        c.height = Math.max(height(c.left),height(c.right))+1;
        p.height = Math.max(height(p.left),height(p.right))+1;
        return p;
    }

注意:在

rightRotate
中,您按照正确的顺序进行了操作。

结果

当我将数字 1 到 1000 按排序顺序插入到树中时,报告的高度为 9,这完全没问题。这意味着树已尽可能保持平衡。按随机顺序插入,高度大部分为 11...这符合预期。

© www.soinside.com 2019 - 2024. All rights reserved.