From 946360f90f46f0dc1038177950fd6964358e3880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B7=A6=E7=A8=8B=E4=BA=91?= Date: Mon, 1 Mar 2021 15:44:49 +0800 Subject: [PATCH] add class --- src/class30/Code01_MorrisTraversal.java | 55 +-- src/class30/Code05_MinHeight.java | 1 + src/class31/Code01_SegmentTree.java | 36 +- src/class31/Code02_FallingSquares.java | 11 +- src/class33/Hash.java | 48 +++ src/class34/说明.txt | 2 + src/class35/Code01_AVLTreeMap.java | 257 +++++++++++ src/class36/Code01_SizeBalancedTreeMap.java | 360 ++++++++++++++++ src/class36/Code02_SkipListMap.java | 248 +++++++++++ src/class37/Code01_CountofRangeSum.java | 224 ++++++++++ src/class37/Code02_SlidingWindowMedian.java | 228 ++++++++++ .../Code03_AddRemoveGetIndexGreat.java | 259 +++++++++++ src/class37/Compare.java | 408 ++++++++++++++++++ 13 files changed, 2083 insertions(+), 54 deletions(-) create mode 100644 src/class33/Hash.java create mode 100644 src/class34/说明.txt create mode 100644 src/class35/Code01_AVLTreeMap.java create mode 100644 src/class36/Code01_SizeBalancedTreeMap.java create mode 100644 src/class36/Code02_SkipListMap.java create mode 100644 src/class37/Code01_CountofRangeSum.java create mode 100644 src/class37/Code02_SlidingWindowMedian.java create mode 100644 src/class37/Code03_AddRemoveGetIndexGreat.java create mode 100644 src/class37/Compare.java diff --git a/src/class30/Code01_MorrisTraversal.java b/src/class30/Code01_MorrisTraversal.java index 7206332..2e3a4a4 100644 --- a/src/class30/Code01_MorrisTraversal.java +++ b/src/class30/Code01_MorrisTraversal.java @@ -12,6 +12,17 @@ public class Code01_MorrisTraversal { } } + public static void process(Node root) { + if (root == null) { + return; + } + // 1 + process(root.left); + // 2 + process(root.right); + // 3 + } + public static void morris(Node head) { if (head == null) { return; @@ -19,20 +30,16 @@ public class Code01_MorrisTraversal { Node cur = head; Node mostRight = null; while (cur != null) { - // cur有没有左树 mostRight = cur.left; - if (mostRight != null) { // 有左树的情况下 - // 找到cur左树上,真实的最右 + if (mostRight != null) { while (mostRight.right != null && mostRight.right != cur) { mostRight = mostRight.right; } - // 从while中出来,mostRight一定是cur左树上的最右节点 - // mostRight if (mostRight.right == null) { mostRight.right = cur; cur = cur.left; continue; - } else { // mostRight.right != null -> mostRight.right == cur + } else { mostRight.right = null; } } @@ -40,7 +47,7 @@ public class Code01_MorrisTraversal { } } - public static void morrisIn(Node head) { + public static void morrisPre(Node head) { if (head == null) { return; } @@ -53,43 +60,43 @@ public class Code01_MorrisTraversal { mostRight = mostRight.right; } if (mostRight.right == null) { + System.out.print(cur.value + " "); mostRight.right = cur; cur = cur.left; continue; } else { mostRight.right = null; } + } else { + System.out.print(cur.value + " "); } - System.out.print(cur.value + " "); cur = cur.right; } System.out.println(); } - public static void morrisPre(Node head) { + public static void morrisIn(Node head) { if (head == null) { return; } - Node cur1 = head; - Node cur2 = null; - while (cur1 != null) { - cur2 = cur1.left; - if (cur2 != null) { - while (cur2.right != null && cur2.right != cur1) { - cur2 = cur2.right; + Node cur = head; + Node mostRight = null; + while (cur != null) { + mostRight = cur.left; + if (mostRight != null) { + while (mostRight.right != null && mostRight.right != cur) { + mostRight = mostRight.right; } - if (cur2.right == null) { - cur2.right = cur1; - System.out.print(cur1.value + " "); - cur1 = cur1.left; + if (mostRight.right == null) { + mostRight.right = cur; + cur = cur.left; continue; } else { - cur2.right = null; + mostRight.right = null; } - } else { - System.out.print(cur1.value + " "); } - cur1 = cur1.right; + System.out.print(cur.value + " "); + cur = cur.right; } System.out.println(); } diff --git a/src/class30/Code05_MinHeight.java b/src/class30/Code05_MinHeight.java index c328760..9814825 100644 --- a/src/class30/Code05_MinHeight.java +++ b/src/class30/Code05_MinHeight.java @@ -19,6 +19,7 @@ public class Code05_MinHeight { return p(head); } + // 返回x为头的树,最小深度是多少 public static int p(Node x) { if (x.left == null && x.right == null) { return 1; diff --git a/src/class31/Code01_SegmentTree.java b/src/class31/Code01_SegmentTree.java index 80e1b26..282c20a 100644 --- a/src/class31/Code01_SegmentTree.java +++ b/src/class31/Code01_SegmentTree.java @@ -5,7 +5,7 @@ public class Code01_SegmentTree { public static class SegmentTree { // arr[]为原序列的信息从0开始,但在arr里是从1开始的 // sum[]模拟线段树维护区间和 - // lazy[]为累加懒惰标记 + // lazy[]为累加和懒惰标记 // change[]为更新的值 // update[]为更新慵懒标记 private int MAXN; @@ -17,12 +17,11 @@ public class Code01_SegmentTree { public SegmentTree(int[] origin) { MAXN = origin.length + 1; - arr = new int[MAXN]; // arr[0] 不用 从1开始使用 + arr = new int[MAXN]; // arr[0] 不用 从1开始使用 for (int i = 1; i < MAXN; i++) { arr[i] = origin[i - 1]; } sum = new int[MAXN << 2]; // 用来支持脑补概念中,某一个范围的累加和信息 - lazy = new int[MAXN << 2]; // 用来支持脑补概念中,某一个范围沒有往下傳遞的纍加任務 change = new int[MAXN << 2]; // 用来支持脑补概念中,某一个范围有没有更新操作的任务 update = new boolean[MAXN << 2]; // 用来支持脑补概念中,某一个范围更新任务,更新成了什么 @@ -58,7 +57,7 @@ public class Code01_SegmentTree { // 在初始化阶段,先把sum数组,填好 // 在arr[l~r]范围上,去build,1~N, - // rt : 这个范围在sum中的下标 + // rt : 这个范围在sum中的下标 public void build(int l, int r, int rt) { if (l == r) { sum[rt] = arr[l]; @@ -70,6 +69,9 @@ public class Code01_SegmentTree { pushUp(rt); } + + // L~R 所有的值变成C + // l~r rt public void update(int L, int R, int C, int l, int r, int rt) { if (L <= l && r <= R) { update[rt] = true; @@ -90,38 +92,30 @@ public class Code01_SegmentTree { pushUp(rt); } - // L..R -> 任务范围 ,所有的值累加上C - // l,r -> 表达的范围 - // rt 去哪找l,r范围上的信息 - public void add( - int L, int R, int C, - int l, int r, - int rt) { - // 任务的范围彻底覆盖了,当前表达的范围 + // L~R, C 任务! + // rt,l~r + public void add(int L, int R, int C, int l, int r, int rt) { + // 任务如果把此时的范围全包了! if (L <= l && r <= R) { sum[rt] += C * (r - l + 1); lazy[rt] += C; return; } - // 任务并没有把l...r全包住 - // 要把当前任务往下发 - // 任务 L, R 没有把本身表达范围 l,r 彻底包住 - int mid = (l + r) >> 1; // l..mid (rt << 1) mid+1...r(rt << 1 | 1) - // 下发之前所有攒的懒任务 + // 任务没有把你全包! + // l r mid = (l+r)/2 + int mid = (l + r) >> 1; pushDown(rt, mid - l + 1, r - mid); - // 左孩子是否需要接到任务 + // L~R if (L <= mid) { add(L, R, C, l, mid, rt << 1); } - // 右孩子是否需要接到任务 if (R > mid) { add(L, R, C, mid + 1, r, rt << 1 | 1); } - // 左右孩子做完任务后,我更新我的sum信息 pushUp(rt); } - // 1~6 累加和是多少? 1~8 rt + // 1~6 累加和是多少? 1~8 rt public long query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return sum[rt]; diff --git a/src/class31/Code02_FallingSquares.java b/src/class31/Code02_FallingSquares.java index fb85a67..2f3b2a2 100644 --- a/src/class31/Code02_FallingSquares.java +++ b/src/class31/Code02_FallingSquares.java @@ -15,7 +15,7 @@ public class Code02_FallingSquares { public SegmentTree(int size) { int N = size + 1; max = new int[N << 2]; - + change = new int[N << 2]; update = new boolean[N << 2]; } @@ -74,11 +74,6 @@ public class Code02_FallingSquares { } - // positions - // [2,7] -> 2 , 8 - // [3, 10] -> 3, 12 - // - // public HashMap index(int[][] positions) { TreeSet pos = new TreeSet<>(); for (int[] arr : positions) { @@ -95,9 +90,7 @@ public class Code02_FallingSquares { public List fallingSquares(int[][] positions) { HashMap map = index(positions); - // 100 -> 1 306 -> 2 403 -> 3 - // [100,403] 1~3 - int N = map.size(); // 1 ~ N + int N = map.size(); SegmentTree segmentTree = new SegmentTree(N); int max = 0; List res = new ArrayList<>(); diff --git a/src/class33/Hash.java b/src/class33/Hash.java new file mode 100644 index 0000000..552191b --- /dev/null +++ b/src/class33/Hash.java @@ -0,0 +1,48 @@ +package class33; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Security; + +import javax.xml.bind.DatatypeConverter; + +public class Hash { + + private MessageDigest hash; + + public Hash(String algorithm) { + try { + hash = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + public String hashCode(String input) { + return DatatypeConverter.printHexBinary(hash.digest(input.getBytes())).toUpperCase(); + } + + public static void main(String[] args) { + System.out.println("支持的算法 : "); + for (String str : Security.getAlgorithms("MessageDigest")) { + System.out.println(str); + } + System.out.println("======="); + + String algorithm = "SHA"; + Hash hash = new Hash(algorithm); + + String input1 = "zuochengyunzuochengyun1"; + String input2 = "zuochengyunzuochengyun2"; + String input3 = "zuochengyunzuochengyun3"; + String input4 = "zuochengyunzuochengyun4"; + String input5 = "zuochengyunzuochengyun5"; + System.out.println(hash.hashCode(input1)); + System.out.println(hash.hashCode(input2)); + System.out.println(hash.hashCode(input3)); + System.out.println(hash.hashCode(input4)); + System.out.println(hash.hashCode(input5)); + + } + +} diff --git a/src/class34/说明.txt b/src/class34/说明.txt new file mode 100644 index 0000000..b1dd3f5 --- /dev/null +++ b/src/class34/说明.txt @@ -0,0 +1,2 @@ +本章并无code,因为资源限制类题目代码量巨大,需要整个工程的设计 +面试中主要和面试官聊解法,也不会让代码实现 \ No newline at end of file diff --git a/src/class35/Code01_AVLTreeMap.java b/src/class35/Code01_AVLTreeMap.java new file mode 100644 index 0000000..caafd46 --- /dev/null +++ b/src/class35/Code01_AVLTreeMap.java @@ -0,0 +1,257 @@ +package class35; + +public class Code01_AVLTreeMap { + + public static class AVLNode, V> { + public K k; + public V v; + public AVLNode l; + public AVLNode r; + public int h; + + public AVLNode(K key, V value) { + k = key; + v = value; + h = 1; + } + } + + public static class AVLTreeMap, V> { + private AVLNode root; + private int size; + + public AVLTreeMap() { + root = null; + size = 0; + } + + private AVLNode rightRotate(AVLNode cur) { + AVLNode left = cur.l; + cur.l = left.r; + left.r = cur; + cur.h = Math.max((cur.l != null ? cur.l.h : 0), (cur.r != null ? cur.r.h : 0)) + 1; + left.h = Math.max((left.l != null ? left.l.h : 0), (left.r != null ? left.r.h : 0)) + 1; + return left; + } + + private AVLNode leftRotate(AVLNode cur) { + AVLNode right = cur.r; + cur.r = right.l; + right.l = cur; + cur.h = Math.max((cur.l != null ? cur.l.h : 0), (cur.r != null ? cur.r.h : 0)) + 1; + right.h = Math.max((right.l != null ? right.l.h : 0), (right.r != null ? right.r.h : 0)) + 1; + return right; + } + + private AVLNode maintain(AVLNode cur) { + if (cur == null) { + return null; + } + int leftHeight = cur.l != null ? cur.l.h : 0; + int rightHeight = cur.r != null ? cur.r.h : 0; + if (Math.abs(leftHeight - rightHeight) > 1) { + if (leftHeight > rightHeight) { + int leftLeftHeight = cur.l != null && cur.l.l != null ? cur.l.l.h : 0; + int leftRightHeight = cur.l != null && cur.l.r != null ? cur.l.r.h : 0; + if (leftLeftHeight >= leftRightHeight) { + cur = rightRotate(cur); + } else { + cur.l = leftRotate(cur.l); + cur = rightRotate(cur); + } + } else { + int rightLeftHeight = cur.r != null && cur.r.l != null ? cur.r.l.h : 0; + int rightRightHeight = cur.r != null && cur.r.r != null ? cur.r.r.h : 0; + if (rightRightHeight >= rightLeftHeight) { + cur = leftRotate(cur); + } else { + cur.r = rightRotate(cur.r); + cur = leftRotate(cur); + } + } + } + return cur; + } + + private AVLNode findLastIndex(K key) { + AVLNode pre = root; + AVLNode cur = root; + while (cur != null) { + pre = cur; + if (key.compareTo(cur.k) == 0) { + break; + } else if (key.compareTo(cur.k) < 0) { + cur = cur.l; + } else { + cur = cur.r; + } + } + return pre; + } + + private AVLNode findLastNoSmallIndex(K key) { + AVLNode ans = null; + AVLNode cur = root; + while (cur != null) { + if (key.compareTo(cur.k) == 0) { + ans = cur; + break; + } else if (key.compareTo(cur.k) < 0) { + ans = cur; + cur = cur.l; + } else { + cur = cur.r; + } + } + return ans; + } + + private AVLNode findLastNoBigIndex(K key) { + AVLNode ans = null; + AVLNode cur = root; + while (cur != null) { + if (key.compareTo(cur.k) == 0) { + ans = cur; + break; + } else if (key.compareTo(cur.k) < 0) { + cur = cur.l; + } else { + ans = cur; + cur = cur.r; + } + } + return ans; + } + + private AVLNode add(AVLNode cur, K key, V value) { + if (cur == null) { + return new AVLNode(key, value); + } else { + if (key.compareTo(cur.k) < 0) { + cur.l = add(cur.l, key, value); + } else { + cur.r = add(cur.r, key, value); + } + cur.h = Math.max(cur.l != null ? cur.l.h : 0, cur.r != null ? cur.r.h : 0) + 1; + return maintain(cur); + } + } + + // 在cur这棵树上,删掉key所代表的节点 + // 返回cur这棵树的新头部 + private AVLNode delete(AVLNode cur, K key) { + if (key.compareTo(cur.k) > 0) { + cur.r = delete(cur.r, key); + } else if (key.compareTo(cur.k) < 0) { + cur.l = delete(cur.l, key); + } else { + if (cur.l == null && cur.r == null) { + cur = null; + } else if (cur.l == null && cur.r != null) { + cur = cur.r; + } else if (cur.l != null && cur.r == null) { + cur = cur.l; + } else { + AVLNode des = cur.r; + while (des.l != null) { + des = des.l; + } + cur.r = delete(cur.r, des.k); + des.l = cur.l; + des.r = cur.r; + cur = des; + } + } + if (cur != null) { + cur.h = Math.max(cur.l != null ? cur.l.h : 0, cur.r != null ? cur.r.h : 0) + 1; + } + return maintain(cur); + } + + public int size() { + return size; + } + + public boolean containsKey(K key) { + if (key == null) { + return false; + } + AVLNode lastNode = findLastIndex(key); + return lastNode != null && key.compareTo(lastNode.k) == 0 ? true : false; + } + + public void put(K key, V value) { + if (key == null) { + return; + } + AVLNode lastNode = findLastIndex(key); + if (lastNode != null && key.compareTo(lastNode.k) == 0) { + lastNode.v = value; + } else { + size++; + root = add(root, key, value); + } + } + + public void remove(K key) { + if (key == null) { + return; + } + if (containsKey(key)) { + size--; + root = delete(root, key); + } + } + + public V get(K key) { + if (key == null) { + return null; + } + AVLNode lastNode = findLastIndex(key); + if (lastNode != null && key.compareTo(lastNode.k) == 0) { + return lastNode.v; + } + return null; + } + + public K firstKey() { + if (root == null) { + return null; + } + AVLNode cur = root; + while (cur.l != null) { + cur = cur.l; + } + return cur.k; + } + + public K lastKey() { + if (root == null) { + return null; + } + AVLNode cur = root; + while (cur.r != null) { + cur = cur.r; + } + return cur.k; + } + + public K floorKey(K key) { + if (key == null) { + return null; + } + AVLNode lastNoBigNode = findLastNoBigIndex(key); + return lastNoBigNode == null ? null : lastNoBigNode.k; + } + + public K ceilingKey(K key) { + if (key == null) { + return null; + } + AVLNode lastNoSmallNode = findLastNoSmallIndex(key); + return lastNoSmallNode == null ? null : lastNoSmallNode.k; + } + + } + +} diff --git a/src/class36/Code01_SizeBalancedTreeMap.java b/src/class36/Code01_SizeBalancedTreeMap.java new file mode 100644 index 0000000..5077b7a --- /dev/null +++ b/src/class36/Code01_SizeBalancedTreeMap.java @@ -0,0 +1,360 @@ +package class36; + +public class Code01_SizeBalancedTreeMap { + + public static class SBTNode, V> { + public K key; + public V value; + public SBTNode l; + public SBTNode r; + public int size; // 不同的key的数量 + + public SBTNode(K key, V value) { + this.key = key; + this.value = value; + size = 1; + } + } + + public static class SizeBalancedTreeMap, V> { + private SBTNode root; + + private SBTNode rightRotate(SBTNode cur) { + 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; + return leftNode; + } + + private SBTNode leftRotate(SBTNode cur) { + 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; + return rightNode; + } + + private SBTNode maintain(SBTNode cur) { + if (cur == null) { + return null; + } + int leftSize = cur.l != null ? cur.l.size : 0; + int leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0; + int leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0; + int rightSize = cur.r != null ? cur.r.size : 0; + int rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0; + int rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0; + if (leftLeftSize > rightSize) { + cur = rightRotate(cur); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (leftRightSize > rightSize) { + cur.l = leftRotate(cur.l); + cur = rightRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (rightRightSize > leftSize) { + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur = maintain(cur); + } else if (rightLeftSize > leftSize) { + cur.r = rightRotate(cur.r); + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(cur); + } + return cur; + } + + private SBTNode findLastIndex(K key) { + SBTNode pre = root; + SBTNode 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 findLastNoSmallIndex(K key) { + SBTNode ans = null; + SBTNode 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 findLastNoBigIndex(K key) { + SBTNode ans = null; + SBTNode 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 add(SBTNode cur, K key, V value) { + if (cur == null) { + return new SBTNode(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 delete(SBTNode 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 pre = null; + SBTNode 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 getIndex(SBTNode 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 lastNode = findLastIndex(key); + return lastNode != null && key.compareTo(lastNode.key) == 0 ? true : false; + } + + // (key,value) put -> 有序表 新增、改value + public void put(K key, V value) { + if (key == null) { + throw new RuntimeException("invalid parameter."); + } + SBTNode 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 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 cur = root; + while (cur.l != null) { + cur = cur.l; + } + return cur.key; + } + + public K lastKey() { + if (root == null) { + return null; + } + SBTNode 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 lastNoBigNode = findLastNoBigIndex(key); + return lastNoBigNode == null ? null : lastNoBigNode.key; + } + + public K ceilingKey(K key) { + if (key == null) { + throw new RuntimeException("invalid parameter."); + } + SBTNode lastNoSmallNode = findLastNoSmallIndex(key); + return lastNoSmallNode == null ? null : lastNoSmallNode.key; + } + + } + + // for test + public static void printAll(SBTNode head) { + System.out.println("Binary Tree:"); + printInOrder(head, 0, "H", 17); + System.out.println(); + } + + // for test + public static void printInOrder(SBTNode head, int height, String to, int len) { + if (head == null) { + return; + } + printInOrder(head.r, height + 1, "v", len); + String val = to + "(" + head.key + "," + head.value + ")" + to; + int lenM = val.length(); + int lenL = (len - lenM) / 2; + int lenR = len - lenM - lenL; + val = getSpace(lenL) + val + getSpace(lenR); + System.out.println(getSpace(height * len) + val); + printInOrder(head.l, height + 1, "^", len); + } + + // for test + public static String getSpace(int num) { + String space = " "; + StringBuffer buf = new StringBuffer(""); + for (int i = 0; i < num; i++) { + buf.append(space); + } + return buf.toString(); + } + + public static void main(String[] args) { + SizeBalancedTreeMap sbt = new SizeBalancedTreeMap(); + sbt.put("d", 4); + sbt.put("c", 3); + sbt.put("a", 1); + sbt.put("b", 2); + // sbt.put("e", 5); + sbt.put("g", 7); + sbt.put("f", 6); + sbt.put("h", 8); + sbt.put("i", 9); + sbt.put("a", 111); + System.out.println(sbt.get("a")); + sbt.put("a", 1); + System.out.println(sbt.get("a")); + for (int i = 0; i < sbt.size(); i++) { + System.out.println(sbt.getIndexKey(i) + " , " + sbt.getIndexValue(i)); + } + printAll(sbt.root); + System.out.println(sbt.firstKey()); + System.out.println(sbt.lastKey()); + System.out.println(sbt.floorKey("g")); + System.out.println(sbt.ceilingKey("g")); + System.out.println(sbt.floorKey("e")); + System.out.println(sbt.ceilingKey("e")); + System.out.println(sbt.floorKey("")); + System.out.println(sbt.ceilingKey("")); + System.out.println(sbt.floorKey("j")); + System.out.println(sbt.ceilingKey("j")); + sbt.remove("d"); + printAll(sbt.root); + sbt.remove("f"); + printAll(sbt.root); + + } + +} diff --git a/src/class36/Code02_SkipListMap.java b/src/class36/Code02_SkipListMap.java new file mode 100644 index 0000000..a450e78 --- /dev/null +++ b/src/class36/Code02_SkipListMap.java @@ -0,0 +1,248 @@ +package class36; + +import java.util.ArrayList; + +public class Code02_SkipListMap { + + // 跳表的节点定义 + public static class SkipListNode, V> { + public K key; + public V val; + public ArrayList> nextNodes; + + public SkipListNode(K k, V v) { + key = k; + val = v; + nextNodes = new ArrayList>(); + } + + // 遍历的时候,如果是往右遍历到的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, V> { + private static final double PROBABILITY = 0.5; // < 0.5 继续做,>=0.5 停 + private SkipListNode head; + private int size; + private int maxLevel; + + public SkipListMap() { + head = new SkipListNode(null, null); + head.nextNodes.add(null); // 0 + size = 0; + maxLevel = 0; + } + + // 从最高层开始,一路找下去, + // 最终,找到第0层的 mostRightLessNodeInTree(K key) { + if (key == null) { + return null; + } + int level = maxLevel; + SkipListNode cur = head; + while (level >= 0) { // 从上层跳下层 + // cur level -> level-1 + cur = mostRightLessNodeInLevel(key, cur, level--); + } + return cur; + } + + // 在level层里,如何往右移动 + // 现在来到的节点是cur,来到了cur的level层,在level层上,找到 mostRightLessNodeInLevel(K key, + SkipListNode cur, + int level) { + SkipListNode 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 less = mostRightLessNodeInTree(key); + SkipListNode next = less.nextNodes.get(0); + return next != null && next.isKeyEqual(key); + } + + // 新增、改value + public void put(K key, V value) { + if (key == null) { + return; + } + // 0层上,最右一个,< key 的Node -> >key + SkipListNode less = mostRightLessNodeInTree(key); + SkipListNode find = less.nextNodes.get(0); + if (find != null && find.isKeyEqual(key)) { + find.val = value; + } else { // find == null 8 7 9 + size++; + int newNodeLevel = 0; + while (Math.random() < PROBABILITY) { + newNodeLevel++; + } + // newNodeLevel + while (newNodeLevel > maxLevel) { + head.nextNodes.add(null); + maxLevel++; + } + SkipListNode newNode = new SkipListNode(key, value); + for (int i = 0; i <= newNodeLevel; i++) { + newNode.nextNodes.add(null); + } + int level = maxLevel; + SkipListNode 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 less = mostRightLessNodeInTree(key); + SkipListNode 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 pre = head; + while (level >= 0) { + pre = mostRightLessNodeInLevel(key, pre, level); + SkipListNode 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 cur = head; + while (level >= 0) { + SkipListNode next = cur.nextNodes.get(level); + while (next != null) { + cur = next; + next = cur.nextNodes.get(level); + } + level--; + } + return cur.key; + } + + public K ceilingKey(K key) { + if (key == null) { + return null; + } + SkipListNode less = mostRightLessNodeInTree(key); + SkipListNode next = less.nextNodes.get(0); + return next != null ? next.key : null; + } + + public K floorKey(K key) { + if (key == null) { + return null; + } + SkipListNode less = mostRightLessNodeInTree(key); + SkipListNode next = less.nextNodes.get(0); + return next != null && next.isKeyEqual(key) ? next.key : less.key; + } + + public int size() { + return size; + } + + } + + // for test + public static void printAll(SkipListMap obj) { + for (int i = obj.maxLevel; i >= 0; i--) { + System.out.print("Level " + i + " : "); + SkipListNode cur = obj.head; + while (cur.nextNodes.get(i) != null) { + SkipListNode next = cur.nextNodes.get(i); + System.out.print("(" + next.key + " , " + next.val + ") "); + cur = next; + } + System.out.println(); + } + } + + public static void main(String[] args) { + SkipListMap test = new SkipListMap<>(); + printAll(test); + System.out.println("======================"); + test.put("A", "10"); + printAll(test); + System.out.println("======================"); + test.remove("A"); + printAll(test); + System.out.println("======================"); + test.put("E", "E"); + test.put("B", "B"); + test.put("A", "A"); + test.put("F", "F"); + test.put("C", "C"); + test.put("D", "D"); + printAll(test); + System.out.println("======================"); + System.out.println(test.containsKey("B")); + System.out.println(test.containsKey("Z")); + System.out.println(test.firstKey()); + System.out.println(test.lastKey()); + System.out.println(test.floorKey("D")); + System.out.println(test.ceilingKey("D")); + System.out.println("======================"); + test.remove("D"); + printAll(test); + System.out.println("======================"); + System.out.println(test.floorKey("D")); + System.out.println(test.ceilingKey("D")); + + + } + +} diff --git a/src/class37/Code01_CountofRangeSum.java b/src/class37/Code01_CountofRangeSum.java new file mode 100644 index 0000000..e8f1292 --- /dev/null +++ b/src/class37/Code01_CountofRangeSum.java @@ -0,0 +1,224 @@ +package class37; + +import java.util.HashSet; + +public class Code01_CountofRangeSum { + + public static int countRangeSum1(int[] nums, int lower, int upper) { + int n = nums.length; + long[] sums = new long[n + 1]; + for (int i = 0; i < n; ++i) + sums[i + 1] = sums[i] + nums[i]; + return countWhileMergeSort(sums, 0, n + 1, lower, upper); + } + + private static int countWhileMergeSort(long[] sums, int start, int end, int lower, int upper) { + if (end - start <= 1) + return 0; + int mid = (start + end) / 2; + int count = countWhileMergeSort(sums, start, mid, lower, upper) + + countWhileMergeSort(sums, mid, end, lower, upper); + int j = mid, k = mid, t = mid; + long[] cache = new long[end - start]; + for (int i = start, r = 0; i < mid; ++i, ++r) { + while (k < end && sums[k] - sums[i] < lower) + k++; + while (j < end && sums[j] - sums[i] <= upper) + j++; + while (t < end && sums[t] < sums[i]) + cache[r++] = sums[t++]; + cache[r] = sums[i]; + count += j - k; + } + System.arraycopy(cache, 0, sums, start, t - start); + return count; + } + + 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 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 maintain(SBTNode cur) { + if (cur == null) { + return null; + } + long leftSize = cur.l != null ? cur.l.size : 0; + long leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0; + long leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0; + long rightSize = cur.r != null ? cur.r.size : 0; + long rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0; + long rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0; + if (leftLeftSize > rightSize) { + cur = rightRotate(cur); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (leftRightSize > rightSize) { + cur.l = leftRotate(cur.l); + cur = rightRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (rightRightSize > leftSize) { + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur = maintain(cur); + } else if (rightLeftSize > leftSize) { + cur.r = rightRotate(cur.r); + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(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 maintain(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 + // a - b + + long a = treeSet.lessKeySize(sum - lower + 1); + long b = treeSet.lessKeySize(sum - upper); + ans += a - b; + treeSet.add(sum); + } + return ans; + } + + // for test + public static void printArray(int[] arr) { + for (int i = 0; i < arr.length; i++) { + System.out.print(arr[i] + " "); + } + System.out.println(); + } + + // for test + public static int[] generateArray(int len, int varible) { + int[] arr = new int[len]; + for (int i = 0; i < arr.length; i++) { + arr[i] = (int) (Math.random() * varible); + } + return arr; + } + + public static void main(String[] args) { + int len = 200; + int varible = 50; + for (int i = 0; i < 10000; i++) { + int[] test = generateArray(len, varible); + int lower = (int) (Math.random() * varible) - (int) (Math.random() * varible); + int upper = lower + (int) (Math.random() * varible); + int ans1 = countRangeSum1(test, lower, upper); + int ans2 = countRangeSum2(test, lower, upper); + if (ans1 != ans2) { + printArray(test); + System.out.println(lower); + System.out.println(upper); + System.out.println(ans1); + System.out.println(ans2); + } + } + + } + +} diff --git a/src/class37/Code02_SlidingWindowMedian.java b/src/class37/Code02_SlidingWindowMedian.java new file mode 100644 index 0000000..2f3fa63 --- /dev/null +++ b/src/class37/Code02_SlidingWindowMedian.java @@ -0,0 +1,228 @@ +package class37; + +public class Code02_SlidingWindowMedian { + + public static class SBTNode> { + public K key; + public SBTNode l; + public SBTNode r; + public int size; + + public SBTNode(K k) { + key = k; + size = 1; + } + } + + public static class SizeBalancedTreeMap> { + private SBTNode root; + + private SBTNode rightRotate(SBTNode cur) { + 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; + return leftNode; + } + + private SBTNode leftRotate(SBTNode cur) { + 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; + return rightNode; + } + + private SBTNode maintain(SBTNode cur) { + if (cur == null) { + return null; + } + int leftSize = cur.l != null ? cur.l.size : 0; + int leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0; + int leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0; + int rightSize = cur.r != null ? cur.r.size : 0; + int rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0; + int rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0; + if (leftLeftSize > rightSize) { + cur = rightRotate(cur); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (leftRightSize > rightSize) { + cur.l = leftRotate(cur.l); + cur = rightRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (rightRightSize > leftSize) { + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur = maintain(cur); + } else if (rightLeftSize > leftSize) { + cur.r = rightRotate(cur.r); + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(cur); + } + return cur; + } + + private SBTNode findLastIndex(K key) { + SBTNode pre = root; + SBTNode 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 add(SBTNode cur, K key) { + if (cur == null) { + return new SBTNode(key); + } else { + cur.size++; + if (key.compareTo(cur.key) < 0) { + cur.l = add(cur.l, key); + } else { + cur.r = add(cur.r, key); + } + return maintain(cur); + } + } + + private SBTNode delete(SBTNode 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 pre = null; + SBTNode 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 getIndex(SBTNode 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 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 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 { + 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 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; + } + +} diff --git a/src/class37/Code03_AddRemoveGetIndexGreat.java b/src/class37/Code03_AddRemoveGetIndexGreat.java new file mode 100644 index 0000000..2c2436a --- /dev/null +++ b/src/class37/Code03_AddRemoveGetIndexGreat.java @@ -0,0 +1,259 @@ +package class37; + +import java.util.ArrayList; + +public class Code03_AddRemoveGetIndexGreat { + + public static class SBTNode { + public V value; + public SBTNode l; + public SBTNode r; + public int size; + + public SBTNode(V v) { + value = v; + size = 1; + } + } + + public static class SbtList { + private SBTNode root; + + private SBTNode rightRotate(SBTNode cur) { + 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; + return leftNode; + } + + private SBTNode leftRotate(SBTNode cur) { + 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; + return rightNode; + } + + private SBTNode maintain(SBTNode cur) { + if (cur == null) { + return null; + } + int leftSize = cur.l != null ? cur.l.size : 0; + int leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0; + int leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0; + int rightSize = cur.r != null ? cur.r.size : 0; + int rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0; + int rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0; + if (leftLeftSize > rightSize) { + cur = rightRotate(cur); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (leftRightSize > rightSize) { + cur.l = leftRotate(cur.l); + cur = rightRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(cur); + } else if (rightRightSize > leftSize) { + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur = maintain(cur); + } else if (rightLeftSize > leftSize) { + cur.r = rightRotate(cur.r); + cur = leftRotate(cur); + cur.l = maintain(cur.l); + cur.r = maintain(cur.r); + cur = maintain(cur); + } + return cur; + } + + private SBTNode add(SBTNode root, int index, SBTNode cur) { + if (root == null) { + return cur; + } + root.size++; + int leftAndHeadSize = (root.l != null ? root.l.size : 0) + 1; + if (index < leftAndHeadSize) { + root.l = add(root.l, index, cur); + } else { + root.r = add(root.r, index - leftAndHeadSize, cur); + } + root = maintain(root); + return root; + } + + private SBTNode remove(SBTNode root, int index) { + root.size--; + int rootIndex = root.l != null ? root.l.size : 0; + if (index != rootIndex) { + if (index < rootIndex) { + root.l = remove(root.l, index); + } else { + root.r = remove(root.r, index - rootIndex - 1); + } + return root; + } + if (root.l == null && root.r == null) { + return null; + } + if (root.l == null) { + return root.r; + } + if (root.r == null) { + return root.l; + } + SBTNode pre = null; + SBTNode suc = root.r; + suc.size--; + while (suc.l != null) { + pre = suc; + suc = suc.l; + suc.size--; + } + if (pre != null) { + pre.l = suc.r; + suc.r = root.r; + } + suc.l = root.l; + suc.size = suc.l.size + (suc.r == null ? 0 : suc.r.size) + 1; + return suc; + } + + private SBTNode get(SBTNode root, int index) { + int leftSize = root.l != null ? root.l.size : 0; + if (index < leftSize) { + return get(root.l, index); + } else if (index == leftSize) { + return root; + } else { + return get(root.r, index - leftSize - 1); + } + } + + public void add(int index, V num) { + SBTNode cur = new SBTNode(num); + if (root == null) { + root = cur; + } else { + if (index <= root.size) { + root = add(root, index, cur); + } + } + } + + public V get(int index) { + SBTNode ans = get(root, index); + return ans.value; + } + + public void remove(int index) { + if (index >= 0 && size() > index) { + root = remove(root, index); + } + } + + public int size() { + return root == null ? 0 : root.size; + } + + } + + // 通过以下这个测试, + // 可以很明显的看到LinkedList的插入、删除、get效率不如SbtList + // LinkedList需要找到index所在的位置之后才能插入或者读取,时间复杂度O(N) + // SbtList是平衡搜索二叉树,所以插入或者读取时间复杂度都是O(logN) + public static void main(String[] args) { + // 功能测试 + int test = 50000; + int max = 1000000; + boolean pass = true; + ArrayList list = new ArrayList<>(); + SbtList sbtList = new SbtList<>(); + for (int i = 0; i < test; i++) { + if (list.size() != sbtList.size()) { + pass = false; + break; + } + if (list.size() > 1 && Math.random() < 0.5) { + int removeIndex = (int) (Math.random() * list.size()); + list.remove(removeIndex); + sbtList.remove(removeIndex); + } else { + int randomIndex = (int) (Math.random() * (list.size() + 1)); + int randomValue = (int) (Math.random() * (max + 1)); + list.add(randomIndex, randomValue); + sbtList.add(randomIndex, randomValue); + } + } + for (int i = 0; i < list.size(); i++) { + if (!list.get(i).equals(sbtList.get(i))) { + pass = false; + break; + } + } + System.out.println("功能测试是否通过 : " + pass); + + // 性能测试 + test = 500000; + list = new ArrayList<>(); + sbtList = new SbtList<>(); + long start = 0; + long end = 0; + + start = System.currentTimeMillis(); + for (int i = 0; i < test; i++) { + int randomIndex = (int) (Math.random() * (list.size() + 1)); + int randomValue = (int) (Math.random() * (max + 1)); + list.add(randomIndex, randomValue); + } + end = System.currentTimeMillis(); + System.out.println("ArrayList插入总时长(毫秒) : " + (end - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < test; i++) { + int randomIndex = (int) (Math.random() * (i + 1)); + list.get(randomIndex); + } + end = System.currentTimeMillis(); + System.out.println("ArrayList读取总时长(毫秒) : " + (end - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < test; i++) { + int randomIndex = (int) (Math.random() * list.size()); + list.remove(randomIndex); + } + end = System.currentTimeMillis(); + System.out.println("ArrayList删除总时长(毫秒) : " + (end - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < test; i++) { + int randomIndex = (int) (Math.random() * (sbtList.size() + 1)); + int randomValue = (int) (Math.random() * (max + 1)); + sbtList.add(randomIndex, randomValue); + } + end = System.currentTimeMillis(); + System.out.println("SbtList插入总时长(毫秒) : " + (end - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < test; i++) { + int randomIndex = (int) (Math.random() * (i + 1)); + sbtList.get(randomIndex); + } + end = System.currentTimeMillis(); + System.out.println("SbtList读取总时长(毫秒) : " + (end - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < test; i++) { + int randomIndex = (int) (Math.random() * sbtList.size()); + sbtList.remove(randomIndex); + } + end = System.currentTimeMillis(); + System.out.println("SbtList删除总时长(毫秒) : " + (end - start)); + + } + +} diff --git a/src/class37/Compare.java b/src/class37/Compare.java new file mode 100644 index 0000000..5bbfd0d --- /dev/null +++ b/src/class37/Compare.java @@ -0,0 +1,408 @@ +package class37; + +import java.util.TreeMap; + +import class35.Code01_AVLTreeMap.AVLTreeMap; +import class36.Code01_SizeBalancedTreeMap.SizeBalancedTreeMap; +import class36.Code02_SkipListMap.SkipListMap; + +// 本文件为avl、sbt、skiplist三种结构的测试文件 +public class Compare { + + public static void functionTest() { + System.out.println("功能测试开始"); + TreeMap treeMap = new TreeMap<>(); + AVLTreeMap avl = new AVLTreeMap<>(); + SizeBalancedTreeMap sbt = new SizeBalancedTreeMap<>(); + SkipListMap skip = new SkipListMap<>(); + int maxK = 500; + int maxV = 50000; + int testTime = 1000000; + for (int i = 0; i < testTime; i++) { + int addK = (int) (Math.random() * maxK); + int addV = (int) (Math.random() * maxV); + treeMap.put(addK, addV); + avl.put(addK, addV); + sbt.put(addK, addV); + skip.put(addK, addV); + + int removeK = (int) (Math.random() * maxK); + treeMap.remove(removeK); + avl.remove(removeK); + sbt.remove(removeK); + skip.remove(removeK); + + int querryK = (int) (Math.random() * maxK); + if (treeMap.containsKey(querryK) != avl.containsKey(querryK) + || sbt.containsKey(querryK) != skip.containsKey(querryK) + || treeMap.containsKey(querryK) != sbt.containsKey(querryK)) { + System.out.println("containsKey Oops"); + System.out.println(treeMap.containsKey(querryK)); + System.out.println(avl.containsKey(querryK)); + System.out.println(sbt.containsKey(querryK)); + System.out.println(skip.containsKey(querryK)); + break; + } + + if (treeMap.containsKey(querryK)) { + int v1 = treeMap.get(querryK); + int v2 = avl.get(querryK); + int v3 = sbt.get(querryK); + int v4 = skip.get(querryK); + if (v1 != v2 || v3 != v4 || v1 != v3) { + System.out.println("get Oops"); + System.out.println(treeMap.get(querryK)); + System.out.println(avl.get(querryK)); + System.out.println(sbt.get(querryK)); + System.out.println(skip.get(querryK)); + break; + } + Integer f1 = treeMap.floorKey(querryK); + Integer f2 = avl.floorKey(querryK); + Integer f3 = sbt.floorKey(querryK); + Integer f4 = skip.floorKey(querryK); + if (f1 == null && (f2 != null || f3 != null || f4 != null)) { + System.out.println("floorKey Oops"); + System.out.println(treeMap.floorKey(querryK)); + System.out.println(avl.floorKey(querryK)); + System.out.println(sbt.floorKey(querryK)); + System.out.println(skip.floorKey(querryK)); + break; + } + if (f1 != null && (f2 == null || f3 == null || f4 == null)) { + System.out.println("floorKey Oops"); + System.out.println(treeMap.floorKey(querryK)); + System.out.println(avl.floorKey(querryK)); + System.out.println(sbt.floorKey(querryK)); + System.out.println(skip.floorKey(querryK)); + break; + } + if (f1 != null) { + int ans1 = f1; + int ans2 = f2; + int ans3 = f3; + int ans4 = f4; + if (ans1 != ans2 || ans3 != ans4 || ans1 != ans3) { + System.out.println("floorKey Oops"); + System.out.println(treeMap.floorKey(querryK)); + System.out.println(avl.floorKey(querryK)); + System.out.println(sbt.floorKey(querryK)); + System.out.println(skip.floorKey(querryK)); + break; + } + } + f1 = treeMap.ceilingKey(querryK); + f2 = avl.ceilingKey(querryK); + f3 = sbt.ceilingKey(querryK); + f4 = skip.ceilingKey(querryK); + if (f1 == null && (f2 != null || f3 != null || f4 != null)) { + System.out.println("ceilingKey Oops"); + System.out.println(treeMap.ceilingKey(querryK)); + System.out.println(avl.ceilingKey(querryK)); + System.out.println(sbt.ceilingKey(querryK)); + System.out.println(skip.ceilingKey(querryK)); + break; + } + if (f1 != null && (f2 == null || f3 == null || f4 == null)) { + System.out.println("ceilingKey Oops"); + System.out.println(treeMap.ceilingKey(querryK)); + System.out.println(avl.ceilingKey(querryK)); + System.out.println(sbt.ceilingKey(querryK)); + System.out.println(skip.ceilingKey(querryK)); + break; + } + if (f1 != null) { + int ans1 = f1; + int ans2 = f2; + int ans3 = f3; + int ans4 = f4; + if (ans1 != ans2 || ans3 != ans4 || ans1 != ans3) { + System.out.println("ceilingKey Oops"); + System.out.println(treeMap.ceilingKey(querryK)); + System.out.println(avl.ceilingKey(querryK)); + System.out.println(sbt.ceilingKey(querryK)); + System.out.println(skip.ceilingKey(querryK)); + break; + } + } + + } + + Integer f1 = treeMap.firstKey(); + Integer f2 = avl.firstKey(); + Integer f3 = sbt.firstKey(); + Integer f4 = skip.firstKey(); + if (f1 == null && (f2 != null || f3 != null || f4 != null)) { + System.out.println("firstKey Oops"); + System.out.println(treeMap.firstKey()); + System.out.println(avl.firstKey()); + System.out.println(sbt.firstKey()); + System.out.println(skip.firstKey()); + break; + } + if (f1 != null && (f2 == null || f3 == null || f4 == null)) { + System.out.println("firstKey Oops"); + System.out.println(treeMap.firstKey()); + System.out.println(avl.firstKey()); + System.out.println(sbt.firstKey()); + System.out.println(skip.firstKey()); + break; + } + if (f1 != null) { + int ans1 = f1; + int ans2 = f2; + int ans3 = f3; + int ans4 = f4; + if (ans1 != ans2 || ans3 != ans4 || ans1 != ans3) { + System.out.println("firstKey Oops"); + System.out.println(treeMap.firstKey()); + System.out.println(avl.firstKey()); + System.out.println(sbt.firstKey()); + System.out.println(skip.firstKey()); + break; + } + } + + f1 = treeMap.lastKey(); + f2 = avl.lastKey(); + f3 = sbt.lastKey(); + f4 = skip.lastKey(); + if (f1 == null && (f2 != null || f3 != null || f4 != null)) { + System.out.println("lastKey Oops"); + System.out.println(treeMap.lastKey()); + System.out.println(avl.lastKey()); + System.out.println(sbt.lastKey()); + System.out.println(skip.lastKey()); + break; + } + if (f1 != null && (f2 == null || f3 == null || f4 == null)) { + System.out.println("firstKey Oops"); + System.out.println(treeMap.lastKey()); + System.out.println(avl.lastKey()); + System.out.println(sbt.lastKey()); + System.out.println(skip.lastKey()); + break; + } + if (f1 != null) { + int ans1 = f1; + int ans2 = f2; + int ans3 = f3; + int ans4 = f4; + if (ans1 != ans2 || ans3 != ans4 || ans1 != ans3) { + System.out.println("lastKey Oops"); + System.out.println(treeMap.lastKey()); + System.out.println(avl.lastKey()); + System.out.println(sbt.lastKey()); + System.out.println(skip.lastKey()); + break; + } + } + if (treeMap.size() != avl.size() || sbt.size() != skip.size() || treeMap.size() != sbt.size()) { + System.out.println("size Oops"); + System.out.println(treeMap.size()); + System.out.println(avl.size()); + System.out.println(sbt.size()); + System.out.println(skip.size()); + break; + } + } + System.out.println("功能测试结束"); + } + + public static void performanceTest() { + System.out.println("性能测试开始"); + TreeMap treeMap; + AVLTreeMap avl; + SizeBalancedTreeMap sbt; + SkipListMap skip; + long start; + long end; + int max = 1000000; + treeMap = new TreeMap<>(); + avl = new AVLTreeMap<>(); + sbt = new SizeBalancedTreeMap<>(); + skip = new SkipListMap<>(); + System.out.println("顺序递增加入测试,数据规模 : " + max); + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + treeMap.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("treeMap 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + avl.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("avl 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + sbt.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("sbt 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + skip.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("skip 运行时间 : " + (end - start) + "ms"); + + System.out.println("顺序递增删除测试,数据规模 : " + max); + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + treeMap.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("treeMap 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + avl.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("avl 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + sbt.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("sbt 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + skip.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("skip 运行时间 : " + (end - start) + "ms"); + + System.out.println("顺序递减加入测试,数据规模 : " + max); + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + treeMap.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("treeMap 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + avl.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("avl 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + sbt.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("sbt 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + skip.put(i, i); + } + end = System.currentTimeMillis(); + System.out.println("skip 运行时间 : " + (end - start) + "ms"); + + System.out.println("顺序递减删除测试,数据规模 : " + max); + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + treeMap.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("treeMap 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + avl.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("avl 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + sbt.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("sbt 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + skip.remove(i); + } + end = System.currentTimeMillis(); + System.out.println("skip 运行时间 : " + (end - start) + "ms"); + + System.out.println("随机加入测试,数据规模 : " + max); + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + treeMap.put((int) (Math.random() * i), i); + } + end = System.currentTimeMillis(); + System.out.println("treeMap 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + avl.put((int) (Math.random() * i), i); + } + end = System.currentTimeMillis(); + System.out.println("avl 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + sbt.put((int) (Math.random() * i), i); + } + end = System.currentTimeMillis(); + System.out.println("sbt 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + skip.put((int) (Math.random() * i), i); + } + end = System.currentTimeMillis(); + System.out.println("skip 运行时间 : " + (end - start) + "ms"); + + System.out.println("随机删除测试,数据规模 : " + max); + start = System.currentTimeMillis(); + for (int i = 0; i < max; i++) { + treeMap.remove((int) (Math.random() * i)); + } + end = System.currentTimeMillis(); + System.out.println("treeMap 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + avl.remove((int) (Math.random() * i)); + } + end = System.currentTimeMillis(); + System.out.println("avl 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + sbt.remove((int) (Math.random() * i)); + } + end = System.currentTimeMillis(); + System.out.println("sbt 运行时间 : " + (end - start) + "ms"); + + start = System.currentTimeMillis(); + for (int i = max; i >= 0; i--) { + skip.remove((int) (Math.random() * i)); + } + end = System.currentTimeMillis(); + System.out.println("skip 运行时间 : " + (end - start) + "ms"); + + System.out.println("性能测试结束"); + } + + public static void main(String[] args) { + functionTest(); + System.out.println("======"); + performanceTest(); + } + +}