zoukankan      html  css  js  c++  java
  • TreeSet与TreeMap浅解

    TreeSet与TreeMap的关系:

    1.TreeSet 实际上就是用TreeMap来组织数据的,因为在TreeSet中保存了一个NavigableMap<e,Object>接口实例变量,而该接口的实现类就是TreeMap

    image

    image

    2.TreeSet与TreeMap都是用二叉树的数据结构来存储数据

    3.TreeSet和TreeMap中保存的数据除了Integer和String等有默认顺序的类型外的自定义类型都需要实现Comparable接口并重写compareTo()方法。

    TreeSet和TreeMap添加数据:

    TreeSet的add方法会调用TreeMap的put方法

    image

    TreeMap的put()方法的实现,

    public V put(K key, V value) {
            Entry<K,V> t = root;
        //判断二叉树中是否存在根节点如果存在则床建根节点
            if (t == null) {
                root = new Entry<K,V>(key, value, null);//创建根节点
                size = 1;//将该集合的元素个数设为1
                modCount++;
                return null;
            }
            int cmp;
            Entry<K,V> parent;//声明父节点
            Comparator<? super K> cpr = comparator;//创建比较器
            if (cpr != null) {//该集合有自定义比较器
                do {
                    parent = t;//将父节点设为t (第一次t为根节点)
                    cmp = cpr.compare(key, t.key);//将根节点的key与参数中的key进行比较
                    if (cmp < 0)//key<t.key
                        t = t.left;
                    else if (cmp > 0)//key>t.key
                        t = t.right;
                    else
                        return t.setValue(value);//key==t.key
                } while (t != null);
            }
            else {//该集合没有自定义比较器
                if (key == null)
                    throw new NullPointerException();
                Comparable<? super K> k = (Comparable<? super K>) key;//参数使用类型的比较器
                do {
                    parent = t;//将父节点设为t (第一次t为根节点)
                    cmp = k.compareTo(t.key);//将根节点的key与参数中的key进行比较
                    if (cmp < 0)//key<t.key
                        t = t.left;
                    else if (cmp > 0)//key>t.key
                        t = t.right;
                    else
                        return t.setValue(value);;//key==t.key
                } while (t != null);
            }
            Entry<K,V> e = new Entry<K,V>(key, value, parent);//将传入的参数封装为集合元素
            if (cmp < 0)//e<parent
                parent.left = e;
            else
        //e>parent
                parent.right = e;
            fixAfterInsertion(e);
            size++;
            modCount++;
            return null;
    }

    下面用图形的方式来进行一个比较直观的显示

    第一次赋值:

    将该值作为根节点存放

    image

    第二次赋值:

    值小于根节点

    image

    值大于根节点

    image

    第三次赋值

    假设赋值为3其先和根节点“2”进行比较其大于“2”尝试将其赋值为根节点“2”的右子节点但发现其已有值,所以查找2的右子节点“4”与其进行比较发现其小于“4”所以赋值结果如图所示:

    image

    以此类推所以其最终的数据结构类似于下图所示的到树状结构

    image

    TreeSet和TreeMap获取值

    其获取值和赋值类似也是从根节点开始与其子节点逐一对比直至找到要查序的元素

    源码:

    image

    getEntry(key)方法源码:

    final Entry<K,V> getEntry(Object key) {
            
            if (comparator != null)
        //集合存在自定义比较器
                return getEntryUsingComparator(key);
            if (key == null)
                throw new NullPointerException();
        Comparable<? super K> k = (Comparable<? super K>) key;
            Entry<K,V> p = root;//获取根节点
            while (p != null) {//若根节点不为空则遍历节点
                int cmp = k.compareTo(p.key);
                if (cmp < 0)
                    p = p.left;
                else if (cmp > 0)
                    p = p.right;
                else
                    return p;如果k与该节点的key比较返回值=0(返回0代表其相等)则返回该节点
            }
            return null;
        }

    getEntryUsingComparator(key)源码:

    //使用自定义比较器进行比较遍历
    final Entry<K,V> getEntryUsingComparator(Object key) {
        K k = (K) key;
            Comparator<? super K> cpr = comparator;
            if (cpr != null) {
                Entry<K,V> p = root;
                while (p != null) {
                    int cmp = cpr.compare(k, p.key);
                    if (cmp < 0)
                        p = p.left;
                    else if (cmp > 0)
                        p = p.right;
                    else
                        return p;
                }
            }
            return null;
        }

    Treeset和TreeMap的排序

    其排序会按照其二叉树的层级关系从最左侧的叶级节点开始找其父节点在查找其父节点的右子节点若其父节点的右子节点下还有子节点则遍历该右节点直至找到该右节点下最左边的叶级节点当期父节点遍历完成之后则以同样的方法遍历其父节点的父节点以此类推直至该二叉树遍历完毕

    如图所示:

    image

  • 相关阅读:
    Linux:PS命令详解与使用
    linux日志守护进程 syslog
    Linux shell 判断字符串为空等常用命令
    Java 中zookeeper操作
    mysql数据库读写分离,主从同步实现方法
    【转】几种Java序列化方式的实现
    如何为SUSE配置IP地址,网关和DNS
    linux中export的作用
    91家纺网,多线程版本待处理
    91家纺网爬虫,不包含多线程登录处理,第三张表格数据没有对接
  • 原文地址:https://www.cnblogs.com/wangzheand/p/5684204.html
Copyright © 2011-2022 走看看