前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >红黑树插入操作的java实现

红黑树插入操作的java实现

作者头像
眯眯眼的猫头鹰
发布2018-10-31 11:18:45
7230
发布2018-10-31 11:18:45
举报

前言

网上有非常多的关于红黑树理论的描述,本文的重点将不在于此,但是会在文中给出优秀文章的链接。对红黑树不了解的建议先阅读文章再看实现。本红黑树实现不支持多线程环境。因为删除操作灰常复杂,所以后续更新。源码在文末可以查看。

参考链接

https://www.geeksforgeeks.org... https://www.geeksforgeeks.org... http://www.codebytes.in/2014/... https://blog.csdn.net/eson_15...

数据结构

定义的红黑树的节点如下:

代码语言:javascript
复制
private static class Node<T>{
        static final int RED = 0;
        static final int BLACK = 1;
        T value;
        int color = RED;
        Node<T> leftChild;
        Node<T> rightChild;
        Node<T> parent;
        
        Node(T value) {
            this.value = value;
        }
    
        boolean isRoot() {
            return this.parent == null;
        }
        
        boolean isLeaf() {
            return this.leftChild == null && this.rightChild == null;
        }
        
        boolean isLeftChild() {
            return this.parent != null && this.parent.leftChild == this;
        }
        
        boolean isRightChild() {
            return this.parent != null && this.parent.rightChild == this;
        }
        
        Node<T> getUncle() {
            if(this.parent == null || this.parent.parent == null) return null;
            if(this.parent.isLeftChild()) {
                return this.parent.parent.rightChild;
            } else {
                return this.parent.parent.leftChild;
            }
                        
        }
        
        Node<T> getSibling() {
            if(this.parent == null) return null;
            return this.parent.leftChild == this ? this.parent.rightChild : this.parent.leftChild;
        }
    
        
        boolean isRed() {
            return this.color == RED;
        }
        
        boolean isBlack() {
            return this.color == BLACK;
        }
    }

该Node作为RedBlackTree的一个内部类存在。除了和普通的TreeNode相同给的左子节点和右子节点的引用,还额外引用了父节点,方便我们回溯。除此以外还封装了一些方法,比如获得自己的祖父节点,叔叔节点以及兄弟节点等。

旋转操作

因为额外持有了父节点,所以在执行旋转操作的时候需要额外注意空指针以及不恰当的赋值带来的循环引用。左旋和右旋的代码如下:

代码语言:javascript
复制
    private void rotateLeft(Node<T> node) {
        if(node == null || node.rightChild == null) return;
        Node<T> parent = node.parent;
        Node<T> rightChild = node.rightChild;
        
        if(rightChild.leftChild != null) {
            node.rightChild = rightChild.leftChild;
            node.rightChild.parent = node;
        } else {
            node.rightChild = null;
        }
        
        rightChild.leftChild = node;
        node.parent = rightChild;
        
        if(parent != null) {
            rightChild.parent = parent;
            if(node == parent.leftChild) {
                parent.leftChild = rightChild;
            } else {
                parent.rightChild = rightChild;
            }
        } else {
            rightChild.parent = null;
            root = rightChild;
        }
    }
    
    private void rotateRight(Node<T> node) {
        if(node == null || node.leftChild == null) return;
        Node<T> parent = node.parent;
        Node<T> leftChild = node.leftChild;
        
        if(leftChild.rightChild != null) {
            node.leftChild = leftChild.rightChild;
            node.leftChild.parent = node;
        } else {
            node.leftChild = null;
        }
        

        leftChild.rightChild = node;
        node.parent = leftChild;
        
        if(parent != null) {
            leftChild.parent = parent;
            if(node == parent.leftChild) {
                parent.leftChild = leftChild;
            } else {
                parent.rightChild = leftChild;
            }
        } else {
            leftChild.parent = null;
            root = leftChild;
        }
    }

插入

我们知道,在红黑树中插入一个节点相当于在一个二叉搜索树中插入一个节点。因此该节点一定是作为叶节点而插入的。二者唯一的不同在于,默认插入的节点为红色,我们需要重新调整树结构从而确保红黑树重新达到平衡。

