TreeMap 学习记录

package cn.onloc.utils.conllection;

import cn.onloc.utils.User;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

//public class TreeMap_1 {

    /** TreeMap
     *  为什么要有树这种结构:
     *      其实在前面已经有了数组和链表这两种数据结构了,知道固定数据个数就用数组,不知道数据固定大小就用链表,按理来说已经不需要其他的数据结构了,但是如果在一个100个无序的数据集合
     *      中去判断是否含有某个值呢?用什么样的方式能够减少时间复杂度。如果是放在一个容积为100的数组中。最坏的情况是循坏100次才能判断成功,放在一个链表中也是的从第一个元素开始一直
     *      对比到最后。但是有没有更好的方法呢,所有就出现了树这种结构。
     *      基于这个问题提出的是一个二分搜索树的概念:
     *      1、每个树节点只有两个子节点
     *      2、树节点的左边肯定小于根节点,树节点的右边肯定大于根基点。
     *      这样的一颗二分搜索树,在进行判断一个值是否存在时,其结果相当于每次取中间值进行对比,不超过七次就能判断是否含有该值。
     *
     *  为什么要有treeMap
     *      都知道Hash结构其实是在内存中查询最快的一种数据结构,就是说吧(k,v)的键值对结构放在HashMap中,去取值的时候肯定是最快的,但是有些工作情况在是对键值对的单个数据取值,
     *      还需要对其存放的内容根据某个条件去排序时,HashMap就显得没法完成了,因为他在内存数组中的存放顺序是无序的,所以就提出了TreeMap的概念。
     *
     *  为什么实现方式是红黑树而不是AVL或者其他的平衡二叉树
     *      AVL树:
     *      1、满足二叉树的特点
     *      2、任意节点的左节点和右节点的高度差不能超过1。
     *      对于一颗树结构来说,为了满足这第二个条件需要对存放的数据进行多次的左右旋转才能保证这个条件。相对来说是一种消耗性能的过程。
     *      红黑树:
     *      1、满足二叉树的特点
     *      2、跟节点和所有的末梢节点都是黑色,所有的节点红黑相间
     *      3、任意节点到他的所有末梢节点所经历过得黑节点数目是一致的
     *      其中第三点仔细理解就是定义它为一颗平衡树的根本,所经历的黑色节点一致,就保证了任意左右节点的差最大为,所有他只是一颗相对严谨的平衡树
     *
     *      在一个对树节点有大量增删的操作中,红黑树的性能是肯定远远大于AVL树的。所有treeMap的底层结构选择的是红黑树
     *
     * 对于键值对方式的实现方式
     *      所谓的数据结构也就是读一些类所做得特殊或者说是一些很巧妙的处理,用来实现相关数据结构的特性,其在内存中的存储也是分为连接在一起的叫数组。不是连接在一起的肯定就是通过记录其
     *      内存地址来实现的,而要一个类又要记录键值对,又要记录其下一个数据的地址,肯定就需要用到内部类了,就是把需要记录的信息放在一个Node类中,所有的操作就是对Node类的一个操作和记录了。
     *      看下源码对node的定义:
     *     static final class Entry<K,V> implements Map.Entry<K,V> {
     *         K key;     // 键
     *         V value;   // 值
     *         Entry<K,V> left;    // 指向左子树的引用(指针)
     *         Entry<K,V> right;   // 指向右子树的引用(指针)
     *         Entry<K,V> parent;  // 指向父节点的引用(指针)
     *         boolean color = BLACK; //
     *     }

     *
     *  假定自己对一个集合所需要哪些操作:(还有很多api后面补充)
     *      1、新增
     *     public V put(K key, V value) { //其实整个方法对于了解树结构实现的话是很简单的,下面是简单的源码截取
     *         Entry<K,V> t = root; // 把当前节点放在一个定义的t对象中
     *         if (t == null) {  //如果第一次进来,当前节点为null,表示是根节点,则只把把相关数据进行存储
     *             compare(key, key); // type (and possibly null) check
     *             root = new Entry<>(key, value, null);
     *             size = 1;
     *             modCount++;
     *             return null;
     *         }
     *        Comparator<? super K> cpr = comparator; //比较器对象,treeMap初始化的比较器对象为null
     *         if (cpr != null) { // 当用户没有定义比较器对象时,则执行默认的比较器。
     *             do {
     *                 parent = t; //首先把parent对象指向当前节点
     *                 cmp = cpr.compare(key, t.key); //根据默认节点来判断现在存储的key值应该放在当前节点的左边还是右边
     *                 if (cmp < 0)
     *                     t = t.left;
     *                 else if (cmp > 0)
     *                     t = t.right;
     *                 else
     *                     return t.setValue(value); // 如果key和某个节点相等,则直接替换,然后结束整个put方法
     *             } while (t != null);
     *         }
     *         Entry<K,V> e = new Entry<>(key, value, parent); //已经找好数据要存放的节点了,把数据拼装好
     *         if (cmp < 0)
     *             parent.left = e;
     *         else
     *             parent.right = e;
     *         fixAfterInsertion(e); //可以画重点,这个就是保证treemap红黑树平衡的关键方法。用的也是一些左右旋的知识。 https://www.jianshu.com/p/454208905619
     *         size++;
     *         modCount++;
     *         return null;
     *     }
     *
     *      2、删除
     *          public v remove(k k), 根据k去删除元素,并返回已经删除掉的元素,k不存在则返回一个null
     *          public boolean remove(k k, v v), 根据key和value去删除元素,有则删除并发返回true,没有则返回false,有的意思是键值对都对
     *      3、修改
     *          所谓的修改就是传入相同的key,就能执行对值的替换
     *      4、查询
     *          public v get(k k);
     *          键值对的存储都能够通过key去get到值。
     *      5、循环
     *          怎么去理解他不能用for遍历呢? for遍历是根据下标去一个以前取值的,像数组和链表其实是有下标的。HashMap是无序的所有不能用for,我的理解,对于一个树结构其实也是没有下标的,
     *          如果有下标的话那他是按照广度优先还是深度优先呢,所以我认为他不能用下标的方式进行for循环遍历。
     *          对treeMap的源码分析我们可以知道,其所有map的结构也都是在底层封装了一个内部类(Map.Entry), 然后可以暂时理解为当treeMap在放入put添加元素的时候,会把相关的Entry放在一个
     *          set集合中,有一个方法可以获取到这个集合,public set<Map.Entry<K,V>> EntrySet();
     *          还有一个方法可以获取所以key的集合: public set<k> keySet();
     *      6、复制
     *      7、排序
     *          1、
     *          因为treeMap的put函数回去判断是否有比较器,所以在他的构造函数中可是传入一个自定义的比较器,
     *          但是注意,比较器是把put中的key拿来作为条件进行比较的。
     *          public treeMap(new compartor(){});
     *          2、
     *          comparable 和 comparator 的比较
     *          1、首先两个都是比较器。
     *          comparable 主要是实现在一个类上,类去重写一个public int comparaTo(Object o)的方法,通过返回值来进行判断排序。
     *          comparator 主要使用在一个类他没有继承comparable的时候,又想和他自身进行比较,这时候就可以使用这个外部的比较器进行比较了。
     *      8、转数组
     *          其不属于collection体系,没有toArray方法
     */

    public static void main(String[] args) {

        {
            //新增
            Map<String, Object> map = new TreeMap();
            map.put("a", 1);
            map.put("b", 3);
            map.put("d", 4);
            map.put("c", 2);
            System.out.println(" treeMap 的原始值: " + map);
            // treeMap 的原始值: {a=1, b=3, c=2, d=4}
        }

     /*   {
            //删除
            Map<String, Object> map = new TreeMap();
            map.put("a", 1);
            map.put("b", 3);
            map.put("d", 4);
            map.put("c", 2);
            System.out.println(" treeMap 的原始值: " + map);
            // treeMap 的原始值: {a=1, b=3, c=2, d=4}

            Object o = map.remove("a");
            System.out.println("treeMap 删除以后: " + map + ", remove返回值 : " + o);
            //treeMap 删除以后: {b=3, c=2, d=4}, remove返回值 : 1

            Object ooo = map.remove("aa");
            System.out.println("remove不存在的元素:" + ooo  + ",结果: " + map );
            //remove不存在的元素:null,结果: {b=3, c=2, d=4}

            Object oo = map.remove("1", 2);
            System.out.println("remove不存在的元素:" + oo  + ",结果: " + map );
            //remove不存在的元素:false,结果: {b=3, c=2, d=4}

            Object oo2 = map.remove("c", 1);
            System.out.println("remove存在key的元素 :" + oo2 + ",结果: " + map );
            //remove存在key的元素 :false,结果: {b=3, c=2, d=4}

            Object oo1 = map.remove("c", 2);
            System.out.println("remove存在key和value的元素 :" + oo1 + ",结果: " + map );
            //remove存在key和value的元素 :true,结果: {b=3, d=4}

        }*/

        {
            //遍历
            Map<String, Object> map = new TreeMap();
            map.put("a", 1);
            map.put("b", 3);
            map.put("d", 4);
            map.put("c", 2);
            System.out.println(" treeMap 的原始值: " + map);
            // treeMap 的原始值: {a=1, b=3, c=2, d=4}

            Iterator<Map.Entry<String, Object>> entry = map.entrySet().iterator();
            while(entry.hasNext()) {
                System.out.println(" entry : " + entry.next());
            }
            // entry : a=1
            // entry : b=3
            // entry : c=2
            // entry : d=4

            Iterator<String> keys = map.keySet().iterator();
            while(keys.hasNext()) {
                System.out.println(" keys : " + keys.next());
            }
            // keys : a
            // keys : b
            // keys : c
            // keys : d
        }

        {
            //查询
            Map<String, Object> map = new TreeMap();
            map.put("a", 1);
            map.put("b", 3);
            map.put("d", 4);
            map.put("c", 2);
            System.out.println(" treeMap 的原始值: " + map);
            // treeMap 的原始值: {a=1, b=3, c=2, d=4}

            Object a = map.get("a");
            System.out.println("TreeMap 查询的值: " + a);
            //TreeMap 查询的值: 1
        }

        {
            //排序
            User zs = new User("张三", 23);
            User ls = new User("李四", 24);
            User ww = new User("王五", 25);

            Map<User, String> map1 = new TreeMap(new Comparator<User>(){
                @Override
                public int compare(User o1, User o2) {
                    return o1.getAge() - o2.getAge();
                }
            });
            map1.put(ww, "aa");
            map1.put(zs, "cc");
            map1.put(ls, "bb");
            System.out.println(" treeMap map1的原始值: " + map1);
            // treeMap 的原始值: {User{age=23, name='张三', sex=null}=cc, User{age=24, name='李四', sex=null}=bb, User{age=25, name='王五', sex=null}=aa}

            TreeMap<User, String> map = new TreeMap();
            map.put(ww, "ww");
            map.put(zs, "zs");
            map.put(ls, "ls");
            System.out.println(" treeMap map的原始值: " + map);
            // treeMap map的原始值: {User{age=23, name='张三', sex=null}=zs, User{age=24, name='李四', sex=null}=ls, User{age=25, name='王五', sex=null}=ww}

        }






    }



//}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值