TreeSet与TreeMap浅解
TreeSet与TreeMap的关系:
1.TreeSet 实际上就是用TreeMap来组织数据的,因为在TreeSet中保存了一个NavigableMap<e,Object>接口实例变量,而该接口的实现类就是TreeMap
2.TreeSet与TreeMap都是用二叉树的数据结构来存储数据
3.TreeSet和TreeMap中保存的数据除了Integer和String等有默认顺序的类型外的自定义类型都需要实现Comparable接口并重写compareTo()方法。
TreeSet和TreeMap添加数据:
TreeSet的add方法会调用TreeMap的put方法
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; }
下面用图形的方式来进行一个比较直观的显示
第一次赋值:
将该值作为根节点存放
第二次赋值:
值小于根节点
值大于根节点
第三次赋值
假设赋值为3其先和根节点“2”进行比较其大于“2”尝试将其赋值为根节点“2”的右子节点但发现其已有值,所以查找2的右子节点“4”与其进行比较发现其小于“4”所以赋值结果如图所示:
以此类推所以其最终的数据结构类似于下图所示的到树状结构
TreeSet和TreeMap获取值
其获取值和赋值类似也是从根节点开始与其子节点逐一对比直至找到要查序的元素
源码:
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的排序
其排序会按照其二叉树的层级关系从最左侧的叶级节点开始找其父节点在查找其父节点的右子节点若其父节点的右子节点下还有子节点则遍历该右节点直至找到该右节点下最左边的叶级节点当期父节点遍历完成之后则以同样的方法遍历其父节点的父节点以此类推直至该二叉树遍历完毕
如图所示: