《漫画算法2》源码整理-1 二分查找树 AVL树 红黑树

Posted GarfieldEr007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《漫画算法2》源码整理-1 二分查找树 AVL树 红黑树相关的知识,希望对你有一定的参考价值。

二分查找树

public class BinarySearchTree 
    private Node root;

    //查找结点
    public Node search(int data) 
        Node targetNode = root;
        while (targetNode!=null && targetNode.data != data) 
            if (data > targetNode.data) 
                targetNode = targetNode.right;
             else 
                targetNode = targetNode.left;
            
        
        if(targetNode == null)
            System.out.println("未找到结点:" + data);
         else 
            System.out.println("已找到结点:" + data);
        
        return targetNode;
    

    //中序遍历
    public static void inOrderTraversal(Node node)
        if(node == null)
            return;
        
        inOrderTraversal(node.left);

        System.out.print(node.data + " ");
        inOrderTraversal(node.right);
    

    //插入结点
    public boolean insert(int data) 
        Node node = new Node(data);
        if(root == null)
            root = node;
            return true;
        
        Node targetNode  = root;
        while (targetNode != null) 
            if( data == targetNode.data)
                System.out.println("二叉查找树中已有重复的结点:" + data);
                return false;
            
            else if (data > targetNode.data) 
                if(targetNode.right == null)
                    targetNode.right = node;
                    return true;
                
                targetNode = targetNode.right;
            
            else 
                if(targetNode.left == null)
                    targetNode.left = node;
                    return true;
                
                targetNode = targetNode.left;
            
        
        return true;
    

    //删除结点
    public boolean delete(int data) 
        Node targetNode = root;
        Node parentNode = new Node(data);
        //判断待删除结点是否存在
        while (targetNode.data != data) 
            parentNode = targetNode;
            if (data > targetNode.data) 
                targetNode = targetNode.right;
             else 
                targetNode = targetNode.left;
            
            if (targetNode == null) 
                // 没有找到待删除结点
                return false;
            
        
        // 待删除结点没有子节点
        if (targetNode.right==null && targetNode.left==null) 
            if (targetNode == root) 
                //待删除结点是根结点
                root = null;
             else 
                if (parentNode.right == targetNode) 
                    parentNode.right = null;
                 else 
                    parentNode.left = null;
                
            
        
        //待删除结点有一个子结点(右)
        else if(targetNode.left == null) 
            if(targetNode == root) 
                root = targetNode.right;
             else if(parentNode.right == targetNode) 
                parentNode.right = targetNode.right;
             else 
                parentNode.left = targetNode.right;
            
        
        //待删除结点有一个子结点(左)
        else if(targetNode.right == null) 
            if(targetNode == root) 
                root = targetNode.left;
             else if(parentNode.right == targetNode) 
                parentNode.right = targetNode.left;
             else 
                parentNode.left = targetNode.left;
            
        
        //待删除结点有两个子结点
        else 
            //待删除结点的后继结点的父结点
            Node successParentNode = targetNode;
            //待删除结点的后继结点
            Node successNode = targetNode.right;
            while(successNode.left != null)
            
                successParentNode = successNode;
                successNode = successNode.left;
            
            //把后继结点复制到待删除结点位置
            targetNode.data = successNode.data;
            //删除后继结点
            if(successParentNode.right == successNode) 
                successParentNode.right = successNode.right;
             else 
                successParentNode.left = successNode.right;
            
        
        return true;
    

    // 结点类
    private class Node 
        int data;
        Node right;
        Node left;

        Node(int data)
            this.data = data;
        
    

    public static void main(String[] args) 
        BinarySearchTree tree = new BinarySearchTree();
        int input[]= 6,3,8,2,5,7,9,1,4;
        for(int i=0; i<input.length; i++) 
            tree.insert(input[i]);
        
        inOrderTraversal(tree.root);
        System.out.println();
        tree.search(3);
        tree.delete(3);
        tree.search(3);
        tree.delete(6);
        inOrderTraversal(tree.root);
    


AVL树

import java.util.LinkedList;
import java.util.Queue;

