`

TreeMap 源码分析

阅读更多
TreeMap是一种红黑树。红黑树的介绍可以查看http://wangyu.iteye.com/blog/190763
存储结构为;
  private transient Entry<K,V> root = null;

put方法:通过排序树查找的方法找到相应的位置,然后插入。再调用fixAfterInsertion()方法旋转,调整成红黑树。
    public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
	    // TBD:
	    // 5045147: (coll) Adding null to an empty TreeSet should
	    // throw NullPointerException
	    //
	    // compare(key, key); // type check
            root = new Entry<K,V>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<K,V>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

getCeilingEntry方法:如果key存在,返回entry。如果不存在,返回最小比key大的entry。
类似的方法有getFloorEntry,getHigherEntry,getLowerEntry
    final Entry<K,V> getCeilingEntry(K key) {
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = compare(key, p.key);
            if (cmp < 0) {
                if (p.left != null)
                    p = p.left;
                else
                    return p;
            } else if (cmp > 0) {
                if (p.right != null) {
                    p = p.right;
                } else {
                    Entry<K,V> parent = p.parent;
                    Entry<K,V> ch = p;
                    while (parent != null && ch == parent.right) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    return parent;
                }
            } else
                return p;
        }
        return null;
    }

treemap的遍历可以通过treemap.entrySet().iterator()来实现
//当调用entrySet()方法时会new一个EntrySet对象
 public Set<Map.Entry<K,V>> entrySet() {
        EntrySet es = entrySet;
        return (es != null) ? es : (entrySet = new EntrySet());
    }
//当调用iterator()方法时会new EntryIterator()对象,并通过方法getFirstEntry()获得tree中key最小的对象。
 class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return new EntryIterator(getFirstEntry());
        }
    }
//当执行iterator().next()的时候,会调用父类的nextEntry()方法
 final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> {
        EntryIterator(Entry<K,V> first) {
            super(first);
        }
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
    }
//当执行iterator().next()的时候,会调用父类的nextEntry()方法
abstract class PrivateEntryIterator<T> implements Iterator<T> {
final Entry<K,V> nextEntry() {
            Entry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            next = successor(e);
            lastReturned = e;
            return e;
        }
}
//通过successor方法找到最小比t大的值
    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
        if (t == null)
            return null;
        else if (t.right != null) {
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        } else {
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }


需要再研究的算法:红黑树的旋转算法
   /** From CLR */
    private void fixAfterInsertion(Entry<K,V> x) {
        x.color = RED;

        while (x != null && x != root && x.parent.color == RED) {
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == rightOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }

  /** From CLR */
    private void fixAfterDeletion(Entry<K,V> x) {
        while (x != root && colorOf(x) == BLACK) {
            if (x == leftOf(parentOf(x))) {
                Entry<K,V> sib = rightOf(parentOf(x));

                if (colorOf(sib) == RED) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    sib = rightOf(parentOf(x));
                }

                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(rightOf(sib)) == BLACK) {
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            } else { // symmetric
                Entry<K,V> sib = leftOf(parentOf(x));

                if (colorOf(sib) == RED) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateRight(parentOf(x));
                    sib = leftOf(parentOf(x));
                }

                if (colorOf(rightOf(sib)) == BLACK &&
                    colorOf(leftOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(leftOf(sib)) == BLACK) {
                        setColor(rightOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateLeft(sib);
                        sib = leftOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(leftOf(sib), BLACK);
                    rotateRight(parentOf(x));
                    x = root;
                }
            }
        }

        setColor(x, BLACK);
    }


TreeMap是非线程安全的。
TreeSet的结构和构造函数如下,其他代码都与TreeMap类似
private transient NavigableMap<E,Object> m;
  public TreeSet() {
	this(new TreeMap<E,Object>());
    }
  TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }


分享到:
评论

相关推荐

    TreeMap源码

    在分析TreeMap源码时,我们应关注以下几个关键类和方法: 1. `java.util.TreeMap` 类:它是TreeMap的实现类,包含节点(Node)的定义以及插入、删除、查找等核心操作的实现。 2. `java.util.TreeMap.Node` 类:表示...

    【死磕Java集合】-集合源码分析.pdf

    五、TreeMap源码分析 TreeMap是一种基于树形结构实现的Map,提供了快速的键值对存储和检索能力。TreeMap的继承体系中,它继承了AbstractMap,实现了Map接口。 TreeMap的主要属性包括键值对数组table、键值对个数...

    通过java.util.TreeMap源码加强红黑树的理解

    本文将通过分析Java.util.TreeMap源码,深入探索红黑树的奥秘,并加强对红黑树的理解。 红黑树的规则 红黑树有四个基本规则: 1. 每个节点不是红色的就是黑色的 2. 根总是黑色的 3. 如果节点是红色的,则它的子...

    Java源码解析TreeMap简介

    TreeMap的源码分析可以帮助我们更好地理解TreeMap的实现机制和排序机制。源码分析可以从TreeMap的构造方法、put和remove操作的实现机制开始,对红黑树的自平衡机制和排序机制进行深入分析。 TreeMap是Java中的一种...

    java集合类源码分析之Set详解.docx

    以下是对HashSet关键方法的源码分析: 1. 构造器: - `HashSet()`:创建一个空的HashSet,其内部的HashMap默认容量为16。 - `HashSet(Collection&lt;? extends E&gt; c)`:根据传入的集合c初始化HashSet,HashMap的容量...

    集合底层源码分析.doc

    《HashMap底层源码解析》 HashMap作为Java中最常用的集合类之一,它的实现原理与高效性能深受开发者喜爱。本文将深入探讨HashMap的概述、数据结构及其内部实现机制。 首先,HashMap是一个基于哈希表的Map接口的非...

    常见的java集合源码分析,以及面试题

    本文将深入剖析Java集合的源码,探讨其内部实现机制,并结合常见面试题,帮助你更好地理解和应用这些知识。 首先,我们从基础开始,Java集合框架主要分为两大类:List(列表)和Set(集合)。List接口包括ArrayList...

    java集合类源码分析之Set详解

    Java集合类源码分析之Set详解 Java集合类中的Set Interface是用于存储无序、不可重复元素的集合接口。Set Interface继承自Collection Interface,提供了基本的集合操作,如add、remove、contains等。Set Interface...

    ArrayList源码分析.docx 等

    比如,HashSet 和 TreeSet 分别基于哈希表和红黑树实现,HashMap 和 TreeMap 同样分别对应这两种数据结构。此外,面试官可能还会询问泛型、迭代器、以及集合的并发控制,如 CopyOnWriteArrayList 和 ...

    2021最新Java基础面试,0~1年小白专属,部分附源码分析.7z

    Java编程语言作为软件开发领域的重要组成部分,对于初学者而言,掌握其...同时,由于资源中提及部分附带源码分析,学习者可以通过实际代码来加深理解,遇到问题还能获得答疑支持,这对于新手来说是一份极其宝贵的资料。

    assemble:这是JDK中集合源码分析

    "assemble:这是JDK中集合源码分析" 提到的是对Java Development Kit (JDK) 中集合类的深入源码分析。集合框架主要包括List、Set、Map等接口,以及ArrayList、LinkedList、HashSet、HashMap等实现类。通过对这些源码...

    Java常用类源码

    通过源码分析,我们可以理解它们各自的性能特点和适用场景。 3. `HashMap` 和 `TreeMap` 类:这两个类实现了`Map`接口,用于存储键值对。`HashMap`提供快速的插入、删除和查找,依赖于哈希表;`TreeMap`则按照键的...

    Android-jdk源码阅读

    "Android-jdk源码阅读"这个主题聚焦于分析Java标准库中的`TreeMap`类,这是一个基于红黑树数据结构实现的有序映射。在这个主题中,我们将探讨`TreeMap`的内部工作原理,特别是它如何利用红黑树来实现高效的插入、...

    java8集合源码分析-Guide4j:Java学习指南

    "java8集合源码分析-Guide4j:Java学习指南"着重于深入理解Java 8集合框架的内部工作原理,这包括List、Set、Map等接口以及其实现类的源码分析。以下将详细探讨这个主题中的关键知识点: 1. **Java集合接口**:集合...

    28个java常用的类库源码

    源码分析有助于掌握数据传输和文件操作的底层机制。 3. **多线程**: Java提供了Thread类和Runnable接口来实现多线程。理解并发控制(如synchronized、volatile、ReentrantLock)和并发工具类(如ExecutorService...

    jdk1.8-source:JDK1.8源码分析包

    JDK1.8源码分析 相关的原始码分析结果会以注解的形式体现到原始码中 已完成部分: ReentrantLock CountDownLatch Semaphore HashMap TreeMap LinkedHashMap ConcurrentHashMap 执行器 ...

    java数据结构源码

    源码分析是理解这些数据结构工作原理的关键,这可以帮助开发者优化算法,提高代码性能。以下是对Java中几种主要数据结构源码的详细说明: 1. **顺序表**:顺序表是最基础的数据结构,它使用数组来存储元素。在Java...

    Collections源码java-JCF-CodeAnalysis:Javacollectionsframework源码分析

    总的来说,Java集合框架源码分析可以帮助我们掌握集合操作的底层原理,提高代码性能,增强对并发编程的理解,并且有助于我们设计出更高效、更安全的Java程序。通过对Collections类的深入学习,我们可以更好地利用...

    java类源码-JavaCollection:基于JDK1.8的集合类源码分析

    在源码分析中,我们需要关注以下关键点: 1. **接口与实现类的关系**:理解`Collection`接口如何通过不同的实现类(如`ArrayList`、`LinkedList`等)来满足不同场景的需求。 2. **数据结构**:了解数组、链表、哈希...

Global site tag (gtag.js) - Google Analytics