代码语言:javascript
复制
    @Override
    public void insert(T t) {
        Node<T> newNode = new Node<T>(t);
        if(root == null) {
            root = newNode;
            root.color = Node.BLACK;
            size++;
        } else {
            Node<T> tmp = root;
            while(tmp != null) {
                if(tmp.value.equals(t)) {
                    newNode = tmp;
                    break;
                } else if(tmp.value.compareTo(t) < 0) {
                    if(tmp.rightChild == null) {
                        tmp.rightChild = newNode;
                        newNode.parent = tmp;
                        size++;
                        break;
                    } else {
                        tmp = tmp.rightChild;
                    }
                } else {
                    if(tmp.leftChild == null) {
                        tmp.leftChild = newNode;
                        newNode.parent = tmp;
                        size++;
                        break;
                    } else {
                        tmp = tmp.leftChild;
                    }
                }
            }
        }
        adjust(newNode);
    }

    private void adjust(Node<T> node) {
        if(node.isRoot()) {
            node.color = Node.BLACK;
            return;
        } else if(node.parent.isRed()) {
            //肯定存在祖父节点,因为根节点必须为黑色
            Node<T> parent = node.parent;
            Node<T> grandParent = node.parent.parent;
            Node<T> uncle = node.getUncle();
            if(uncle!=null && uncle.isRed()) {
                parent.color = Node.BLACK;
                uncle.color = Node.BLACK;
                grandParent.color = Node.RED;
                adjust(grandParent);
            } else {
                if(node.isLeftChild() && node.parent.isLeftChild()) {
                    parent.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateRight(grandParent);
                } else if(node.isRightChild() && node.parent.isRightChild()) {
                    parent.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateLeft(grandParent);
                } else if(node.isLeftChild() && node.parent.isRightChild()) {
                    node.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateRight(parent);
                    rotateLeft(grandParent);
                } else {
                    node.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateLeft(parent);
                    rotateRight(grandParent);
                }
            }
        }
    }

删除

待更新

源码

代码语言:javascript
复制
public interface RedBlackTreeADT<T extends Comparable<T>> {    
    boolean contains(T t);
    
    void insert(T t);
    
    void delete(T t);
    
    int size();
    
}


public class RedBlackTree<T extends Comparable<T>> implements RedBlackTreeADT<T>{

    private int size;
    private Node<T> root;
    
    private static class Node<T>{
        static final int RED = 0;
        static final int BLACK = 1;
        T value;
        int color = RED;
        Node<T> leftChild;
        Node<T> rightChild;
        Node<T> parent;
        
        Node(T value) {
            this.value = value;
        }
    
        boolean isRoot() {
            return this.parent == null;
        }
        
        boolean isLeaf() {
            return this.leftChild == null && this.rightChild == null;
        }
        
        boolean isLeftChild() {
            return this.parent != null && this.parent.leftChild == this;
        }
        
        boolean isRightChild() {
            return this.parent != null && this.parent.rightChild == this;
        }
        
        Node<T> getUncle() {
            if(this.parent == null || this.parent.parent == null) return null;
            if(this.parent.isLeftChild()) {
                return this.parent.parent.rightChild;
            } else {
                return this.parent.parent.leftChild;
            }
                        
        }
        
        Node<T> getSibling() {
            if(this.parent == null) return null;
            return this.parent.leftChild == this ? this.parent.rightChild : this.parent.leftChild;
        }
    
        
        boolean isRed() {
            return this.color == RED;
        }
        
        boolean isBlack() {
            return this.color == BLACK;
        }
    }

    @Override
    public boolean contains(T t) {
        Node<T> tmp = root;
        while(tmp != null) {
            int cmp = tmp.value.compareTo(t);
            if(cmp == 0) {
                return true;
            } else if (cmp < 0) {
                tmp = tmp.rightChild;
            } else {
                tmp = tmp.leftChild;
            }
        }
        return false;
    }

