diff --git a/src/main/java/git/snippet/heap/Code_EveryStepShowBoss.java b/src/main/java/git/snippet/heap/Code_EveryStepShowBoss.java index 652556456a3f414d38702b9b62a1828fdb7a2723..263c5bfa9600a49459edf3dba3c5a81b5e8b3eee 100644 --- a/src/main/java/git/snippet/heap/Code_EveryStepShowBoss.java +++ b/src/main/java/git/snippet/heap/Code_EveryStepShowBoss.java @@ -251,13 +251,13 @@ public class Code_EveryStepShowBoss { public static class WhosYourDaddy { private final int daddyLimit; private HashMap customers; - private Code_Heap.HeapGreater candHeap; - private Code_Heap.HeapGreater daddyHeap; + private Code_HeapGreater candHeap; + private Code_HeapGreater daddyHeap; public WhosYourDaddy(int limit) { customers = new HashMap<>(); - candHeap = new Code_Heap.HeapGreater<>(new CandidateComparator()); - daddyHeap = new Code_Heap.HeapGreater<>(new DaddyComparator()); + candHeap = new Code_HeapGreater<>(new CandidateComparator()); + daddyHeap = new Code_HeapGreater<>(new DaddyComparator()); daddyLimit = limit; } diff --git a/src/main/java/git/snippet/heap/Code_Heap.java b/src/main/java/git/snippet/heap/Code_Heap.java deleted file mode 100644 index f8ccfed980f3922451e8e2b2a89de5ebd82216f3..0000000000000000000000000000000000000000 --- a/src/main/java/git/snippet/heap/Code_Heap.java +++ /dev/null @@ -1,244 +0,0 @@ -package git.snippet.heap; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; - -// 笔记:https://www.cnblogs.com/greyzeng/p/16933830.html -// 什么是完全二叉树 如果一个树是满的,它是完全二叉树,即便不是满的,也是从左到右依次变满的 -// 堆结构 -// 1)堆结构就是用数组实现的完全二叉树结构 -// 2)完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 -// 3)完全二叉树中如果每棵子树的最小值都在顶部就是小根堆 -// 4)堆结构的heapInsert与heapify操作 -// 5)堆结构的增大和减少 -// 6)Java中的PriorityQueue,就是堆结构 -// 用数组表示堆的两种情况 -// 第一种情况:如果使用数组0位置,对于i位置来说,它的: -// 左孩子 2 * i + 1 -// 右孩子 2 * i + 2 -// 父节点 (i - 1)/ 2 -// 第二种情况:如果不用0位置,对于i位置来说,它的: -// 左孩子 2 * i 即:i << 1 -// 右孩子 2 * i + 1 即:i << 1 | 1 -// 父节点 i / 2 即:i >> 1 -// 大根堆:完全二叉树中,每棵树的最大值都是头节点的值 -// heapify和heapInsert都是logN级别的复杂度,因为N个节点的二叉树高度是logN -public class Code_Heap { - - public static class MaxHeap { - private final int[] heap; - // private final int limit; limit == heap.length - private int heapSize; - - public MaxHeap(int limit) { - heap = new int[limit]; - // this.limit = limit; - heapSize = 0; - } - - public void push(int value) { - if (!isFull()) { - heap[heapSize] = value; - // value heapSize - heapInsert(); - heapSize++; - } - } - - public int pop() { - int ans = heap[0]; - swap(heap, 0, --heapSize); - heapify(); - return ans; - } - - private void heapInsert() { - int i = heapSize; - while (heap[i] > heap[(i - 1) / 2]) { - swap(heap, i, (i - 1) / 2); - i = (i - 1) / 2; - } - } - - private void heapify() { - int index = 0; - int left = index * 2 + 1; - while (left < heapSize) { - int largest // bigger index - = - left + 1 < heapSize // right child exist - && heap[left + 1] > heap[left] // compare left child and right child - ? left + 1 - : left; - largest = heap[largest] > heap[index] ? largest : index; - if (largest == index) { - break; - } - swap(heap, largest, index); - index = largest; - left = index * 2 + 1; - } - } - - public boolean isEmpty() { - return heapSize == 0; - } - - public boolean isFull() { - return heapSize == heap.length; - } - - private void swap(int[] arr, int i, int j) { - int tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } - } - - // 加强堆 - // 笔记:https://www.cnblogs.com/greyzeng/p/16936506.html - public static class HeapGreater { - - private ArrayList heap; - private HashMap indexMap; // 元素在堆中的位置 - private int heapSize; // 和heap配合使用 - private Comparator comp; - - public HeapGreater(Comparator c) { - heap = new ArrayList<>(); - indexMap = new HashMap<>(); - comp = c; - } - - public boolean isEmpty() { - return heapSize == 0; - } - - public int size() { - return heapSize; - } - - public boolean contains(T obj) { - return indexMap.containsKey(obj); - } - - public T peek() { - return heap.get(0); - } - - public void push(T obj) { - heap.add(obj); - indexMap.put(obj, heapSize); - heapInsert(heapSize++); - } - - public T pop() { - T ans = heap.get(0); - swap(0, heapSize - 1); - indexMap.remove(ans); - heap.remove(--heapSize); - heapify(0); - return ans; - } - - public void remove(T obj) { - T replace = heap.get(heapSize - 1); - int index = indexMap.get(obj); - indexMap.remove(obj); - heap.remove(--heapSize); - if (obj != replace) { // obj == replace表示删掉的是最后一个位置的数据,此时不需要进行resign操作 - heap.set(index, replace); - indexMap.put(replace, index); - resign(replace); - } - } - - public void resign(T obj) { - heapInsert(indexMap.get(obj)); - heapify(indexMap.get(obj)); - } - - // 请返回堆上的所有元素 - public List getAllElements() { - List ans = new ArrayList<>(); - for (T c : heap) { - ans.add(c); - } - return ans; - } - - private void heapInsert(int index) { - while (comp.compare(heap.get(index), heap.get((index - 1) / 2)) < 0) { - swap(index, (index - 1) / 2); - index = (index - 1) / 2; - } - } - - private void heapify(int index) { - int left = index * 2 + 1; - while (left < heapSize) { - int best = - left + 1 < heapSize && comp.compare(heap.get(left + 1), heap.get(left)) < 0 - ? (left + 1) - : left; - best = comp.compare(heap.get(best), heap.get(index)) < 0 ? best : index; - if (best == index) { - break; - } - swap(best, index); - index = best; - left = index * 2 + 1; - } - } - - private void swap(int i, int j) { - T o1 = heap.get(i); - T o2 = heap.get(j); - heap.set(i, o2); - heap.set(j, o1); - indexMap.put(o2, i); - indexMap.put(o1, j); - } - } - - public static class RightMaxHeap { - private final int limit; - private int[] arr; - private int size; - - public RightMaxHeap(int limit) { - arr = new int[limit]; - this.limit = limit; - size = 0; - } - - public boolean isEmpty() { - return size == 0; - } - - public boolean isFull() { - return size == limit; - } - - public void push(int value) { - if (size == limit) { - throw new RuntimeException("heap is full"); - } - arr[size++] = value; - } - - public int pop() { - int maxIndex = 0; - for (int i = 1; i < size; i++) { - if (arr[i] > arr[maxIndex]) { - maxIndex = i; - } - } - int ans = arr[maxIndex]; - arr[maxIndex] = arr[--size]; - return ans; - } - } -} diff --git a/src/main/java/git/snippet/heap/Code_HeapGreater.java b/src/main/java/git/snippet/heap/Code_HeapGreater.java new file mode 100644 index 0000000000000000000000000000000000000000..29846ab0923226218f8d4ab766bb616d3ba0fcee --- /dev/null +++ b/src/main/java/git/snippet/heap/Code_HeapGreater.java @@ -0,0 +1,109 @@ +package git.snippet.heap; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +// 加强堆 +// 笔记:https://www.cnblogs.com/greyzeng/p/16936506.html +public class Code_HeapGreater { + + private ArrayList heap; + private HashMap indexMap; // 元素在堆中的位置 + private int heapSize; // 和heap配合使用 + private Comparator comp; + + public Code_HeapGreater(Comparator c) { + heap = new ArrayList<>(); + indexMap = new HashMap<>(); + comp = c; + } + + public boolean isEmpty() { + return heapSize == 0; + } + + public int size() { + return heapSize; + } + + public boolean contains(T obj) { + return indexMap.containsKey(obj); + } + + public T peek() { + return heap.get(0); + } + + public void push(T obj) { + heap.add(obj); + indexMap.put(obj, heapSize); + heapInsert(heapSize++); + } + + public T pop() { + T ans = heap.get(0); + swap(0, heapSize - 1); + indexMap.remove(ans); + heap.remove(--heapSize); + heapify(0); + return ans; + } + + public void remove(T obj) { + T replace = heap.get(heapSize - 1); + int index = indexMap.get(obj); + indexMap.remove(obj); + heap.remove(--heapSize); + if (obj != replace) { // obj == replace表示删掉的是最后一个位置的数据,此时不需要进行resign操作 + heap.set(index, replace); + indexMap.put(replace, index); + resign(replace); + } + } + + public void resign(T obj) { + heapInsert(indexMap.get(obj)); + heapify(indexMap.get(obj)); + } + + // 请返回堆上的所有元素 + public List getAllElements() { + List ans = new ArrayList<>(); + for (T c : heap) { + ans.add(c); + } + return ans; + } + + private void heapInsert(int index) { + while (comp.compare(heap.get(index), heap.get((index - 1) / 2)) < 0) { + swap(index, (index - 1) / 2); + index = (index - 1) / 2; + } + } + + private void heapify(int index) { + int left = index * 2 + 1; + while (left < heapSize) { + int best = left + 1 < heapSize && comp.compare(heap.get(left + 1), heap.get(left)) < 0 ? (left + 1) : left; + best = comp.compare(heap.get(best), heap.get(index)) < 0 ? best : index; + if (best == index) { + break; + } + swap(best, index); + index = best; + left = index * 2 + 1; + } + } + + private void swap(int i, int j) { + T o1 = heap.get(i); + T o2 = heap.get(j); + heap.set(i, o2); + heap.set(j, o1); + indexMap.put(o2, i); + indexMap.put(o1, j); + } +} \ No newline at end of file diff --git a/src/main/java/git/snippet/heap/Code_MaxHeap.java b/src/main/java/git/snippet/heap/Code_MaxHeap.java new file mode 100644 index 0000000000000000000000000000000000000000..ed1985390d9afc0027eb9b852c001cad66ad00a8 --- /dev/null +++ b/src/main/java/git/snippet/heap/Code_MaxHeap.java @@ -0,0 +1,89 @@ +package git.snippet.heap; + +// 笔记:https://www.cnblogs.com/greyzeng/p/16933830.html +// 什么是完全二叉树 如果一个树是满的,它是完全二叉树,即便不是满的,也是从左到右依次变满的 +// 堆结构 +// 1)堆结构就是用数组实现的完全二叉树结构 +// 2)完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 +// 3)完全二叉树中如果每棵子树的最小值都在顶部就是小根堆 +// 4)堆结构的heapInsert与heapify操作 +// 5)堆结构的增大和减少 +// 6)Java中的PriorityQueue,就是堆结构 +// 用数组表示堆的两种情况 +// 第一种情况:如果使用数组0位置,对于i位置来说,它的: +// 左孩子 2 * i + 1 +// 右孩子 2 * i + 2 +// 父节点 (i - 1)/ 2 +// 第二种情况:如果不用0位置,对于i位置来说,它的: +// 左孩子 2 * i 即:i << 1 +// 右孩子 2 * i + 1 即:i << 1 | 1 +// 父节点 i / 2 即:i >> 1 +// 大根堆:完全二叉树中,每棵树的最大值都是头节点的值 +// heapify和heapInsert都是logN级别的复杂度,因为N个节点的二叉树高度是logN +public class Code_MaxHeap { + private final int[] heap; + // private final int limit; limit == heap.length + private int heapSize; + + public Code_MaxHeap(int limit) { + heap = new int[limit]; + // this.limit = limit; + heapSize = 0; + } + + public void push(int value) { + if (!isFull()) { + heap[heapSize] = value; + // value heapSize + heapInsert(); + heapSize++; + } + } + + public int pop() { + int ans = heap[0]; + swap(heap, 0, --heapSize); + heapify(); + return ans; + } + + private void heapInsert() { + int i = heapSize; + while (heap[i] > heap[(i - 1) / 2]) { + swap(heap, i, (i - 1) / 2); + i = (i - 1) / 2; + } + } + + private void heapify() { + int index = 0; + int left = index * 2 + 1; + while (left < heapSize) { + int largest // bigger index + = left + 1 < heapSize // right child exist + && heap[left + 1] > heap[left] // compare left child and right child + ? left + 1 : left; + largest = heap[largest] > heap[index] ? largest : index; + if (largest == index) { + break; + } + swap(heap, largest, index); + index = largest; + left = index * 2 + 1; + } + } + + public boolean isEmpty() { + return heapSize == 0; + } + + public boolean isFull() { + return heapSize == heap.length; + } + + private void swap(int[] arr, int i, int j) { + int tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } +} diff --git a/src/test/java/git/snippet/heap/Code_HeapGreaterTest.java b/src/test/java/git/snippet/heap/Code_HeapGreaterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b8f54bada2b4c3e799c2c231eca955949cbc8fa9 --- /dev/null +++ b/src/test/java/git/snippet/heap/Code_HeapGreaterTest.java @@ -0,0 +1,49 @@ +package git.snippet.heap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("加强堆结构测试") +public class Code_HeapGreaterTest { + + + // 加强堆测试 + @Test + @DisplayName("加强堆结构测试") + public void testGreaterHeap() { + int value = 1000; + int limit = 100; + int testTimes = 1000000; + for (int i = 0; i < testTimes; i++) { + int curLimit = (int) (Math.random() * limit) + 1; + Code_HeapGreater my = + new Code_HeapGreater<>( + (o1, o2) -> o2 - o1); + RightMaxHeap test = new RightMaxHeap(curLimit); + int curOpTimes = (int) (Math.random() * limit); + for (int j = 0; j < curOpTimes; j++) { + if (test.isEmpty()) { + int curValue = (int) (Math.random() * value); + my.push(curValue); + test.push(curValue); + } else if (test.isFull()) { + if (my.pop() != test.pop()) { + Assertions.fail(); + } + } else { + if (Math.random() < 0.5) { + int curValue = (int) (Math.random() * value); + my.push(curValue); + test.push(curValue); + } else { + if (my.pop() != test.pop()) { + Assertions.fail(); + } + } + } + } + } + } + +} \ No newline at end of file diff --git a/src/test/java/git/snippet/heap/Code_HeapTest.java b/src/test/java/git/snippet/heap/Code_HeapTest.java index 8d831f42b068d1896e56d9a98c6226b2b9e069a5..8424c5445760e280c08b5bb4df453abe159c622f 100644 --- a/src/test/java/git/snippet/heap/Code_HeapTest.java +++ b/src/test/java/git/snippet/heap/Code_HeapTest.java @@ -7,15 +7,14 @@ import org.junit.jupiter.api.Test; @DisplayName("堆结构测试") public class Code_HeapTest { @Test - @DisplayName("堆结构测试") public void testHeap() { int value = 1000; int limit = 100; int testTimes = 1000000; for (int i = 0; i < testTimes; i++) { int curLimit = (int) (Math.random() * limit) + 1; - Code_Heap.MaxHeap my = new Code_Heap.MaxHeap(curLimit); - Code_Heap.RightMaxHeap test = new Code_Heap.RightMaxHeap(curLimit); + Code_MaxHeap my = new Code_MaxHeap(curLimit); + RightMaxHeap test = new RightMaxHeap(curLimit); int curOpTimes = (int) (Math.random() * limit); for (int j = 0; j < curOpTimes; j++) { if (my.isEmpty() != test.isEmpty()) { @@ -47,42 +46,5 @@ public class Code_HeapTest { } } - // 加强堆测试 - @Test - @DisplayName("加强堆结构测试") - public void testGreaterHeap() { - int value = 1000; - int limit = 100; - int testTimes = 1000000; - for (int i = 0; i < testTimes; i++) { - int curLimit = (int) (Math.random() * limit) + 1; - Code_Heap.HeapGreater my = - new Code_Heap.HeapGreater<>( - (o1, o2) -> o2 - o1); - Code_Heap.RightMaxHeap test = new Code_Heap.RightMaxHeap(curLimit); - int curOpTimes = (int) (Math.random() * limit); - for (int j = 0; j < curOpTimes; j++) { - if (test.isEmpty()) { - int curValue = (int) (Math.random() * value); - my.push(curValue); - test.push(curValue); - } else if (test.isFull()) { - if (my.pop() != test.pop()) { - Assertions.fail(); - } - } else { - if (Math.random() < 0.5) { - int curValue = (int) (Math.random() * value); - my.push(curValue); - test.push(curValue); - } else { - if (my.pop() != test.pop()) { - Assertions.fail(); - } - } - } - } - } - } } \ No newline at end of file diff --git a/src/test/java/git/snippet/heap/RightMaxHeap.java b/src/test/java/git/snippet/heap/RightMaxHeap.java new file mode 100644 index 0000000000000000000000000000000000000000..0494d1064cd9e181168dcf6659a7732d1094c1f5 --- /dev/null +++ b/src/test/java/git/snippet/heap/RightMaxHeap.java @@ -0,0 +1,40 @@ +package git.snippet.heap; + +public class RightMaxHeap { + private final int limit; + private int[] arr; + private int size; + + public RightMaxHeap(int limit) { + arr = new int[limit]; + this.limit = limit; + size = 0; + } + + public boolean isEmpty() { + return size == 0; + } + + public boolean isFull() { + return size == limit; + } + + public void push(int value) { + if (size == limit) { + throw new RuntimeException("heap is full"); + } + arr[size++] = value; + } + + public int pop() { + int maxIndex = 0; + for (int i = 1; i < size; i++) { + if (arr[i] > arr[maxIndex]) { + maxIndex = i; + } + } + int ans = arr[maxIndex]; + arr[maxIndex] = arr[--size]; + return ans; + } +}