Map接口
Map集合的特点
- 能够存储唯一的列的数据(唯一,不可重复) Set
- 能够存储可以重复的数据(可重复) List
- 值的顺序取决于键的顺序
- 键和值都是可以存储null元素的
Set接口
一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2)
的元素对
e1
和 e2
,并且最多包含一个 null 元素
TreeMap
TreeMap底层的实现原理是红黑树,所以要搞清楚TreeMap的底层原理,前提条件就必须要搞清楚红黑树的原理
类图结构
定义TreeMap 无参构造
TreeMap map = new TreeMap();
源码
public TreeMap() {
comparator = null;
}
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
/**
* The comparator used to maintain order in this tree map, or
* null if it uses the natural ordering of its keys.
*
* @serial
*/
private final Comparator<? super K> comparator;// 比较器
private transient Entry<K,V> root;// 根节点
/**
* The number of entries in the tree
*/
private transient int size = 0;// map中元素的个数
/**
* The number of structural modifications to the tree.
*/
private transient int modCount = 0;// 记录修改的次数
进入Entry内部类
static final class Entry<K,V> implements Map.Entry<K,V> {
K key; // key
V value; // value
Entry<K,V> left; // 左子树
Entry<K,V> right; // 右子树
Entry<K,V> parent; // 父节点
boolean color = BLACK; // 颜色标志
/**
* Make a new cell with given key, value, and parent, and with
* {@code null} child links, and BLACK color.
*/
Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
}
/**
* Returns the key.
*
* @return the key
*/
public K getKey() {
return key;
}
/**
* Returns the value associated with the key.
*
* @return the value associated with the key
*/
public V getValue() {
return value;
}
/**
* Replaces the value currently associated with the key with the given
* value.
*
* @return the value associated with the key before this method was
* called
*/
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
// 重写了equals方法 必须是key和value都相等
return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
}
public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash; // 异或
}
public String toString() {
return key + "=" + value;
}
}
以put方法为例来介绍TreeMap中红黑树的操作
TreeMap map = new TreeMap();
map.put("wm","666");
map.put("wmm","777");
第一次添加
public V put(K key, V value) {
// 获取根节点 将root赋值给局部变量 初始为Null
Entry<K,V> t = root;
if (t == null) {
// 初始操作
// 检查key是否为null
compare(key, key); // type (and possibly null) check
// 将要添加的key、value封装为一个Entry对象 并赋值给root
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null; //返回null
}
第二次添加 root不为空
public V put(K key, V value) {
// 获取根节点 将root赋值给局部变量 初始为Null
Entry<K,V> t = root;
if (t == null) {
// 初始操作
// 检查key是否为null
compare(key, key); // type (and possibly null) check
// 对根节点初始化
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null; //返回null
}
int cmp;
Entry<K,V> parent;//父节点
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;//获取比较器
if (cpr != null) { // 如果比较器不为null
do { // 循环 将root赋值给parent
parent = t;
// 比较父节点和插入节点的值得大小
cmp = cpr.compare(key, t.key);
if (cmp < 0) // 插入节点比父节点小
t = t.left; // 把父节点左节点赋给t
else if (cmp > 0) // 插入的值比父节点大
t = t.right; // 把父节点右侧的节点赋给t
else // 如果相等,直接替换,并返回原来的值
return t.setValue(value);
} while (t != null);// 一直循环直到找到合适的插入位置
}
else {
if (key == null)
throw new NullPointerException();
// 比较器为空 就创建一个 通过ASCII码值进行比较
@SuppressWarnings("unchecked")
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);
}
// 将要添加的 key value 封装为一个Entry 对象
// t 就是我们要插入节点的父节点 parent
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e; // 添加到父节点的左侧
else
parent.right = e; // 添加到父节点的右侧
fixAfterInsertion(e); // 红黑树的平衡
size++;
modCount++;
return null;
}
红黑树平衡 fixAfterInsertion(e);
/** From CLR */
private void fixAfterInsertion(Entry<K,V> x) {
// 设置创建的初始节点为红色节点
x.color = RED;
// 循环的条件 添加的节点不为空 不是root节点 父节点是红色
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 因为祖父节点是红色,当前新插入的节点 下一次循环向上再检查
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 rotateLeft(Entry<K,V> p) {
if (p != null) {
Entry<K,V> r = p.right;
p.right = r.left;
if (r.left != null)
r.left.parent = p;
r.parent = p.parent;
if (p.parent == null)
root = r;
else if (p.parent.left == p)
p.parent.left = r;
else
p.parent.right = r;
r.left = p;
p.parent = r;
}
}
右旋源码
/** From CLR */
private void rotateRight(Entry<K,V> p) {
if (p != null) {
Entry<K,V> l = p.left;
p.left = l.right;
if (l.right != null) l.right.parent = p;
l.parent = p.parent;
if (p.parent == null)
root = l;
else if (p.parent.right == p)
p.parent.right = l;
else p.parent.left = l;
l.right = p;
p.parent = l;
}
}