public class AVLTree 
    private TreeNode root;
    /*
     * 获取树的高度
     */
    private int height(TreeNode node) 
        if (node != null)
            return node.height;

        return 0;
    

    public int height() 
        return height(root);
    

    //查找结点
    public TreeNode search(TreeNode node, int data) 
        while (node!=null) 
            if (data < node.data)
                node = node.left;
            else if (data > node.data)
                node = node.right;
            else
                return node;
        
        return node;
    

    //左左局面旋转
    private TreeNode leftLeftRotation(TreeNode node) 
        //leftChildNode 对应示意图中的结点B
        TreeNode leftChildNode = node.left;
        node.left = leftChildNode.right;
        leftChildNode.right = node;
        //刷新结点A和结点B的高度
        node.height = Math.max(height(node.left), height(node.right)) + 1;
        leftChildNode.height = Math.max(height(leftChildNode.left), node.height) + 1;
        //返回旋转后的父结点
        return leftChildNode;
    

    //右右局面旋转
    private TreeNode rightRightRotation(TreeNode node) 
        //rightChildNode 对应示意图中的结点B
        TreeNode rightChildNode = node.right;
        node.right = rightChildNode.left;
        rightChildNode.left = node;
        //刷新结点A和结点B的高度
        node.height = Math.max(height(node.left), height(node.right)) + 1;
        rightChildNode.height = Math.max(height(rightChildNode.right), node.height) + 1;
        //返回旋转后的父结点
        return rightChildNode;
    

    //左右局面旋转
    private TreeNode leftRightRotation(TreeNode node) 
        //先做左旋
        node.left = rightRightRotation(node.left);
        //再做右旋
        return leftLeftRotation(node);
    

    //右左局面旋转
    private TreeNode rightLeftRotation(TreeNode node) 
        //先做右旋
        node.right = leftLeftRotation(node.right);
        //再做左旋
        return rightRightRotation(node);
    

    //插入结点
    public void insert(int data) 
        root = insert(root, data);
    

    //插入结点详细过程(递归)
    private TreeNode insert(TreeNode node, int data) 
        if (node == null) 
            node = new TreeNode(data);
         else 
            if (data < node.data) 
                //新结点小于当前结点,选择当前结点的左子树插入
                node.left = insert(node.left, data);
                // 插入节点后,若AVL树失去平衡,则进行相应的调节。
                if (node.getBalance() == 2) 
                    if (data < node.left.data) 
                        node = leftLeftRotation(node);
                     else 
                        node = leftRightRotation(node);
                    
                
             else if (data > node.data)  
                //新结点大于当前结点,选择当前结点的右子树插入
                node.right = insert(node.right, data);
                // 插入节点后,若AVL树失去平衡,则进行相应的调节。
                if (node.getBalance() == -2) 
                    if (data > node.right.data) 
                        node = rightRightRotation(node);
                     else 
                        node = rightLeftRotation(node);
                    
                
             else 
                System.out.println("AVL树中已有重复的结点!");
            
        
        //刷新结点的高度
        node.height = Math.max(height(node.left), height(node.right)) + 1;
        return node;
    

    //删除结点
    public void remove(int data) 
        TreeNode deletedNode;
        if ((deletedNode = search(root, data)) != null)
            root = remove(root, deletedNode);
    

    //删除结点详细过程(递归)
    private TreeNode remove(TreeNode node, TreeNode deletedNode) 
        // 根为空 或者 没有要删除的节点,直接返回null。
        if (node==null || deletedNode==null)
            return null;
        if (deletedNode.data < node.data)
            //待删除结点小于当前结点,在当前结点的左子树继续执行
            node.left = remove(node.left, deletedNode);
            // 删除节点后,若AVL树失去平衡,则进行相应的调节。
            if (height(node.right) - height(node.left) == 2) 
                TreeNode r =  node.right;
                if (height(r.left) > height(r.right))
                    node = rightLeftRotation(node);
                else
                    node = rightRightRotation(node);
            
         else  if (deletedNode.data > node.data) 
            //待删除结点大于当前结点,在当前结点的右子树继续执行
            node.right = remove(node.right, deletedNode);
            // 删除节点后,若AVL树失去平衡,则进行相应的调节。
            if (height(node.left) - height(node.right) == 2) 
                TreeNode l =  node.left;
                if (height(l.right) > height(l.left))
                    node = leftRightRotation(node);
                else
                    node = leftLeftRotation(node);
            
         else 
            // tree的左右孩子都非空
            if ((node.left!=null) && (node.right!=null)) 
                if (height(node.left) > height(node.right)) 
                    // 如果node的左子树比右子树高,找出左子树最大结点赋值给Node,并删除最小结点
                    TreeNode max = maximum(node.left);
                    node.data = max.data;
                    node.left = remove(node.left, max);
                 else 
                    // 如果node的右子树比左子树高,找出右子树最小结点赋值给Node,并删除最小结点
                    TreeNode min = minimum(node.right);
                    node.data = min.data;
                    node.right = remove(node.right, min);
                
             else 
                node = (node.left!=null) ? node.left : node.right;
            
        
        node.height = Math.max(height(node.left), height(node.right)) + 1;
        return node;
    

    //找出结点node为根的子树的最大节点
    private TreeNode maximum(TreeNode node) 
        if (node == null)
            return null;
        while(node.right != null)
            node = node.right;
        return node;
    

    //找出结点node为根的子树的最小节点
    private TreeNode minimum(TreeNode node) 
        if (node == null)
            return null;
        while(node.left != null)
            node = node.left;
        return node;
    

    //中序遍历
    public static void inOrderTraversal(TreeNode node) 
        if(node != null) 
            inOrderTraversal(node.left);
            System.out.print(node.data+" ");
            inOrderTraversal(node.right);
        
    

    //层序遍历
    public static void levelOrderTraversal(TreeNode root)
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty())
            TreeNode node = queue.poll();
            System.out.print(node.data+" ");
            if(node.left != null)
                queue.offer(node.left);
            
            if(node.right != null)
                queue.offer(node.right);
            
        
    

    class TreeNode 
        int data;
        int height;
        TreeNode left;
        TreeNode right;

        public TreeNode(int data) 
            this.data = data;
            this.height = 0;
        

        //获得结点的平衡因子
        public int getBalance()
            int left =  (this.left==null ? 0:this.left.height);
            int right = (this.right==null ? 0:this.right.height);
            return left - right;
        
    

    public static void main(String[] args) 
        AVLTree tree = new AVLTree();
        int input[]= 5,3,7,2,4,6,9,1;
        for(int i=0; i<input.length; i++) 
            tree.insert(input[i]);
        
        System.out.println("中序遍历: ");
        inOrderTraversal(tree.root);
        System.out.println();
        System.out.println("层序遍历: ");
        levelOrderTraversal(tree.root);
        System.out.println();
        System.out.printf("高度: %d\\n", tree.height());
        int deletedData = 3;

        System.out.printf("删除根节点: %d\\n", deletedData);
        tree.remove(deletedData);

        System.out.println("中序遍历: ");
        inOrderTraversal(tree.root);
        System.out.println();
        System.out.println("层序遍历: ");
        levelOrderTraversal(tree.root);
        System.out.println();
        System.out.printf("高度: %d\\n", tree.height());
    


