`
dieslrae
  • 浏览: 35386 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

二叉树:红黑树

    博客分类:
  • Tree
 
阅读更多
    红黑树是一种自平衡的二叉树,它的查找,插入,删除操作时间复杂度皆为O(logN),不会出现普通二叉搜索树在最差情况时时间复杂度会变为O(N)的问题.
    红黑树必须遵循红黑规则,规则如下
    1、每个节点不是红就是黑。
    2、根总是黑的
    3、如果节点是红的,它的子节点必须全部是黑的
    4、从根到叶节点或者空子节点的每条路径,必须包含相同数量的黑色节点(黑色高度一致)    


    红黑树的插入操作比二叉搜索树复杂,为了保证黑红规则,要进行必要的变色和旋转.
  
    插入操作:
    查找例程遇到一个有两个红色子节点的黑色节点时,必须要把子节点变成黑色,把父节点变成红色(除非父节点为根节点).这样做是为了连接新的红色节点更容易.但有可违背规则3,当违背规则3时,X为违规节点(子节点违规),P为X的父节点,G为P的父节点则:
    如果X是G的外侧子孙节点:
        1、改变G的颜色
        2、改变P的颜色
        3、以G为顶点旋转,向X上升的方向(即X为左外侧子孙就右旋,为右外侧子孙就左旋)

    如果X是G的内侧子孙节点:
        1、改变G的颜色
        2、改变X的颜色
        3、以P为顶点旋转,向X上升的方向
        4、以G为顶点旋转,向X上升的方向

    在找到要插入的位置并插入节点后,会面临2种情况,即:插入节点的父节点是红色的(违背规则3);插入节点的父节点是黑色的(不违规).在父节点是黑色的情况下就不需要再做什么处理.而如果是红色的又分为两种情况:插入节点是外侧子孙节点;插入节点是内侧子孙节点.两者的处理方式与插入例程中的相同,即:
    如果P为红色,X是G的外侧子孙节点:
        1、改变G的颜色
        2、改变P的颜色
        3、以G为顶点旋转,向X上升的方向

    如果P为红色,X是G的内侧子孙节点:
        1、改变G的颜色
        2、改变X的颜色
        3、以P为顶点旋转,向X上升的方向
        4、以G为顶点旋转,向X上升的方向

    删除操作:
    说实话,本人愚钝,研究插入操作蛋已经碎了一地,好不容易才粘起来,删除操作则更加的复杂,于是还是尽量回避删除操作的好,比如设个作废标记神马的...

    查找操作:
    跟普通的二叉搜索树一样.


tree代码:
public class Tree {
    private Node root;
    
    /**
     * 插入数据
     * @param data 
     */
    public void insert(int data){
        Node node = new Node(data);
        
        if(this.root == null){
            this.setRoot(node);
            return;
        }
        
        Node current = this.root;
        
        while(true){
            //在变色后如果违反规则3,旋转平衡
            if(!this.changeColor(current)){
                this.rotate(current);
            }
            
            if(current.getData() > data){
                if(current.hasLeft()){
                    current = current.getLeft();
                }else{
                    current.setLeft(node);
                    break;
                }
            }else if(current.getData() < data){
                if(current.hasRihgt()){
                    current = current.getRight();
                }else{
                    current.setRight(node);
                    break;
                }
            }else{
                current.setValid(true);
                return;
            }
        }
        
        //插入后如果违反规则3,旋转平衡
        if(node.getParent().isRed()){
            this.rotate(node);
        }
    }
    
    /**
     * 查找数据
     * @param key 
     */
    public void find(int key){
        Node node = this.findNode(key);
        
        if(node != null && node.isValid()){
            System.out.println(node);
        }else{
            System.out.println("No find");
        }
    }
    
    /**
     * 删除节点
     * @param key 
     */
    public void remove(int key){
        Node node = this.findNode(key);
        
        if(node != null){
            node.setValid(false);
        }
    }
    
    /**
     * 树是否为空
     * @return 
     */
    public boolean isEmpty(){
        return this.root == null;
    }
    
    /**
     * 清空树
     */
    public void clear(){
        this.setRoot(null);
    }
    
    /**
     * 查找节点
     * @param i
     * @return 
     */
    private Node findNode(int key){
        Node current = this.root;
        
        while(current != null){
            if(current.getData() > key){
                current = current.getLeft();
            }else if(current.getData() < key){
                current = current.getRight();
            }else{
                return current;
            }
        }
        
        return null;
    }
    
    /**
     * 右旋转
     * @param top 顶点
     */
    private void rotateRight(Node top){
        if(top.hasLeft()){
            Node parent = top.getParent();
            Node left = top.getLeft();
            
            if(left.hasRihgt()){
                top.setLeft(left.getRight());
            }else{
                top.setLeft(null);
            }
            
            if(!top.isRoot()){
                if(top.isLeft()){
                    parent.setLeft(left);
                }else{
                    parent.setRight(left);
                }
            }else{
                this.setRoot(left);
            }
            
            left.setRight(top);
        }
    }
    
    /**
     * 左旋转
     * @param top 顶点 
     */
    private void rotateLeft(Node top){
        if(top.hasRihgt()){
            Node parent = top.getParent();
            Node right = top.getRight();
            
            if(right.hasLeft()){
                top.setRight(right.getLeft());
            }else{
                top.setRight(null);
            }
            
            if(!top.isRoot()){
                if(top.isLeft()){
                    parent.setLeft(right);
                }else{
                    parent.setRight(right);
                }
            }else{
                this.setRoot(right);
            }
            
            right.setLeft(top);
        }
    }
    
    /**
     * 如果一个节点的为黑色,并且它的两个子节点均为红色,将父节点变味红色,子节点变为黑色
     * @param node 父节点
     * @return 是否违反规则3,false为违反
     */
    private boolean changeColor(Node node){
        if(node.isBlack() && node.hasLeft() && node.hasRihgt() 
                && node.getLeft().isRed() && node.getRight().isRed()){
            
            node.getLeft().changeColor();
            node.getRight().changeColor();
            
            if(!node.isRoot()){
                node.changeColor();
                
                if(node.getParent().isRed()){
                    return false;
                }
            }
        }
        
        return true;
    }
    
    /**
     * 在违反规则3时做旋转操作平衡
     * @param node 违规节点
     */
    private void rotate(Node node){
        Node p = node.getParent();
        Node g = p.getParent();
        
        //当节点是外侧子孙节点的时候
        if(this.isRR(node) || this.isLL(node)){
            p.changeColor();
            g.changeColor();
            
            if(node.isRight()){
                this.rotateLeft(g);
            }else{
                this.rotateRight(g);
            }
        //当节点是内侧子孙节点的时候
        }else{
            g.changeColor();
            node.changeColor();
            
            if(node.isRight()){
                this.rotateLeft(p);
                this.rotateRight(g);
            }else{
                this.rotateRight(p);
                this.rotateLeft(g);
            }
        }
    }
    
    /**
     * 判断节点是否是父节点的右节点,并且父节点是否是祖父节点的右节点
     * @return 
     */
    private boolean isRR(Node node){
        return node.isRight() && node.getParent().isRight();
    }
    
    /**
     * 判断节点是否是父节点的左节点,并且父节点是否是祖父节点的左节点
     * @return 
     */
    private boolean isLL(Node node){
        return node.isLeft() && node.getParent().isLeft();
    }
    
    /**
     * 设置根节点
     * @param node 
     */
    private void setRoot(Node node){
        this.root = node;
        
        if(this.isEmpty()){
            return;
        }
        
        this.root.setParent(null);
        
        if(this.root.isRed()){
            this.root.changeColor();
        }
    }
}


node代码:
public class Node {
    
    private boolean color;//true是红,false是黑
    private Node parent;
    private Node left;
    private Node right;
    private int data;
    private boolean valid;

    public Node(int data) {
        this.data = data;
        this.color = true;
        this.valid = true;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;

        if (left != null) {
            left.setParent(this);
        }
    }

    public Node getParent() {
        return parent;
    }

    public void setParent(Node parent) {
        this.parent = parent;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;

        if (right != null) {
            right.setParent(this);
        }
    }

    public void setValid(boolean flag){
        this.valid = flag;
    }
    
    public boolean isValid(){
        return this.valid;
    }
    
    public boolean hasLeft() {
        return this.left != null;
    }

    public boolean hasRihgt() {
        return this.right != null;
    }

    public boolean isRed() {
        return this.color;
    }

    public boolean isBlack() {
        return !this.color;
    }

    public boolean isRoot() {
        return this.parent == null;
    }
    
    public boolean isLeft(){
        if(this.isRoot()){
            return false;
        }
        
        return this.parent.getLeft() == this;
    }
    
    public boolean isRight(){
        if(this.isRoot()){
            return false;
        }
        
        return this.parent.getRight() == this;
    }

    public void changeColor() {
        this.color = !this.color;
    }
}
分享到:
评论

相关推荐

    平衡二叉树-红黑树的实现

    平衡二叉树-红黑树的实现

    原生CSS+JS实现数据结构动态展示如二叉树,红黑树等

    原生CSS+JS实现数据结构动态展示如二叉树,红黑树等

    数据结构,树、二叉树、红黑树、堆、图等结构教程

    理解这些核心数据结构(如二叉树、二叉查找树和红黑树)及其相关算法对于软件开发人员至关重要,尤其是在设计高效的数据处理系统时。此外,掌握复杂度分析有助于我们在实际应用中做出更合理的决策,选择最适合当前...

    高级数据结构代码 红黑树 二叉树 B树

    本资源包含关于三种高级数据结构的代码实现:红黑树、二叉树和B树。这些数据结构在实际编程中有着广泛的应用,尤其在算法设计、数据库系统、内存管理等领域。 首先,我们来看二叉树,它是数据结构中最基础也是最...

    二叉树、B树、B+树、红黑树

    ### 二叉树、B树、B+树、红黑树 #### 一、二叉树 二叉树是一种常见的树形数据结构,在计算机科学中应用广泛。它具有以下特点: - **节点最多有两个子节点**:即每个节点最多有一个左子节点和一个右子节点。 - **...

    HashMap源码实现红黑树添加元素和删除元素

    红黑树是一种自平衡二叉树,可以保持二叉树的平衡,从而获得较高的查找性能。 红黑树的创建: 红黑树的优点是可以以 O(log2(N)) 的时间复杂度进行搜索、插入、删除操作。红黑树的创建过程中,首先定义了一个内部类...

    数据结构和算法分析、二叉树、红黑树、堆、图等数据结构

    通过对复杂度分析的理解以及对二叉树、二叉查找树和红黑树等数据结构的学习,我们可以更好地设计和优化算法,以应对各种实际问题。特别是在大数据时代,高效的数据结构和算法成为了软件开发的核心竞争力之一。

    c++容器list、vector、map、set区别与用法详解

    c++容器list、vector、map、set区别 list 封装链表,以链表形式实现,不支持[]运算符。... 采用平衡检索二叉树:红黑树 存储结构为键值对 set 采用平衡检索二叉树:红黑树 set中不包含重复的数据 Hash

    红黑树&二叉树

    红黑树和二叉树是数据结构中的重要概念,它们在计算机科学中有着广泛的应用,尤其是在算法和数据存储方面。二叉树是最基础的树形数据结构,而红黑树则是一种自平衡的二叉查找树,能有效地保证操作的时间复杂度。 ...

    红黑树的java实现 (二叉树也有)

    红黑树(Red-Black Tree)是一种自平衡的二叉查找树,它的设计目标是尽可能地减少在插入、删除和查找等操作时的最坏情况下的时间复杂度。这种数据结构在Java中广泛应用于集合框架,如`java.util.TreeMap`和`java....

    红黑树-数据结构

    - 红黑树支持前序遍历、中序遍历和后序遍历,这些遍历方式与普通二叉树的遍历类似,只是因为红黑树的特性,遍历速度更加均匀,性能更优。 5. **RBtree.cpp和RBtree.h**: 这两个文件很可能是实现红黑树的数据结构...

    1,int(20)中20的涵义 2,为什么索引结构默认使用B+Tree,而不是Hash,二叉树,红黑树? 3、MySQL里记录

    2,为什么索引结构默认使用B+Tree,而不是Hash,二叉树,红黑树? 3、MySQL里记录货币用什么字段类型好 4、数据库自增主键可能遇到什么问题。 5、从锁的类别角度讲,MySQL都有哪些锁呢? 6、索引失效情况? 7、优化...

    数据结构-b类-红黑二叉树-毕业论文.doc

    红黑二叉树是一种自平衡的二叉查找树,它的每个节点都是红色或黑色。红黑二叉树的特点是它可以在O(log n)时间内完成查找、插入和删除操作。红黑二叉树广泛应用于数据存储、数据库索引、文件系统等领域。 红黑二叉树...

    红黑树(Red Black Tree)

    - **遍历**:红黑树支持前序遍历、中序遍历和后序遍历,这些遍历方式在任何二叉树中都有定义。 4. **代码实现**: - 在CLION IDE中实现红黑树,你需要创建`main.c`文件并定义红黑树的节点结构、颜色枚举、插入、...

    红黑树-使用C++实现-简单练习

    红黑树是一种自平衡二叉查找树,由Rudolf Bayer于1972年提出。...C++实现红黑树不仅需要对二叉树有深入理解,还需要掌握颜色转换和旋转技巧。通过实践和调试,可以逐步完善实现,使其更高效、稳定。

    大厂真题之蚂蚁金服-资深工程师

    1. 二叉搜索树和平衡二叉树有什么关系,强平衡二叉树(AVL 树)和弱平衡二叉树 (红黑树)有什么区别 二叉搜索树:也称二叉查找树,或二叉排序树。定义也比较简单,要么是一颗空 树,要么就是具有如下性质的二叉树:...

    红黑树在Linux虚拟内存区域管理中的应用 (1).pdf

    红黑树是一种不完全平衡二叉树,它能够以 O(logN) 的时间复杂度进行插入、删除操作,并且它的插入和删除最多需要两次或者三次旋转即可保持树的平衡。红黑树的高效操作更适合 Linux 内核中 VMA 的添加、删除和查找,...

    COMP2211Project1:二叉树和红黑树的 Java 代码

    在本项目"COMP2211Project1"中,我们主要关注的是两种数据结构:二叉树和红黑树,它们都是在计算机科学中广泛使用的高效数据存储方式,特别是对于搜索、排序和组织大量数据非常有用。这个项目是用Java语言实现的,...

    talerbtree红黑树二叉树.zip

    红黑树(Red-Black Tree)是一种自平衡的二叉查找树,由Rudolf Bayer在1972年提出。这种数据结构在计算机科学中广泛应用于实现动态集合或关联数组,因为它能保证插入、删除和查找操作的时间复杂度保持在O(log n)。在...

    红黑树、平衡二叉树、排序算法的java实现

    本文将深入探讨"红黑树"、"平衡二叉树"、"二叉树"、"二叉搜索树"以及"排序算法"这些关键概念,并在Java环境下进行实现。 首先,我们来理解"二叉树"。二叉树是一种特殊的树形数据结构,每个节点最多有两个子节点,...

Global site tag (gtag.js) - Google Analytics