详解Java数据结构之平衡二叉树

详解Java数据结构之平衡二叉树

什么是平衡二叉树?

平衡二叉树(Balanced Binary Tree)是一种特殊的二叉搜索树,它的左子树和右子树的高度差不超过1,这样可以保证在最坏情况下,查找、插入、删除等操作的时间复杂度都是O(log n)。

平衡二叉树的基本性质

  1. 左子树和右子树的高度差不超过1。

  2. 平衡二叉树的左右子树也是平衡二叉树。

如何实现?

平衡二叉树的实现有多种,其中比较常见的是AVL树和红黑树。

AVL树

AVL树是一种严格平衡的二叉树,它的平衡条件是:对于AVL树上的任意结点,它的左子树和右子树的高度差不超过1。

红黑树

红黑树是一种非严格平衡的二叉树,它的平衡条件是:红黑树上的任意结点,到它的叶子节点的路径上,黑色结点数目相同。红黑树通过旋转和变色来保证平衡。

平衡二叉树的应用

平衡二叉树常用于需要高效查找、插入、删除操作的场景,比如数据库索引、缓存等。

示例如何定义一棵平衡二叉树

以下是用Java代码定义一棵基于AVL树的平衡二叉树:

public class AVLTree<T extends Comparable<T>> {
    private static class AVLNode<T> {
        T element;
        AVLNode<T> left;
        AVLNode<T> right;
        int height;
        AVLNode(T theElement, AVLNode<T> lt, AVLNode<T> rt) {
            element = theElement;
            left = lt;
            right = rt;
            height = 0;
        }
    }

    private AVLNode<T> root;

    public AVLTree() {
        root = null;
    }

    public void insert(T x) {
        root = insert(x, root);
    }

    private AVLNode<T> insert(T x, AVLNode<T> t) {
        if (t == null) {
            return new AVLNode<>(x, null, null);
        }

        int compareResult = x.compareTo(t.element);

        if (compareResult < 0) {
            t.left = insert(x, t.left);
            if (height(t.left) - height(t.right) == 2) {
                if (x.compareTo(t.left.element) < 0) {
                    t = rotateWithLeftChild(t);
                } else {
                    t = doubleWithLeftChild(t);
                }
            }
        } else if (compareResult > 0) {
            t.right = insert(x, t.right);
            if (height(t.right) - height(t.left) == 2) {
                if (x.compareTo(t.right.element) > 0) {
                    t = rotateWithRightChild(t);
                } else {
                    t = doubleWithRightChild(t);
                }
            }
        } else {
            // element is already in the tree, do nothing
        }
        t.height = Math.max(height(t.left), height(t.right)) + 1;
        return t;
    }

    private int height(AVLNode<T> t) {
        return t == null ? -1 : t.height;
    }

    private AVLNode<T> rotateWithLeftChild(AVLNode<T> k2) {
        AVLNode<T> k1 = k2.left;
        k2.left = k1.right;
        k1.right = k2;
        k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
        k1.height = Math.max(height(k1.left), k2.height) + 1;
        return k1;
    }

    private AVLNode<T> rotateWithRightChild(AVLNode<T> k1) {
        AVLNode<T> k2 = k1.right;
        k1.right = k2.left;
        k2.left = k1;
        k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
        k2.height = Math.max(height(k2.right), k1.height) + 1;
        return k2;
    }

    private AVLNode<T> doubleWithLeftChild(AVLNode<T> k3) {
        k3.left = rotateWithRightChild(k3.left);
        return rotateWithLeftChild(k3);
    }

    private AVLNode<T> doubleWithRightChild(AVLNode<T> k1) {
        k1.right = rotateWithLeftChild(k1.right);
        return rotateWithRightChild(k1);
    }

    public void remove(T x) {
        root = remove(x, root);
    }

    private AVLNode<T> remove(T x, AVLNode<T> t) {
        if (t == null) {
            return t;
        }

        int compareResult = x.compareTo(t.element);

        if (compareResult < 0) {
            t.left = remove(x, t.left);
            if (height(t.right) - height(t.left) == 2) {
                if (height(t.right.right) >= height(t.right.left)) {
                    t = rotateWithRightChild(t);
                } else {
                    t = doubleWithRightChild(t);
                }
            }
        } else if (compareResult > 0) {
            t.right = remove(x, t.right);
            if (height(t.left) - height(t.right) == 2) {
                if (height(t.left.left) >= height(t.left.right)) {
                    t = rotateWithLeftChild(t);
                } else {
                    t = doubleWithLeftChild(t);
                }
            }
        } else if (t.left != null && t.right != null) {
            t.element = findMin(t.right).element;
            t.right = remove(t.element, t.right);
            if (height(t.left) - height(t.right) == 2) {
                if (height(t.left.left) >= height(t.left.right)) {
                    t = rotateWithLeftChild(t);
                } else {
                    t = doubleWithLeftChild(t);
                }
            }
        } else {
            t = (t.left != null) ? t.left : t.right;
        }

        if (t != null) {
            t.height = Math.max(height(t.left), height(t.right)) + 1;
        }
        return t;
    }

    private AVLNode<T> findMin(AVLNode<T> t) {
        if (t == null) {
            return null;
        }
        if (t.left == null) {
            return t;
        }
        return findMin(t.left);
    }