红黑树


import java.util.LinkedList;
import java.util.Queue;

public class RedBlackTree 
    TreeNode root;
    final static boolean RED = true;
    final static boolean BLACK = false;

    //查找结点
    public TreeNode search(int data) 
        TreeNode tmp = root;
        while (tmp != null) 
            if (tmp.data == data)
                return tmp;
            else if (tmp.data > data)
                tmp = tmp.left;
            else
                tmp = tmp.right;
        
        return null;
    

    //插入结点
    public boolean insert(int data) 
        TreeNode node = new TreeNode(data);
        //局面1:新结点位于树根,没有父结点。
        if (root == null) 
            root = node;
            node.color = BLACK;
            return true;
        
        TreeNode targetNode = root;
        while (targetNode != null) 
            if( data == targetNode.data)
                System.out.println("红黑树中已有重复的结点:" + data);
                return false;
             else if (data > targetNode.data) 
                if(targetNode.right == null)
                    targetNode.right = node;
                    node.parent = targetNode;
                    insertAdjust(node);
                    return true;
                
                targetNode = targetNode.right;
             else 
                if(targetNode.left == null)
                    targetNode.left = node;
                    node.parent = targetNode;
                    insertAdjust(node);
                    return true;
                
                targetNode = targetNode.left;
            
        
        return true;
    

    //插入后自我调整
    private void insertAdjust(TreeNode node) 
        //创建父结点和祖父结点指针
        TreeNode parent, grandParent;
        //局面3的调整有可能引发后续的一系列调整,所以使用while循环。
        while (node.parent != null && node.parent.color == RED) 
            parent = node.parent;
            grandParent = parent.parent;
            if (grandParent.left == parent) 
                TreeNode uncle = grandParent.right;
                //局面3:新结点的父结点和叔叔结点都是红色。
                if (uncle != null && uncle.color == RED) 
                    parent.color = BLACK;
                    uncle.color = BLACK;
                    grandParent.color = RED;
                    node = grandParent;
                    continue;
                
                //局面4:新结点的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右孩子,父结点是祖父结点的左孩子。
                if (node == parent.right) 
                    leftRotate(parent);
                    TreeNode tmp = node;
                    node = parent;
                    parent = tmp;
                
                //局面5:新结点的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的左孩子,父结点是祖父结点的左孩子。
                parent.color = BLACK;
                grandParent.color = RED;
                rightRotate(grandParent);
             else 
                TreeNode uncle = grandParent.left;
                //局面3(镜像):新结点的父结点和叔叔结点都是红色。
                if (uncle != null && uncle.color == RED) 
                    parent.color = BLACK;
                    uncle.color = BLACK;
                    grandParent.color = RED;
                    node = grandParent;
                    continue;
                
                //局面4(镜像):新结点的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的左孩子,父结点是祖父结点的右孩子。
                if (node == parent.left) 
                    rightRotate(parent);
                    TreeNode tmp = node;
                    node = parent;
                    parent = tmp;
                
                //局面5(镜像):新结点的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右孩子,父结点是祖父结点的右孩子。
                parent.color = BLACK;
                grandParent.color = RED;
                leftRotate(grandParent);
            
        
        //经过局面3的调整,有可能把根结点变为红色,此时再变回黑色即可。
        if(root.color == RED)
            root.color = BLACK;
        
    

    //删除节点
    public void remove(int key) 
        remove(search(key));
    

    //删除节点详细逻辑
    private void remove(TreeNode node) 
        TreeNode targetNode = node;
        if (node == null)
            return;
        //第一步:如果待删除结点有两个非空的孩子结点,转化成待删除结点只有一个孩子(或没有孩子)的情况。
        if (node.left != null && node.right != null) 
            //待删除结点的后继结点
            TreeNode successNode = targetNode.right;
            while(successNode.left != null) 
                successNode = successNode.left;
            
            if(targetNode == root) 
                root = successNode;
            
            //把后继结点复制到待删除结点位置
            targetNode.data = successNode.data;
            remove(successNode);
            return;
        
        //第二步:根据待删除结点和其唯一子结点的颜色,分情况处理。
        TreeNode successNode = node.left!= null ? node.left : node.right;
        TreeNode parent = node.parent;
        if (parent == null) 
            //子情况1,被删除结点是红黑树的根结点:
            root = successNode;
            if (successNode != null)
                successNode.parent = null;
         else 
            if (successNode != null)
                successNode.parent = parent;
            if (parent.left == node)
                parent.left = successNode;
            else 
                parent.right = successNode;
            
        
        if (node.color == BLACK )
            //第三步:遇到双黑结点,在子结点顶替父结点之后,分成6种子情况处理。
            removeAdjust(parent, successNode);

    

    //删除结点后的自我调整
    private void removeAdjust(TreeNode parent, TreeNode node) 
        while ((node == null || node.color == BLACK) && node != root) 
            if (parent.left == node) 
                //node的兄弟节点
                TreeNode sibling = parent.right;
                //子情况3,node的兄弟结点是红色:
                if (sibling != null && sibling.color == RED) 
                    parent.color = RED;
                    sibling.color = BLACK;
                    leftRotate(parent);
                    sibling = parent.right;
                
                if (sibling == null || ((sibling.left == null || sibling.left.color == BLACK) && (sibling.right == null || sibling.right.color == BLACK))) 
                    //子情况2(镜像),node的父结点是黑色,兄弟和侄子结点是黑色:
                    if(parent.color == BLACK)
                        sibling.color = RED;
                        node = parent;
                        parent = node.parent;
                        continue;
                    
                    //子情况4(镜像),node的父结点是红色,兄弟和侄子结点是黑色:
                    else 
                        sibling.color = RED;
                        break;
                    
                
                //子情况5,node的父结点随意,兄弟结点是黑色右孩子,左侄子结点是红色,右侄子结点是黑色:
                if (sibling.left == null || sibling.color == RED) 
                    sibling.left.color = BLACK;
                    sibling.color = RED;
                    rightRotate(sibling);
                    sibling = sibling.parent;
                
                //子情况6,结点2的父结点随意,兄弟结点B是黑色右孩子,右侄子结点是红色:
                sibling.color = parent.color;
                parent.color = BLACK;
                sibling.right.color = BLACK;
                leftRotate(parent);
                node = root; //跳出循环
             else 
                //node的兄弟节点
                TreeNode sibling = parent.left;
                //子情况3(镜像),node的兄弟结点是红色:
                if (sibling != null && sibling.color == RED) 
                    parent.color = RED;
                    sibling.color = BLACK;
                    rightRotate(parent);
                    sibling = parent.left;
                
                if (sibling == null || ((sibling.left == null || sibling.left.color == BLACK) && (sibling.right == null || sibling.right.color == BLACK))) 
                    //子情况2(镜像),node的父结点是黑色,兄弟和侄子结点是黑色:
                    if(parent.color == BLACK)
                        sibling.color = RED;
                        node = parent;
                        parent = node.parent;
                        continue;
                    
                    //子情况4(镜像),node的父结点是红色,兄弟和侄子结点是黑色:
                    else 
                        sibling.color = RED;
                        break;
                    
                
                //子情况5(镜像),node的父结点随意,兄弟结点是黑色左孩子,右侄子结点是红色,左侄子结点是黑色:
                if (sibling.right == null || sibling.right.color == RED) 
                    sibling.right.color = BLACK;
                    sibling.color = RED;
                    leftRotate(sibling);
                    sibling = sibling.parent;
                
                //子情况6(镜像),结点2的父结点随意,兄弟结点是黑色左孩子,左侄子结点是红色:
                sibling.color = parent.color;
                parent.color = BLACK;
                sibling.left.color = BLACK;
                rightRotate(parent);
                node = root; //跳出循环
            
        
        if (node != null) 
            node.color = BLACK;
        
    

    //左旋转
    private void leftRotate(TreeNode node) 
        TreeNode right = node.right;
        TreeNode parent = node.parent;
        if (parent == null) 
            root = right;
            right.parent = null;
         else 
            if (parent.left != null && parent.left == node) 
                parent.left = right;
             else 
                parent.right = right;
            
            right.parent = parent;
        
        node.parent = right;
        node.right = right.left;
        if (right.left != null) 
            right.left.parent = node;
        
        right.left = node;
    

    //右旋转
    private void rightRotate(TreeNode node) 
        TreeNode left = node.left;
        TreeNode parent = node.parent;
        if (parent == null) 
            root = left;
            left.parent = null;
         else 
            if (parent.left != null && parent.left == node) 
                parent.left = left;
             else 
                parent.right = left;
            
            left.parent = parent;
        
        node.parent = left;
        node.left = left.right;
        if (left.right != null) 
            left.right.parent = node;
        
        left.right = node;
    

    //中序遍历
    public static void inOrderTraversal(TreeNode node) 
        if(node != null) 
            inOrderTraversal(node.left);
            System.out.print(node);
            inOrderTraversal(node.right);
        
    

    //层序遍历
    public static void levelOrderTraversal(TreeNode root)
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty())
            TreeNode node = queue.poll();
            System.out.print(node);
            if(node.left != null)
                queue.offer(node.left);
            
            if(node.right != null)
                queue.offer(node.right);
            
        
    

    class TreeNode 
        int data;
        boolean color;
        TreeNode left;
        TreeNode right;
        TreeNode parent;

        public TreeNode(int data) 
            this.data = data;
            this.color = RED;
        

        @Override
        public String toString() 
            return  data + (color?"(red)":"(black)") + "  " ;
        
    

    public static void main(String[] args) 
        RedBlackTree rbTree = new RedBlackTree();
        int input[]= 13,8,17,1,11,15,25,6,22,27;
        for(int i=0; i<input.length; i++) 
            rbTree.insert(input[i]);
        
        rbTree.remove(8);
        System.out.println("中序遍历: ");
        inOrderTraversal(rbTree.root);
        System.out.println();
        System.out.println("层序遍历: ");
        levelOrderTraversal(rbTree.root);
        System.out.println();
    


以上是关于《漫画算法2》源码整理-1 二分查找树 AVL树 红黑树的主要内容,如果未能解决你的问题,请参考以下文章

C++ 树进阶系列之平衡二叉查找树( AVL)的自平衡算法

动画 | 什么是平衡二分搜索树(AVL)?

13-自平衡二分搜索树 AVLTree

解密树的平衡:二分搜索树 → AVL自平衡树 → 左倾红黑树

解密树的平衡:二分搜索树 → AVL自平衡树 → 左倾红黑树

数据结构与算法二分钟初识树