有序表的原理、应用、扩展
搜索二叉树
搜索二叉树一定要说明以什么标准来排序
经典的搜索二叉树,树上没有重复的用来排序的key值
如果有重复节点的需求,可以在一个节点内部增加数据项
搜索二叉树查询key(查询某个key存在还是不存在
1)如果当前节点的value==key,返回true
2)如果当前节点的value<key,当前节点向左移动
3)如果当前节点的value>key,当前节点向右移动
4)如果当前节点变成null,返回false
搜索二叉树插入新的key
和查询过程一样,但当前节点滑到空的时候,就插入在这里
搜索二叉树删除key
0)先找到key所在的节点
1)如果该节点没有左孩子、没有右孩子,直接删除即可
2)如果该节点有左孩子、没有右孩子,直接用左孩子顶替该节点
3)如果该节点没有左孩子、有右孩子,直接用右孩子顶替该节点
4)如果该节点有左孩子、有右孩子,用该节点后继节点顶替该节点
搜索二叉树特别不讲究
1)基础的搜索二叉树,添加、删除时候不照顾平衡性
2)数据状况很差时,性能就很差
给搜索二叉树引入两个动作:左旋、右旋
自平衡的机制——平衡搜索二叉树
AVL树、SB树、红黑树的共性
1)都是搜索二叉树
2)插入、删除、查询(一切查询)搜索二叉树怎么做,这些结构都这么做
3)使用调整的基本动作都只有左旋、右旋
4)插入、删除时,从最底层被影响到的节点开始,对往上路径的节点做平衡性检查
5)因为只对一条向上路径的每个节点做O(1)的检查和调整,所以可以做到O(logN)
AVL树、SB树、红黑树的不同
1)平衡性的约束不同
AVL树最严格、任何节点左树高度和右树高度差不超过1
SB树稍宽松、任何叔节点的节点数,不少于任何他的任何一个侄子节点
红黑树最宽松、长链的长度比短链的长度不超过两倍以上
2)插入、删除和搜索二叉树一样,但是额外,做各自的平衡性调整。各自的平衡性调整所使用的动作都是左旋或者右旋
AVL树
1)最严格的平衡性,任何节点左树高度和右树高度差不超过1
2)往上沿途检查每个节点时,都去检查四种违规情况:LL、RR、LR、RL
3)不同情况虽然看起来复杂,但是核心点是:
LL(做一次右旋)、RR(做一次左旋)
LR和RL(利用旋转让底层那个孙子上到顶部)
有序表的重要功能
//有序表
TreeMap<Integer,String> treeMap = new TreeMap<>();
// 在treeMap中,请你告诉我,离3最近,>=3的key是什么
treeMap.ceilingKey(3);
// 所有key中最小
treeMap.firstKey();
// 所有key中最大
treeMap.lastKey();
// 哈希表的增删改查 O(1)
// treeMap O(N)
SB树(size-balance-tree)
1)让每一个叔叔节点为头的数,节点个数都不少于其任何一个侄子节点
2)也是从底层被影响节点开始向上做路径每个节点检查
3)与AVL树非常像,也是四种违规类型:LL、RR、LR、RL
4)与AVL树非常像,核心点是:
LL(做一次右旋)、RR(做一次左旋)
LR和RL(利用旋转让底层那个上到顶部)
5)与AVL树不同的是,每轮经过调整后,谁的孩子发生变化了,谁就再查
SB树在使用时候的改进
1)删除时候可以不用检查
2)就把平衡性的调整放在插入的时候
3)因为这种只要变就递归的特性,别的树没有,虽然有递归但是收敛于O(1)
4)可以在节点上封装别的数据项,来增加功能
5) 平衡性要求低,所以各个操作所带来的扰动小
size balance tree 实现
public static class SBTNode<K extends Comparable<K>, V> {
public K key;
public V value;
public SBTNode<K, V> l;
public SBTNode<K, V> r;
public int size; // 不同的key的数量
public SBTNode(K key, V value) {
this.key = key;
this.value = value;
size = 1;
}
}
public static class SizeBalancedTreeMap<K extends Comparable<K>, V> {
private SBTNode<K, V> root;
private SBTNode<K, V> rightRotate(SBTNode<K, V> cur) {
SBTNode<K, V> leftNode = cur.l;
cur.l = leftNode.r;
leftNode.r = cur;
// 交换节点的size互换
leftNode.size = cur.size;
cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
return leftNode;
}
private SBTNode<K, V> leftRotate(SBTNode<K, V> cur) {
SBTNode<K, V> rightNode = cur.r;
cur.r = rightNode.l;
rightNode.l = cur;
rightNode.size = cur.size;
cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
return rightNode;
}
private SBTNode<K, V> maintain(SBTNode<K, V> cur) {
if (cur == null) {
return null;
}
if (cur.l != null && cur.l.l != null && cur.r != null && cur.l.l.size > cur.r.size) {
cur = rightRotate(cur);
cur.r = maintain(cur.r);
cur = maintain(cur);
} else if (cur.l != null && cur.l.r != null && cur.r != null && cur.l.r.size > cur.r.size) {
cur.l = leftRotate(cur.l);
cur = rightRotate(cur);
cur.l = maintain(cur.l);
cur.r = maintain(cur.r);
cur = maintain(cur);
} else if (cur.r != null && cur.r.r != null && cur.l != null && cur.r.r.size > cur.l.size) {
cur = leftRotate(cur);
cur.l = maintain(cur.l);
cur = maintain(cur);
} else if (cur.r != null && cur.r.l != null && cur.l != null && cur.r.l.size > cur.l.size) {
cur.r = rightRotate(cur.r);
cur = leftRotate(cur);
cur.l = maintain(cur.l);
cur.r = maintain(cur.r);
cur = maintain(cur);
}
return cur;
}
/**
* 如果没找到,返回离这个key最近不空的结点
* @param key
* @return
*/
private SBTNode<K, V> findLastIndex(K key) {
SBTNode<K, V> pre = root;
SBTNode<K, V> cur = root;
while (cur != null) {
pre = cur;
if (key.compareTo(cur.key) == 0) {
break;
} else if (key.compareTo(cur.key) < 0) {
cur = cur.l;
} else {
cur = cur.r;
}
}
return pre;
}
private SBTNode<K, V> findLastNoSmallIndex(K key) {
SBTNode<K, V> ans = null;
SBTNode<K, V> cur = root;
while (cur != null) {
if (key.compareTo(cur.key) == 0) {
ans = cur;
break;
} else if (key.compareTo(cur.key) < 0) {
ans = cur;
cur = cur.l;
} else {
cur = cur.r;
}
}
return ans;
}
private SBTNode<K, V> findLastNoBigIndex(K key) {
SBTNode<K, V> ans = null;
SBTNode<K, V> cur = root;
while (cur != null) {
if (key.compareTo(cur.key) == 0) {
ans = cur;
break;
} else if (key.compareTo(cur.key) < 0) {
cur = cur.l;
} else {
ans = cur;
cur = cur.r;
}
}
return ans;
}
// 现在,以cur为头的树上,加(key, value)这样的记录
// 加完之后,会对cur做检查,该调整调整
// 返回,调整完之后,整棵树的新头部
private SBTNode<K, V> add(SBTNode<K, V> cur, K key, V value) {
if (cur == null) {
return new SBTNode<K, V>(key, value);
} else {
cur.size++;
if (key.compareTo(cur.key) < 0) {
cur.l = add(cur.l, key, value);
} else {
cur.r = add(cur.r, key, value);
}
return maintain(cur);
}
}
// 在cur这棵树上,删掉key所代表的节点
// 返回cur这棵树的新头部
private SBTNode<K, V> delete(SBTNode<K, V> cur, K key) {
cur.size--;
if (key.compareTo(cur.key) > 0) {
cur.r = delete(cur.r, key);
} else if (key.compareTo(cur.key) < 0) {
cur.l = delete(cur.l, key);
} else { // 当前要删掉cur
if (cur.l == null && cur.r == null) {
// free cur memory -> C++
cur = null;
} else if (cur.l == null && cur.r != null) {
// free cur memory -> C++
cur = cur.r;
} else if (cur.l != null && cur.r == null) {
// free cur memory -> C++
cur = cur.l;
} else { // 有左有右
SBTNode<K, V> pre = null;
SBTNode<K, V> des = cur.r;
des.size--;
while (des.l != null) {
pre = des;
des = des.l;
des.size--;
}
if (pre != null) {
pre.l = des.r;
des.r = cur.r;
}
des.l = cur.l;
des.size = des.l.size + (des.r == null ? 0 : des.r.size) + 1;
// free cur memory -> C++
cur = des;
}
}
// cur = maintain(cur); 可以不加调整
return cur;
}
private SBTNode<K, V> getIndex(SBTNode<K, V> cur, int kth) {
if (kth == (cur.l != null ? cur.l.size : 0) + 1) {
return cur;
} else if (kth <= (cur.l != null ? cur.l.size : 0)) {
return getIndex(cur.l, kth);
} else {
return getIndex(cur.r, kth - (cur.l != null ? cur.l.size : 0) - 1);
}
}
public int size() {
return root == null ? 0 : root.size;
}
public boolean containsKey(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
SBTNode<K, V> lastNode = findLastIndex(key);
return lastNode != null && key.compareTo(lastNode.key) == 0 ? true : false;
}
public void put(K key, V value) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
SBTNode<K, V> lastNode = findLastIndex(key);
if (lastNode != null && key.compareTo(lastNode.key) == 0) {
lastNode.value = value;
} else {
root = add(root, key, value);
}
}
public void remove(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
if (containsKey(key)) {
root = delete(root, key);
}
}
public K getIndexKey(int index) {
if (index < 0 || index >= this.size()) {
throw new RuntimeException("invalid parameter.");
}
return getIndex(root, index + 1).key;
}
public V getIndexValue(int index) {
if (index < 0 || index >= this.size()) {
throw new RuntimeException("invalid parameter.");
}
return getIndex(root, index + 1).value;
}
public V get(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
SBTNode<K, V> lastNode = findLastIndex(key);
if (lastNode != null && key.compareTo(lastNode.key) == 0) {
return lastNode.value;
} else {
return null;
}
}
public K firstKey() {
if (root == null) {
return null;
}
SBTNode<K, V> cur = root;
while (cur.l != null) {
cur = cur.l;
}
return cur.key;
}
public K lastKey() {
if (root == null) {
return null;
}
SBTNode<K, V> cur = root;
while (cur.r != null) {
cur = cur.r;
}
return cur.key;
}
public K floorKey(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
SBTNode<K, V> lastNoBigNode = findLastNoBigIndex(key);
return lastNoBigNode == null ? null : lastNoBigNode.key;
}
public K ceilingKey(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
SBTNode<K, V> lastNoSmallNode = findLastNoSmallIndex(key);
return lastNoSmallNode == null ? null : lastNoSmallNode.key;
}
}
数组保存的方式:
public static class SizeBalancedTreeMap<K extends Comparable<K>, V> {
private int root;
private int len;
private int[] left;
private int[] right;
private int[] size;
private ArrayList<K> keys;
private ArrayList<V> values;
public SizeBalancedTreeMap(int init) {
left = new int[init + 1];
right = new int[init + 1];
size = new int[init + 1];
keys = new ArrayList<K>();
values = new ArrayList<V>();
keys.add(null);
values.add(null);
root = 0;
len = 0;
}
private int rightRotate(int index) {
int iLeft = left[index];
left[index] = right[iLeft];
right[iLeft] = index;
size[iLeft] = size[index];
size[index] = size[left[index]] + size[right[index]] + 1;
return iLeft;
}
private int leftRotate(int index) {
int iRight = right[index];
right[index] = left[iRight];
left[iRight] = index;
size[iRight] = size[index];
size[index] = size[left[index]] + size[right[index]] + 1;
return iRight;
}
private int matain(int index) {
if (size[left[left[index]]] > size[right[index]]) {
index = rightRotate(index);
right[index] = matain(right[index]);
index = matain(index);
} else if (size[right[left[index]]] > size[right[index]]) {
left[index] = leftRotate(left[index]);
index = rightRotate(index);
left[index] = matain(left[index]);
right[index] = matain(right[index]);
index = matain(index);
} else if (size[right[right[index]]] > size[left[index]]) {
index = leftRotate(index);
left[index] = matain(left[index]);
index = matain(index);
} else if (size[left[right[index]]] > size[left[index]]) {
right[index] = rightRotate(right[index]);
index = leftRotate(index);
left[index] = matain(left[index]);
right[index] = matain(right[index]);
index = matain(index);
}
return index;
}
private int findLastIndex(K key) {
int pre = root;
int cur = root;
while (cur != 0) {
pre = cur;
if (key.compareTo(keys.get(cur)) == 0) {
break;
} else if (key.compareTo(keys.get(cur)) < 0) {
cur = left[cur];
} else {
cur = right[cur];
}
}
return pre;
}
private int findLastNoSmallIndex(K key) {
int ans = 0;
int cur = root;
while (cur != 0) {
if (key.compareTo(keys.get(cur)) == 0) {
ans = cur;
break;
} else if (key.compareTo(keys.get(cur)) < 0) {
ans = cur;
cur = left[cur];
} else {
cur = right[cur];
}
}
return ans;
}
private int findLastNoBigIndex(K key) {
int ans = 0;
int cur = root;
while (cur != 0) {
if (key.compareTo(keys.get(cur)) == 0) {
ans = cur;
break;
} else if (key.compareTo(keys.get(cur)) < 0) {
cur = left[cur];
} else {
ans = cur;
cur = right[cur];
}
}
return ans;
}
private int add(int index, K key, V value) {
if (index == 0) {
index = ++len;
keys.add(key);
values.add(value);
size[index] = 1;
left[index] = 0;
right[index] = 0;
return index;
} else {
size[index]++;
if (key.compareTo(keys.get(index)) < 0) {
left[index] = add(left[index], key, value);
} else {
right[index] = add(right[index], key, value);
}
return matain(index);
}
}
private int getIndex(int index, int kth) {
if (kth == size[left[index]] + 1) {
return index;
} else if (kth <= size[left[index]]) {
return getIndex(left[index], kth);
} else {
return getIndex(right[index], kth - size[left[index]] - 1);
}
}
public int size() {
return len;
}
public boolean containsKey(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
int lastIndex = findLastIndex(key);
return lastIndex != 0 && key.compareTo(keys.get(lastIndex)) == 0 ? true : false;
}
public void put(K key, V value) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
if (len == size.length - 1) {
throw new RuntimeException("size balanced tree is full.");
}
int lastIndex = findLastIndex(key);
if (lastIndex != 0 && key.compareTo(keys.get(lastIndex)) == 0) {
values.set(lastIndex, value);
} else {
root = add(root, key, value);
}
}
public K getIndexKey(int index) {
if (index < 0 || index >= len) {
throw new RuntimeException("invalid parameter.");
}
return keys.get(getIndex(root, index + 1));
}
public V getIndexValue(int index) {
if (index < 0 || index >= len) {
throw new RuntimeException("invalid parameter.");
}
return values.get(getIndex(root, index + 1));
}
public V get(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
int lastIndex = findLastIndex(key);
if (lastIndex != 0 && key.compareTo(keys.get(lastIndex)) == 0) {
return values.get(lastIndex);
} else {
return null;
}
}
public K firstKey() {
int cur = root;
while (left[cur] != 0) {
cur = left[cur];
}
return cur == 0 ? null : keys.get(cur);
}
public K lastKey() {
int cur = root;
while (right[cur] != 0) {
cur = right[cur];
}
return cur == 0 ? null : keys.get(cur);
}
public K floorKey(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
int lastNoBigIndex = findLastNoBigIndex(key);
return lastNoBigIndex == 0 ? null : keys.get(lastNoBigIndex);
}
public K ceilingKey(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
int lastNoSmallIndex = findLastNoSmallIndex(key);
return lastNoSmallIndex == 0 ? null : keys.get(lastNoSmallIndex);
}
}
跳表(skiplist)
1)结构上根本和搜索二叉树无关
2)利用随机概率分布来使得高层索引可以无视数据规律,做到整体性能优良
3)思想是所有有序表中最先进的
4)结构简单就是多级单链表
// 跳表的节点定义
public static class SkipListNode<K extends Comparable<K>, V> {
public K key;
public V val;
// 0 nextNodes.get(0)
// 1 nextNodes.get(1)
// i nextNodes.get(i)
// nextNodes.size()
public ArrayList<SkipListNode<K, V>> nextNodes;
public SkipListNode(K k, V v) {
key = k;
val = v;
// node 7层指针
// nextNodes.add(null)
// nextNodes.add(null)
// nextNodes.add(null)
// nextNodes.add(null)
// nextNodes.add(null)
// nextNodes.add(null)
// nextNodes.add(null)
nextNodes = new ArrayList<SkipListNode<K, V>>();
}
// 遍历的时候,如果是往右遍历到的null(next == null), 遍历结束
// 头(null), 头节点的null,认为最小
// node -> 头,node(null, "") node.isKeyLess(!null) true
// node里面的key是否比otherKey小,true,不是false
public boolean isKeyLess(K otherKey) {
// otherKey == null -> false
return otherKey != null && (key == null || key.compareTo(otherKey) < 0);
}
public boolean isKeyEqual(K otherKey) {
return (key == null && otherKey == null)
|| (key != null && otherKey != null && key.compareTo(otherKey) == 0);
}
}
public static class SkipListMap<K extends Comparable<K>, V> {
private static final double PROBABILITY = 0.5; // < 0.5 继续做,>=0.5 停
private SkipListNode<K, V> head;
private int size;
private int maxLevel;
public SkipListMap() {
head = new SkipListNode<K, V>(null, null);
head.nextNodes.add(null); // 0 层
size = 0;
maxLevel = 0;
}
// 从最高层开始,一路找下去,
// 最终,找到第0层的<key的最右的节点
private SkipListNode<K, V> mostRightLessNodeInTree(K key) {
if (key == null) {
return null;
}
int level = maxLevel;
SkipListNode<K, V> cur = head;
while (level >= 0) { // 从上层跳下层
// cur level -> level-1
cur = mostRightLessNodeInLevel(key, cur, level--);
}
return cur;
}
// 在level层里,如何往右移动
// 现在来到的节点是cur,来到了cur的level层,在level层上,找到<key最后一个节点并返回
private SkipListNode<K, V> mostRightLessNodeInLevel(K key,
SkipListNode<K, V> cur,
int level) {
SkipListNode<K, V> next = cur.nextNodes.get(level);
while (next != null && next.isKeyLess(key)) {
cur = next;
next = cur.nextNodes.get(level);
}
return cur;
}
public boolean containsKey(K key) {
if (key == null) {
return false;
}
SkipListNode<K, V> less = mostRightLessNodeInTree(key);
SkipListNode<K, V> next = less.nextNodes.get(0);
return next != null && next.isKeyEqual(key);
}
public void put(K key, V value) {
if (key == null) {
return;
}
// 0层上,最右一个,小于key的Node,再往下一个要么等于key,要么大于key
SkipListNode<K, V> less = mostRightLessNodeInTree(key);
SkipListNode<K, V> find = less.nextNodes.get(0);
if (find != null && find.isKeyEqual(key)) {
find.val = value;
} else {
size++;
int newNodeLevel = 0;
while (Math.random() < PROBABILITY) {
newNodeLevel++;
}
// 如果层数比最左节点大,最左就要补成一样
while (newNodeLevel > maxLevel) {
head.nextNodes.add(null);
maxLevel++;
}
SkipListNode<K, V> newNode = new SkipListNode<K, V>(key, value);
for (int i = 0; i <= newNodeLevel; i++) {
newNode.nextNodes.add(null);
}
int level = maxLevel;
SkipListNode<K, V> pre = head;
while (level >= 0) {
// 在level层中,找到最右的小于key的节点
pre = mostRightLessNodeInLevel(key, pre, level);
if (level <= newNodeLevel) {
newNode.nextNodes.set(level, pre.nextNodes.get(level));
pre.nextNodes.set(level, newNode);
}
level--;
}
}
}
public V get(K key) {
if (key == null) {
return null;
}
SkipListNode<K, V> less = mostRightLessNodeInTree(key);
SkipListNode<K, V> next = less.nextNodes.get(0);
return next != null && next.isKeyEqual(key) ? next.val : null;
}
public void remove(K key) {
if (containsKey(key)) {
size--;
int level = maxLevel;
SkipListNode<K, V> pre = head;
while (level >= 0) {
pre = mostRightLessNodeInLevel(key, pre, level);
SkipListNode<K, V> next = pre.nextNodes.get(level);
// 1)在这一层中,pre下一个就是key
// 2)在这一层中,pre的下一个key是>要删除key
if (next != null && next.isKeyEqual(key)) {
// free delete node memory -> C++
// level : pre -> next(key) -> ...
pre.nextNodes.set(level, next.nextNodes.get(level));
}
// 在level层只有一个节点了,就是默认节点head
if (level != 0 && pre == head && pre.nextNodes.get(level) == null) {
head.nextNodes.remove(level);
maxLevel--;
}
level--;
}
}
}
public K firstKey() {
return head.nextNodes.get(0) != null ? head.nextNodes.get(0).key : null;
}
public K lastKey() {
int level = maxLevel;
SkipListNode<K, V> cur = head;
while (level >= 0) {
SkipListNode<K, V> next = cur.nextNodes.get(level);
while (next != null) {
cur = next;
next = cur.nextNodes.get(level);
}
level--;
}
return cur.key;
}
public K ceillingKey(K key) {
if (key == null) {
return null;
}
SkipListNode<K, V> less = mostRightLessNodeInTree(key);
SkipListNode<K, V> next = less.nextNodes.get(0);
return next != null ? next.key : null;
}
public K floorKey(K key) {
if (key == null) {
return null;
}
SkipListNode<K, V> less = mostRightLessNodeInTree(key);
SkipListNode<K, V> next = less.nextNodes.get(0);
return next != null && next.isKeyEqual(key) ? next.key : less.key;
}
public int size() {
return size;
}
}
聊聊红黑树
1)平衡性规定非常诡异
2)平衡性调整最为复杂
3)优点在于每次插入删除扰动较好,但是在今天看来这个优势也极其微弱了
原因:贪图扰动小的话,B+树、2-3-4树可能更好(可以少读写硬盘),还是那句话,到底图什么
4)除此之外,红黑树并不比AVL树、SB树、跳表更加优秀,关键在于红黑树在扰动上达到了一种中间状态
5)面试上遇到,说清楚道理,不行就举报
红黑树的性质(本质上还是一种平衡二叉树)
1、节点非红即黑
2、整颗树的头和叶一定是黑
3、红的子不能是红
4、从叶节点出发到头,任何一条链,黑的一样多,这样最长的链不会超过最短的链的两倍
插入违规有5种情况,删除违规有8种情况
redis为什么用跳表不去使用AVL,SB,因为跳表序列化更方便
例1:给定一些长度不一的数组,每个数组都有序,整体是一个二维数组,想要找到一个最短区间[a,b],每个数组中至少有一个数字在这个区间里。
准备一个有序表,将每个数组中最小的数放进去,那么就能取到一个区间[x,y],弹出最小的,从包含最小数的数组中取下一个放入有序表,又得到[z,y],比较有没有比[x,y]好
每次都弹出最小,再加入最小所在数组中的下一个,放入,比较区间,最短的就是[a,b]
实际每次求的是以x开头,让每个数字在区间里的最短的区间是什么(做了一步贪心,只是列举在数组里的数字就行,不需要穷举每一个整数)
例2:给定一个数组arr,和两个整数a和b(a<=b),求arr中有多少个子数组,累加和在[a,b]这个范围上,返回达标的子数组数量。
public static class SBTNode {
public long key;
public SBTNode l;
public SBTNode r;
public long size; // 不同key的size
public long all; // 总的size
public SBTNode(long k) {
key = k;
size = 1;
all = 1;
}
}
public static class SizeBalancedTreeSet {
private SBTNode root;
private HashSet<Long> set = new HashSet<>();
private SBTNode rightRotate(SBTNode cur) {
long same = cur.all - (cur.l != null ? cur.l.all : 0) - (cur.r != null ? cur.r.all : 0);
SBTNode leftNode = cur.l;
cur.l = leftNode.r;
leftNode.r = cur;
leftNode.size = cur.size;
cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
// all modify
leftNode.all = cur.all;
cur.all = (cur.l != null ? cur.l.all : 0) + (cur.r != null ? cur.r.all : 0) + same;
return leftNode;
}
private SBTNode leftRotate(SBTNode cur) {
long same = cur.all - (cur.l != null ? cur.l.all : 0) - (cur.r != null ? cur.r.all : 0);
SBTNode rightNode = cur.r;
cur.r = rightNode.l;
rightNode.l = cur;
rightNode.size = cur.size;
cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
// all modify
rightNode.all = cur.all;
cur.all = (cur.l != null ? cur.l.all : 0) + (cur.r != null ? cur.r.all : 0) + same;
return rightNode;
}
private SBTNode matain(SBTNode cur) {
if (cur == null) {
return null;
}
if (cur.l != null && cur.l.l != null && cur.r != null && cur.l.l.size > cur.r.size) {
cur = rightRotate(cur);
cur.r = matain(cur.r);
cur = matain(cur);
} else if (cur.l != null && cur.l.r != null && cur.r != null && cur.l.r.size > cur.r.size) {
cur.l = leftRotate(cur.l);
cur = rightRotate(cur);
cur.l = matain(cur.l);
cur.r = matain(cur.r);
cur = matain(cur);
} else if (cur.r != null && cur.r.r != null && cur.l != null && cur.r.r.size > cur.l.size) {
cur = leftRotate(cur);
cur.l = matain(cur.l);
cur = matain(cur);
} else if (cur.r != null && cur.r.l != null && cur.l != null && cur.r.l.size > cur.l.size) {
cur.r = rightRotate(cur.r);
cur = leftRotate(cur);
cur.l = matain(cur.l);
cur.r = matain(cur.r);
cur = matain(cur);
}
return cur;
}
private SBTNode add(SBTNode cur, long key, boolean contains) {
if (cur == null) {
return new SBTNode(key);
} else {
cur.all++;
if (key == cur.key) {
return cur;
} else { // 还在左滑或者右滑
if (!contains) {
cur.size++;
}
if (key < cur.key) {
cur.l = add(cur.l, key, contains);
} else {
cur.r = add(cur.r, key, contains);
}
return matain(cur);
}
}
}
public void add(long sum) {
boolean contains = set.contains(sum);
root = add(root, sum, contains);
set.add(sum);
}
public long lessKeySize(long key) {
SBTNode cur = root;
long ans = 0;
while (cur != null) {
if (key == cur.key) {
return ans + (cur.l != null ? cur.l.all : 0);
} else if (key < cur.key) { // 左滑
cur = cur.l;
} else { // 右滑
ans += cur.all - (cur.r != null ? cur.r.all : 0);
cur = cur.r;
}
}
return ans;
}
// > 7 8...
// <8 ...<=7
public long moreKeySize(long key) {
return root != null ? (root.all - lessKeySize(key + 1)) : 0;
}
}
public static int countRangeSum2(int[] nums, int lower, int upper) {
SizeBalancedTreeSet treeSet = new SizeBalancedTreeSet();
long sum = 0;
int ans = 0;
treeSet.add(0); // 一个数都没有的时候,就已经有一个前缀累加和为0
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
// sum i 结尾的时候[lower,upper]
// 之前所有前缀累加和中,有多少累加和落在[sum - upper, sum - lower]
// 查 ? < sum - lower + 1 a
// 查? < sum - upper b
long a = treeSet.lessKeySize(sum - lower + 1);
// sum = x [a,b] start < x-b -start > -x+b x-start > b
long b = treeSet.lessKeySize(sum - upper);
ans += a - b;
treeSet.add(sum);
}
return ans;
}
例3:
有一个滑动窗口(讲过的):
1)L是滑动窗口最左位置、R是滑动窗口最右位置,一开始LR都在数组左侧
2)任何一步都可能R往右动,表示某个数进了窗口
3)任何一步都可能L往右动,表示某个数出了窗口
想知道每一个窗口状态的中位数,偶数个的时候上中位与下中位除2,
public static class SBTNode<K extends Comparable<K>> {
public K key;
public SBTNode<K> l;
public SBTNode<K> r;
public int size;
public SBTNode(K k) {
key = k;
size = 1;
}
}
public static class SizeBalancedTreeMap<K extends Comparable<K>> {
private SBTNode<K> root;
private SBTNode<K> rightRotate(SBTNode<K> cur) {
SBTNode<K> leftNode = cur.l;
cur.l = leftNode.r;
leftNode.r = cur;
leftNode.size = cur.size;
cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
return leftNode;
}
private SBTNode<K> leftRotate(SBTNode<K> cur) {
SBTNode<K> rightNode = cur.r;
cur.r = rightNode.l;
rightNode.l = cur;
rightNode.size = cur.size;
cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
return rightNode;
}
private SBTNode<K> matain(SBTNode<K> cur) {
if (cur == null) {
return null;
}
if (cur.l != null && cur.l.l != null && cur.r != null && cur.l.l.size > cur.r.size) {
cur = rightRotate(cur);
cur.r = matain(cur.r);
cur = matain(cur);
} else if (cur.l != null && cur.l.r != null && cur.r != null && cur.l.r.size > cur.r.size) {
cur.l = leftRotate(cur.l);
cur = rightRotate(cur);
cur.l = matain(cur.l);
cur.r = matain(cur.r);
cur = matain(cur);
} else if (cur.r != null && cur.r.r != null && cur.l != null && cur.r.r.size > cur.l.size) {
cur = leftRotate(cur);
cur.l = matain(cur.l);
cur = matain(cur);
} else if (cur.r != null && cur.r.l != null && cur.l != null && cur.r.l.size > cur.l.size) {
cur.r = rightRotate(cur.r);
cur = leftRotate(cur);
cur.l = matain(cur.l);
cur.r = matain(cur.r);
cur = matain(cur);
}
return cur;
}
private SBTNode<K> findLastIndex(K key) {
SBTNode<K> pre = root;
SBTNode<K> cur = root;
while (cur != null) {
pre = cur;
if (key.compareTo(cur.key) == 0) {
break;
} else if (key.compareTo(cur.key) < 0) {
cur = cur.l;
} else {
cur = cur.r;
}
}
return pre;
}
private SBTNode<K> add(SBTNode<K> cur, K key) {
if (cur == null) {
return new SBTNode<K>(key);
} else {
cur.size++;
if (key.compareTo(cur.key) < 0) {
cur.l = add(cur.l, key);
} else {
cur.r = add(cur.r, key);
}
return matain(cur);
}
}
private SBTNode<K> delete(SBTNode<K> cur, K key) {
cur.size--;
if (key.compareTo(cur.key) > 0) {
cur.r = delete(cur.r, key);
} else if (key.compareTo(cur.key) < 0) {
cur.l = delete(cur.l, key);
} else {
if (cur.l == null && cur.r == null) {
// free cur memory -> C++
cur = null;
} else if (cur.l == null && cur.r != null) {
// free cur memory -> C++
cur = cur.r;
} else if (cur.l != null && cur.r == null) {
// free cur memory -> C++
cur = cur.l;
} else {
SBTNode<K> pre = null;
SBTNode<K> des = cur.r;
des.size--;
while (des.l != null) {
pre = des;
des = des.l;
des.size--;
}
if (pre != null) {
pre.l = des.r;
des.r = cur.r;
}
des.l = cur.l;
des.size = des.l.size + (des.r == null ? 0 : des.r.size) + 1;
// free cur memory -> C++
cur = des;
}
}
return cur;
}
private SBTNode<K> getIndex(SBTNode<K> cur, int kth) {
if (kth == (cur.l != null ? cur.l.size : 0) + 1) {
return cur;
} else if (kth <= (cur.l != null ? cur.l.size : 0)) {
return getIndex(cur.l, kth);
} else {
return getIndex(cur.r, kth - (cur.l != null ? cur.l.size : 0) - 1);
}
}
public int size() {
return root == null ? 0 : root.size;
}
public boolean containsKey(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
SBTNode<K> lastNode = findLastIndex(key);
return lastNode != null && key.compareTo(lastNode.key) == 0 ? true : false;
}
public void add(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
SBTNode<K> lastNode = findLastIndex(key);
if (lastNode == null || key.compareTo(lastNode.key) != 0) {
root = add(root, key);
}
}
public void remove(K key) {
if (key == null) {
throw new RuntimeException("invalid parameter.");
}
if (containsKey(key)) {
root = delete(root, key);
}
}
public K getIndexKey(int index) {
if (index < 0 || index >= this.size()) {
throw new RuntimeException("invalid parameter.");
}
return getIndex(root, index + 1).key;
}
}
public static class Node implements Comparable<Node> {
public int index;
public int value;
public Node(int i, int v) {
index = i;
value = v;
}
@Override
public int compareTo(Node o) {
return value != o.value ? Integer.valueOf(value).compareTo(o.value)
: Integer.valueOf(index).compareTo(o.index);
}
}
public static double[] medianSlidingWindow(int[] nums, int k) {
SizeBalancedTreeMap<Node> map = new SizeBalancedTreeMap<>();
for (int i = 0; i < k - 1; i++) {
map.add(new Node(i, nums[i]));
}
double[] ans = new double[nums.length - k + 1];
int index = 0;
for (int i = k - 1; i < nums.length; i++) {
map.add(new Node(i, nums[i]));
if (map.size() % 2 == 0) {
Node upmid = map.getIndexKey(map.size() / 2 - 1);
Node downmid = map.getIndexKey(map.size() / 2);
ans[index++] = ((double) upmid.value + (double) downmid.value) / 2;
} else {
Node mid = map.getIndexKey(map.size() / 2);
ans[index++] = (double) mid.value;
}
map.remove(new Node(i - k + 1, nums[i - k + 1]));
}
return ans;
}