Skip to content

Commit

Permalink
Merge pull request krahets#241 from krahets/heap-dev
Browse files Browse the repository at this point in the history
Add the chapter of Heap
  • Loading branch information
krahets authored Jan 11, 2023
2 parents 274d6a5 + d0e5406 commit 56134d1
Show file tree
Hide file tree
Showing 33 changed files with 639 additions and 45 deletions.
1 change: 1 addition & 0 deletions codes/java/chapter_hashing/array_hash_map.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

package chapter_hashing;

import java.util.*;

/* 键值对 int->String */
Expand Down
1 change: 1 addition & 0 deletions codes/java/chapter_hashing/hash_map.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

package chapter_hashing;

import java.util.*;
import include.*;

Expand Down
67 changes: 67 additions & 0 deletions codes/java/chapter_heap/heap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* File: my_heap.java
* Created Time: 2023-01-07
* Author: Krahets ([email protected])
*/

package chapter_heap;

import include.*;
import java.util.*;


public class heap {
public static void testPush(Queue<Integer> heap, int val) {
heap.add(val); // 元素入堆
System.out.format("\n元素 %d 入堆后\n", val);
PrintUtil.printHeap(heap);
}

public static void testPoll(Queue<Integer> heap) {
int val = heap.poll(); // 堆顶元素出堆
System.out.format("\n堆顶元素 %d 出堆后\n", val);
PrintUtil.printHeap(heap);
}

public static void main(String[] args) {
/* 初始化堆 */
// 初始化小顶堆
Queue<Integer> minHeap = new PriorityQueue<>();
// 初始化大顶堆(使用 lambda 表达式修改 Comparator 即可)
Queue<Integer> maxHeap = new PriorityQueue<>((a, b) -> { return b - a; });

System.out.println("\n以下测试样例为大顶堆");

/* 元素入堆 */
testPush(maxHeap, 1);
testPush(maxHeap, 3);
testPush(maxHeap, 2);
testPush(maxHeap, 5);
testPush(maxHeap, 4);

/* 获取堆顶元素 */
int peek = maxHeap.peek();
System.out.format("\n堆顶元素为 %d\n", peek);

/* 堆顶元素出堆 */
testPoll(maxHeap);
testPoll(maxHeap);
testPoll(maxHeap);
testPoll(maxHeap);
testPoll(maxHeap);

/* 获取堆大小 */
int size = maxHeap.size();
System.out.format("\n堆元素数量为 %d\n", size);

/* 判断堆是否为空 */
boolean isEmpty = maxHeap.isEmpty();
System.out.format("\n堆是否为空 %b\n", isEmpty);

/* 输入列表并建堆 */
// 时间复杂度为 O(n) ,而非 O(nlogn)
minHeap = new PriorityQueue<>(Arrays.asList(1, 3, 2, 5, 4));
System.out.println("\n输入列表并建立小顶堆后");
PrintUtil.printHeap(minHeap);
}
}
177 changes: 177 additions & 0 deletions codes/java/chapter_heap/my_heap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/**
* File: my_heap.java
* Created Time: 2023-01-07
* Author: Krahets ([email protected])
*/

package chapter_heap;

import include.*;
import java.util.*;

class MaxHeap {
// 使用列表而非数组,这样无需考虑扩容问题
private List<Integer> maxHeap;

/* 构造函数,建立空堆 */
public MaxHeap() {
maxHeap = new ArrayList<>();
}

/* 构造函数,根据输入列表建堆 */
public MaxHeap(List<Integer> nums) {
// 所有元素入堆
maxHeap = new ArrayList<>(nums);
// 堆化除叶结点以外的其他所有结点
for (int i = parent(size() - 1); i >= 0; i--) {
siftDown(i);
}
}

/* 获取左子结点索引 */
private int left(int i) {
return 2 * i + 1;
}

/* 获取右子结点索引 */
private int right(int i) {
return 2 * i + 2;
}

/* 获取父结点索引 */
private int parent(int i) {
return (i - 1) / 2; // 向下整除
}

/* 交换元素 */
private void swap(int i, int j) {
int a = maxHeap.get(i),
b = maxHeap.get(j),
tmp = a;
maxHeap.set(i, b);
maxHeap.set(j, tmp);
}

/* 获取堆大小 */
public int size() {
return maxHeap.size();
}

/* 判断堆是否为空 */
public boolean isEmpty() {
return size() == 0;
}

/* 访问堆顶元素 */
public int peek() {
return maxHeap.get(0);
}

/* 元素入堆 */
public void push(int val) {
// 添加结点
maxHeap.add(val);
// 从底至顶堆化
siftUp(size() - 1);
}

/* 从结点 i 开始,从底至顶堆化 */
private void siftUp(int i) {
while (true) {
// 获取结点 i 的父结点
int p = parent(i);
// 当“越过根结点”或“结点无需修复”时,结束堆化
if (p < 0 || maxHeap.get(i) <= maxHeap.get(p))
break;
// 交换两结点
swap(i, p);
// 循环向上堆化
i = p;
}
}

/* 元素出堆 */
public int poll() {
// 判空处理
if (isEmpty())
throw new EmptyStackException();
// 交换根结点与最右叶结点(即交换首元素与尾元素)
swap(0, size() - 1);
// 删除结点
int val = maxHeap.remove(size() - 1);
// 从顶至底堆化
siftDown(0);
// 返回堆顶元素
return val;
}

/* 从结点 i 开始,从顶至底堆化 */
private void siftDown(int i) {
while (true) {
// 判断结点 i, l, r 中值最大的结点,记为 ma
int l = left(i), r = right(i), ma = i;
if (l < size() && maxHeap.get(l) > maxHeap.get(ma))
ma = l;
if (r < size() && maxHeap.get(r) > maxHeap.get(ma))
ma = r;
// 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i) break;
// 交换两结点
swap(i, ma);
// 循环向下堆化
i = ma;
}
}

/* 打印堆(二叉树) */
public void print() {
Queue<Integer> queue = new PriorityQueue<>((a, b) -> { return b - a; });
queue.addAll(maxHeap);
PrintUtil.printHeap(queue);
}
}


