// 如果该节点存在,则替换值直接返回
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();
@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);
}
// 如果该节点未存在,则新建
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;
}
三、 get函数 {#3-_get函数}
get函数则相对来说比较简单,以log(n)的复杂度进行get。
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings(“unchecked”)
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;
}
return null;
}
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
四、successor后继 {#4-_successor后继}
TreeMap是如何保证其迭代输出是有序的呢?其实从宏观上来讲,就相当于树的中序遍历(LDR)。我们先看一下迭代输出的步骤
for(Entry<Integer, String> entry : tmap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
根据The enhanced for statement,for语句会做如下转换为:
for(Iterator<Map.Entry<String, String>> it = tmap.entrySet().iterator() ; tmap.hasNext(); ) {
Entry<Integer, String> entry = it.next();
System.out.println(entry.getKey() + ": " + entry.getValue());
}
在it.next()的调用中会使用nextEntry调用successor
这个是过的后继的重点,具体实现如下:
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 {
// 如果右子树为空,则寻找当前节点所在左子树的第一个祖先节点
// 因为左子树找完了,根据LDR该D了
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
// 保证左子树
技术学习总结
学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。
最后面试分享
大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!
了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!
[外链图片转存中…(img-y2n5a202-1714160958063)]
[外链图片转存中…(img-zAOILD5j-1714160958063)]