    @Override
    public void insert(T t) {
        Node<T> newNode = new Node<T>(t);
        if(root == null) {
            root = newNode;
            root.color = Node.BLACK;
            size++;
        } else {
            Node<T> tmp = root;
            while(tmp != null) {
                if(tmp.value.equals(t)) {
                    newNode = tmp;
                    break;
                } else if(tmp.value.compareTo(t) < 0) {
                    if(tmp.rightChild == null) {
                        tmp.rightChild = newNode;
                        newNode.parent = tmp;
                        size++;
                        break;
                    } else {
                        tmp = tmp.rightChild;
                    }
                } else {
                    if(tmp.leftChild == null) {
                        tmp.leftChild = newNode;
                        newNode.parent = tmp;
                        size++;
                        break;
                    } else {
                        tmp = tmp.leftChild;
                    }
                }
            }
        }
        adjust(newNode);
    }

    private void adjust(Node<T> node) {
        if(node.isRoot()) {
            node.color = Node.BLACK;
            return;
        } else if(node.parent.isRed()) {
            //肯定存在祖父节点,因为根节点必须为黑色
            Node<T> parent = node.parent;
            Node<T> grandParent = node.parent.parent;
            Node<T> uncle = node.getUncle();
            if(uncle!=null && uncle.isRed()) {
                parent.color = Node.BLACK;
                uncle.color = Node.BLACK;
                grandParent.color = Node.RED;
                adjust(grandParent);
            } else {
                if(node.isLeftChild() && node.parent.isLeftChild()) {
                    parent.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateRight(grandParent);
                } else if(node.isRightChild() && node.parent.isRightChild()) {
                    parent.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateLeft(grandParent);
                } else if(node.isLeftChild() && node.parent.isRightChild()) {
                    node.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateRight(parent);
                    rotateLeft(grandParent);
                } else {
                    node.color = Node.BLACK;
                    grandParent.color = Node.RED;
                    rotateLeft(parent);
                    rotateRight(grandParent);
                }
            }
        }
    }
    
    private void rotateLeft(Node<T> node) {
        if(node == null || node.rightChild == null) return;
        Node<T> parent = node.parent;
        Node<T> rightChild = node.rightChild;
        
        if(rightChild.leftChild != null) {
            node.rightChild = rightChild.leftChild;
            node.rightChild.parent = node;
        } else {
            node.rightChild = null;
        }
        
        rightChild.leftChild = node;
        node.parent = rightChild;
        
        if(parent != null) {
            rightChild.parent = parent;
            if(node == parent.leftChild) {
                parent.leftChild = rightChild;
            } else {
                parent.rightChild = rightChild;
            }
        } else {
            rightChild.parent = null;
            root = rightChild;
        }
    }
    
    private void rotateRight(Node<T> node) {
        if(node == null || node.leftChild == null) return;
        Node<T> parent = node.parent;
        Node<T> leftChild = node.leftChild;
        
        if(leftChild.rightChild != null) {
            node.leftChild = leftChild.rightChild;
            node.leftChild.parent = node;
        } else {
            node.leftChild = null;
        }
        

        leftChild.rightChild = node;
        node.parent = leftChild;
        
        if(parent != null) {
            leftChild.parent = parent;
            if(node == parent.leftChild) {
                parent.leftChild = leftChild;
            } else {
                parent.rightChild = leftChild;
            }
        } else {
            leftChild.parent = null;
            root = leftChild;
        }
    }
    

    @Override
    public int size() {
        return size;
    }
    

    public void printTree() {
        this.printTree(this.root);
    }
    
    private void printTree(Node<T> root) {
        if(root == null) {
            System.out.print("nil(BLACK)");
            return;
        }
        printTree(root.leftChild);
        System.out.print(root.value + "(" + (root.color==Node.RED ? "RED" : "BLACK") + ")");
        printTree(root.rightChild);
    }

    @Override
    public void delete(T t) {
        // TODO Auto-generated method stub
        
    }
}

有任何问题,欢迎指出!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 参考链接
  • 数据结构
  • 旋转操作
  • 插入
  • 删除
    • 源码
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档