其他分享
首页 > 其他分享> > 红黑树杀人事件始末

红黑树杀人事件始末

作者:互联网

前言

红黑树是算法领域中一个著名的二叉查找树实现,它能够以较小的开销保持二叉查找树的平衡。具备平衡性质的二叉查找树能够极大地提高节点的查询速度。举个形象一点的例子:从一个十亿节点的红黑树中查找一个节点,所需要的查询次数不到30,这不禁让人感叹算法的魅力。

红黑树是工程中最常见的二叉查找树的实现,例如在Linux的内存管理和进程管理中就用到了红黑树;Java语言的集合包、C++语言的标准模板库中均提供了红黑树的实现类。

红黑树本身的设计很复杂,多数情况下我们也不需要自己去实现红黑树,但研究红黑树还是有意义的。一方面可以让学习者领略这种神奇的数据结构的奥妙,另一方面可以作为一种思维训练工具,提升自己的算法设计能力。

本文以漫画形式讲述红黑树,第一话讲解二叉查找树的概念和基本操作,包括节点查找、插入、删除;第二话讲解二叉查找树的缺点和红黑树的概念,以及红黑树的节点旋转操作;第三话讲解红黑树的节点插入操作;第四话讲解红黑树的节点删除操作;第五话和彩蛋部分讲解红黑树在插入修正和删除修正时,对各种CASE所进行的调整操作背后的思想。

红黑树的实现中,最难的部分在于实现节点的插入和删除时,要穷举所有可能的CASE,然后对每种CASE进行处理。在理解节点的插入和删除的过程时,读者要把握住一个中心:每种CASE所进行的调整步骤都在尽量恢复插入/删除节点后所违反的红黑树特性,如果当前CASE解决不了,就转成另一种更接近问题解决状态的CASE。每种CASE的所进行的调整步骤都是为了向解决问题的出口更靠近一步,直至找到出口。

漫画采用大量的图示来展示红黑树操作的诸多细节,作者力求详尽,因此篇幅略长。附录给出了完整的二叉查找树定义 + 测试代码,以及红黑树定义 + 测试代码。两份代码均经过了若干次十万数量级随机节点插入和删除测试,结果均无误。读者可贴到自己的 IDE 中,结合本文讲解进行调试研究。

在电脑端本文阅读效果更佳。另外,读者可联系「码海」公众号博主(微信:geekoftaste)获取本漫画的pdf版本。

正文

附录:代码清单

二叉查找树代码

BsTreeTest.java

package bst;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

public class BsTreeTest {
    public static void main(String[] args) {

        // 随机数的上限
        int bound = 10000000;

        // 随机序列的长度
        int seqLen = 100000;

        // 随机数生成器
        Random random = new Random();

        // 根节点值
        int rootValue = random.nextInt(bound);

        // 随机序列容器
        List

BsTree.java

package bst;

import java.util.Collection;

public class BsTree<T extends Comparable<T>> {

    /**
     * 使用递归实现 BsTree 查找
     *
     * @param root BST 根节点引用
     * @param key  待查找的节点值
     * @return 命中的节点
     */
    public BsTreeNode{
        if (root == null) {
            return null;
        }

        if (root.nodeKey.compareTo(key) > 0) {
            return searchRecursively(root.left, key);
        } else if (root.nodeKey.compareTo(key) < 0) {
            return searchRecursively(root.right, key);
        } else {
            return root;
        }
    }

    /**
     * 中序遍历 BsTree,打印节点值(递归实现)
     *
     * @param root
     */
    public void inOder(BsTreeNode {
        if (root == null) {
            return;
        }
        inOder(root.left);
        System.out.print("->" + root.nodeKey.toString());
        inOder(root.right);
    }

    /**
     * 中序遍历 BsTree,打印节点值(递归实现)
     *
     * @param root
     */
    public void middleOder(BsTreeNode {
        if (root == null) {
            return;
        }

        middleOder(root.left, collection);
        //System.out.print("->" + root.nodeKey.toString());
        collection.add(root.nodeKey);
        middleOder(root.right, collection);
    }

    /**
     * 向 BsTree 中插入节点(递归实现)
     * 


     * 二叉排序树本身是动态查找表的一种表示形式,有时会在
     * 查找过程中插入或者删除表中元素。当因为查找失败而需
     * 要插入数据元素时,该数据元素的插入位置一定位于二叉
     * 排序树的叶子结点,并且一定是查找失败时访问的最后一
     * 个结点的左孩子或者右孩子。
     *
     * @param root BsTree 根节点引用
     * @param key  待插入的节点值
     * @return 插入成功返回 true,如果树中有该元素不需要插入则返回 false
     */


    public boolean insertRecursively(BsTreeNode {
        if (root.nodeKey.compareTo(key) > 0) {
            if (root.left == null) {
                BsTreeNode

红黑树代码

RbTreeTest.java

package rbt;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

public class RbTreeTest {

    public static void main(String[] args) {

        // 随机数的上限
        int bound = 1000000000;

        // 随机序列的长度
        int seqLen = 100000;

        // 随机数生成器
        Random random = new Random();

        // 根节点值
        int rootValue = random.nextInt(bound);

        // 随机序列容器
        List

RbTree.java

package rbt;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;


public class RbTree<T extends Comparable<T>> {

    /**
     * 根结点
     */
    private RbTreeNode

标签:java,始末,util,红黑树,杀人,import,root,节点
来源: https://blog.51cto.com/u_15175267/2833204