    public void makeEmpty() {
        root = null;
    }

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

示例说明

假设我们有以下整数序列需要插入到一棵基于AVL树的平衡二叉树中:1, 2, 3, 4, 5, 6, 7, 8。

AVLTree<Integer> avlTree = new AVLTree<>();
avlTree.insert(1);
avlTree.insert(2);
avlTree.insert(3);
avlTree.insert(4);
avlTree.insert(5);
avlTree.insert(6);
avlTree.insert(7);
avlTree.insert(8);

在插入完上述整数序列后,我们可以使用以下代码检查平衡二叉树的平衡性:

private static <T extends Comparable<T>> boolean checkBalance(AVLTree.AVLNode<T> t) {
    if (t == null) {
        return true;
    }
    int leftHeight = height(t.left);
    int rightHeight = height(t.right);
    if (Math.abs(leftHeight - rightHeight) > 1) {
        return false;
    }
    return checkBalance(t.left) && checkBalance(t.right);
}

private static <T extends Comparable<T>> int height(AVLTree.AVLNode<T> t) {
    return t == null ? -1 : t.height;
}

boolean isBalanced = checkBalance(avlTree.root);

如果isBalanced等于true,则说明平衡二叉树插入所有整数后仍然平衡。

接下来,我们尝试从平衡二叉树中删除元素8:

avlTree.remove(8);

然后,我们可以使用以下代码检查AVL树的平衡性:

boolean isBalanced = checkBalance(avlTree.root);

如果isBalanced等于true,则说明AVL树删除元素8后仍然平衡。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java数据结构之平衡二叉树 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • C语言深入浅出讲解顺序表的实现

    C语言深入浅出讲解顺序表的实现 顺序表简介 顺序表是一种线性表的存储结构,它是由连续的内存空间来存储线性表中的元素。 顺序表的特点是支持查找、插入和删除操作,操作效率较高,但需要提前分配足够大的内存空间。当顺序表空间不足时,需要扩容,移动数据较为麻烦。 顺序表的实现 数据结构定义 顺序表的数据结构定义包含以下几个成员: 数据元素数组 data,存储线性表中的…

    数据结构 2023年5月17日
    00
  • C语言详解数据结构与算法中枚举和模拟及排序

    我们一步步来详细讲解“C语言详解数据结构与算法中枚举和模拟及排序”的完整攻略。 纲要 本文的主要内容包括: 枚举的概念及应用 模拟的概念及应用 排序的概念及分类 枚举的概念及应用 枚举是一种数据类型,可以将一组具有相关性质的常量定义为枚举常量。枚举常量默认是按照自然数递增的顺序进行编号的。枚举常量可以用于表示状态、类型、结果等概念。以下是一个枚举类型的定义:…

    数据结构 2023年5月17日
    00
  • Mysql Innodb存储引擎之索引与算法

    Mysql Innodb存储引擎之索引与算法 MySQL是一款非常受欢迎的关系型数据库,有许多的存储引擎可供选择,其中InnoDB是目前最受欢迎的存储引擎之一。索引是InnoDB存储引擎的一个重要特性,它可以大大提高数据库查询的效率。本文将详细讲解InnoDB存储引擎的索引与算法。 索引 索引是一种数据结构,它将表中的列与对应的行位置组成键值对,以便快速查找…

    数据结构 2023年5月17日
    00
  • 一文吃透JS树状结构的数据处理(增删改查)

    一文吃透JS树状结构的数据处理(增删改查) 什么是树状结构 树状结构是一种经典的数据结构,在计算机领域中被广泛应用。树状结构由连通的节点组成,节点之间形成父子关系。一根树状结构的“根节点”没有父节点,每个子节点可以有多个“子节点”,但一个“子节点”只能有一个“父节点”。常见的应用包括文件系统、HTML DOM 和 JSON 数据格式等。 数据结构设计 我们以…

    数据结构 2023年5月17日
    00
  • Java数据结构之常见排序算法(上)

    Java数据结构之常见排序算法(上) 本篇文章将介绍常见的排序算法,包括冒泡排序、选择排序、插入排序、快速排序和归并排序。这些排序算法既是学习算法和数据结构的入门知识,也是在实际工作中常用的基础算法。 冒泡排序 冒泡排序是一种简单的排序算法,它的基本思想是从前往后依次比较相邻的两个元素,如果前面的元素比后面的元素大,则交换它们的位置,重复这个过程,每一轮比较…

    数据结构 2023年5月17日
    00
  • Android随手笔记44之JSON数据解析

    Android随手笔记44之JSON数据解析 1. JSON数据的基本概念 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于 JavaScript 的一个子集。JSON 格式最初是为了解决 JavaScript 程序通过 AJAX 传输数据时的数据交换格式问题而出现的,但是现在已经成为了一种通用的数据格式。…

    数据结构 2023年5月17日
    00
  • Java数据结构之队列(动力节点Java学院整理)

    Java数据结构之队列(动力节点Java学院整理) 队列是一种有序列表,在其中所有插入操作必须在后端进行,而所有的删除操作必须在前端进行的数据结构。这种结构有时被称为先进先出(FIFO)。 队列的分类 普通队列:队列和栈一样,都是只能在一端进行插入操作,在另一端进行删除操作的特殊线性表。队列的特点是:先进先出。适用于数据必须按照插入顺序处理的必要场合。 双端…

    数据结构 2023年5月17日
    00
  • C#常用数据结构和算法总结

    C#常用数据结构和算法总结 数据结构 数组(Array) 数组是一种线性数据结构,它可以在内存中连续地存储相同类型的数据。可以使用索引访问数组中的元素。数组的元素可以是任意类型。 在 C# 中,定义一个数组需要指定数组的类型和数组的大小。例如,定义一个包含 5 个整数的数组: int[] arr = new int[5]; 链表(LinkedList) 链表…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部