二叉树、红黑树

二叉树

1.什么是二叉树?

每个树节点只有两个分支的树形数据结构,按照数值左小右大分布

数据结构可视化: https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

二叉树使用:https://www.cs.usfca.edu/~galles/visualization/BST.html

2.写一个二叉树程序

实现添加元素、遍历元素功能

(1)添加原理:

(2)遍历原理:

  • 先续遍历: 中 -> 左 -> 右

  • 中序遍历: 左 -> 中 -> 右 , 最常见的遍历顺序, 输出结果是排序的!

  • 后续遍历: 左 -> 右 -> 中

手写程序如下:

 package list;
 
 /**
  * 手写二叉树
  * @param <T>
  */
 public class MyTreeSet<T> {
     //根节点
     private Node root;
 
     /**
      * 内部节点类Node
      * @param <T>
      */
     private static class Node<T>{
         T value;//节点内部存储的值
         Node left;//左节点
         Node right;//右节点
 
         /**
          * 构造方法
          * @param e 元素值
          */
         public Node(T e){
             value = e;
        }
 
         /**
          * 添加子节点
          * @param e
          * @return
          */
         public boolean addChild(T e){
             //先比较大小,如果小了,就加到左侧;如果大了,就加到右侧
             //将e转化为可比较的对象obj,转换类型以后就为了调用比较大小方法
             Comparable obj = (Comparable)e;
             //将obj与value进行比较
             int result = obj.compareTo(value);
             //obj.compareTo(value) 返回: 0     相等
             //                         正数 obj>value
             //                         负数 obj<value
             //int result = val.compareTo(root.value);
             //1.数据不允许重复,重复就返回false,表示添加失败
             if(result==0){
                 return false;
            }else if (result<0){//e<value 向左侧添加
                 if(left==null){//无左节点
                     left = new Node(e);//创建一个新的左节点
                     System.out.println("添加:"+value+"的左侧"+e);
                     return true;
                }else{
                     return left.addChild(e);//有左节点,递归调用添加节点
                }
            }else{//e>value 向右侧添加
                 if(right ==null){
                     right = new Node(e);
                     System.out.println("添加:"+value+"的右侧"+e);
                     return true;
                }else{
                     return right.addChild(e);
                }
            }
        }
 
         /*
          * 中序遍历算法
          */
         public void appendTo(StringBuilder builder){
             //判断是否有左节点
             if(left != null){
                 left.appendTo(builder);//递归拼接左节点
            }
             //System.out.println("添加:"+value);
             builder.append(value).append(", ");//添加中间节点和", "
             //判断是否有右节点
             if (right != null){
                 right.appendTo(builder);//递归拼接右节点
            }
        }
    }
 
     /**
      * 添加节点
      * @param e 要添加的元素
      * @return
      */
     public boolean add(T e){
         //没有根节点
         if(root == null){
             root = new Node(e);//创建根节点
             System.out.println("添加根元素:"+e);
             return true;
        }
         //已经有了根节点,先检查对象是否能进行大小比较,判断e是否是可以进行比较的
         if(!(e instanceof Comparable)){//不可以比较,抛出异常
             throw new RuntimeException("无比较大小方法:" + e);
        }else{//可以比较
             //调用方法,添加子节点
             return root.addChild(e);
        }
    }
 
     /**
      * 重写toString方法
      * @return
      */
     @Override
     public String toString() {
         //1.没有根节点,说明没有元素
         if (root==null){
             return "[]";
        }
         //2.根节点存在
         StringBuilder builder = new StringBuilder("[");//先拼接[
         //将StringBuilder添加到根元素中
         root.appendTo(builder);
         //删除最后一个逗号和空格   起点             终点
         builder.delete(builder.length()-2, builder.length());
         //拼接最后一个]
         return builder.append(']').toString();
    }
 }

测试程序:

 package list;
 
 /**
  * 测试MyTreeSet
  */
 public class Demo09 {
     public static void main(String[] args) {
         MyTreeSet<Integer> treeSet = new MyTreeSet<>();
         treeSet.add(680);
         treeSet.add(560);
         treeSet.add(750);
         treeSet.add(520);
         treeSet.add(600);
         treeSet.add(700);
         treeSet.add(800);
         System.out.println(treeSet);//自动调用toString方法,按元素大小输出结果
    }
 }

输出结果:

[520, 560, 600, 680, 700, 750, 800]

 

红黑树

1.解决二叉树不平衡问题

  • 二叉树存在不平衡现象,不平衡的二叉树查询性能差!

  • 有专家提出红黑树策略, 利用红黑树规则可以自动调整二叉树的平衡问题

  • 红黑树也称为:自平衡二叉树.

2.红黑树定义和性质

  红黑树是一种含有红黑结点并能自平衡的二叉查找树。

  可视化工具https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

它必须满足下面性质:

  • 性质1:每个节点要么是黑色,要么是红色。

  • 性质2:根节点是黑色。

  • 性质3:每个叶子节点(NIL)是黑色。

  • 性质4:每个红色结点的两个子结点一定都是黑色, 不能两个相邻的红色节点.

  • 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

关于红黑树:

  • 红黑树就是一个自动调整平衡的二叉树

  • 满足红黑规则的二叉树是平衡二叉树

  • 在插入元素时候, 如果造成二叉树不满足红黑规则, 则失去平衡

    • 利用左旋\右旋\调整颜色最终达到满足红黑规则, 实现调整平衡

  • 红黑树可以保持很好的查询性能

  • java 中的 TreeMap内部就是红黑树, 按照key比较大小, 按照key查询

  • java中的 TreeSet 内部封装的是 TreeMap, 利用Map的key存储数据.

    同理,HashMap内部封装的是Array,HashSet内部封装的是HashMap

3.利用Debug调试TreeMap

测试程序:

 package list;
 
 import java.util.TreeMap;
 
 public class Demo10 {
     public static void main(String[] args) {
         /**
          * TreeMap是Java提供的二叉排序树,其内部算法是红黑树
          * 使用时,按照key大小排序,左小右大
          * key必须能够比较大小:
          * 1.实现Comparable自然比较大小
          * 2.提供自定义比较器Comparator
          * 查询时候,根据key查找二叉树找到value
          */
         /*
          * 利用Debug分析TreeMap的内部结构
          * Debug调试过程:
          * Debug‘Demo010’-->在treeMap上右键-->View as-->选择Object-->treeMap出现下三角
          * -->出现comparator、root、size、modCount、entrySet、navigableKeySet、descendingMap、keySet、values等属性
          *
          * 在出现插入的元素内容上,右键,View as,选择Object,此时内容变为元素插入位置下标
          */
         TreeMap<Integer,String> treeMap = new TreeMap<>();
         treeMap.put(670,"1");
         treeMap.put(570,"2");
         treeMap.put(470,"3");
    }
 }

调试过程:

 

posted @ 2021-08-18 23:00  Coder_Cui  阅读(204)  评论(0编辑  收藏  举报