public class my_heap {
public static void testPush(MaxHeap maxHeap, int val) {
maxHeap.push(val); // 元素入堆
System.out.format("\n添加元素 %d 后\n", val);
maxHeap.print();
}

public static void testPoll(MaxHeap maxHeap) {
int val = maxHeap.poll(); // 堆顶元素出堆
System.out.format("\n出堆元素为 %d\n", val);
maxHeap.print();
}

public static void main(String[] args) {
/* 初始化大顶堆 */
MaxHeap maxHeap = new MaxHeap(Arrays.asList(9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2));
System.out.println("\n输入列表并建堆后");
maxHeap.print();

/* 获取堆顶元素 */
int peek = maxHeap.peek();
System.out.format("\n堆顶元素为 %d\n", peek);

/* 元素入堆 */
int val = 7;
maxHeap.push(val);
System.out.format("\n元素 %d 入堆后\n", val);
maxHeap.print();

/* 堆顶元素出堆 */
peek = maxHeap.poll();
System.out.format("\n堆顶元素 %d 出堆后\n", peek);
maxHeap.print();

/* 获取堆大小 */
int size = maxHeap.size();
System.out.format("\n堆元素数量为 %d\n", size);

/* 判断堆是否为空 */
boolean isEmpty = maxHeap.isEmpty();
System.out.format("\n堆是否为空 %b\n", isEmpty);
}
}
2 changes: 1 addition & 1 deletion codes/java/chapter_tree/binary_tree_bfs.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ static List<Integer> hierOrder(TreeNode root) {
public static void main(String[] args) {
/* 初始化二叉树 */
// 这里借助了一个从数组直接生成二叉树的函数
TreeNode root = TreeNode.arrToTree(new Integer[] { 1, 2, 3, 4, 5, 6, 7 });
TreeNode root = TreeNode.listToTree(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
System.out.println("\n初始化二叉树\n");
PrintUtil.printTree(root);

Expand Down
2 changes: 1 addition & 1 deletion codes/java/chapter_tree/binary_tree_dfs.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ static void postOrder(TreeNode root) {
public static void main(String[] args) {
/* 初始化二叉树 */
// 这里借助了一个从数组直接生成二叉树的函数
TreeNode root = TreeNode.arrToTree(new Integer[] { 1, 2, 3, 4, 5, 6, 7 });
TreeNode root = TreeNode.listToTree(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
System.out.println("\n初始化二叉树\n");
PrintUtil.printTree(root);

Expand Down
14 changes: 10 additions & 4 deletions codes/java/include/PrintUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,16 @@ public static <K, V> void printHashMap(Map<K, V> map) {
}
}

public static void printHeap(PriorityQueue<Integer> queue) {
Integer[] nums = (Integer[])queue.toArray();
TreeNode root = TreeNode.arrToTree(nums);

/**
* Print a heap (PriorityQueue)
* @param queue
*/
public static void printHeap(Queue<Integer> queue) {
List<Integer> list = new ArrayList<>(queue);
System.out.print("堆的数组表示:");
System.out.println(list);
System.out.println("堆的树状表示:");
TreeNode root = TreeNode.listToTree(list);
printTree(root);
}
}
21 changes: 11 additions & 10 deletions codes/java/include/TreeNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,27 @@ public TreeNode(int x) {

/**
* Generate a binary tree given an array
* @param arr
* @param list
* @return
*/
public static TreeNode arrToTree(Integer[] arr) {
if (arr.length == 0)
public static TreeNode listToTree(List<Integer> list) {
int size = list.size();
if (size == 0)
return null;

TreeNode root = new TreeNode(arr[0]);
TreeNode root = new TreeNode(list.get(0));
Queue<TreeNode> queue = new LinkedList<>() {{ add(root); }};
int i = 0;
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
if (++i >= arr.length) break;
if(arr[i] != null) {
node.left = new TreeNode(arr[i]);
if (++i >= size) break;
if (list.get(i) != null) {
node.left = new TreeNode(list.get(i));
queue.add(node.left);
}
if (++i >= arr.length) break;
if(arr[i] != null) {
node.right = new TreeNode(arr[i]);
if (++i >= size) break;
if (list.get(i) != null) {
node.right = new TreeNode(list.get(i));
queue.add(node.right);
}
}
Expand Down
Binary file added docs/chapter_heap/heap.assets/heap_poll_step1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_poll_step3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_poll_step4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_poll_step5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_poll_step6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_poll_step7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_poll_step8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_poll_step9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_push_step1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_push_step2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_push_step3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_push_step4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_push_step5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heap_push_step6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter_heap/heap.assets/heapify_count.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 56134d1

Please sign in to comment.