Skip to content

Commit cb9b6ad

Browse files
committed
最小堆及其相关算法(堆排序)的实现
1 parent c526ad7 commit cb9b6ad

2 files changed

Lines changed: 188 additions & 0 deletions

File tree

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package cn.edu.tju.rico.heap;
2+
3+
/**
4+
* Title: 最小堆 :完全二叉树,能方便地从中取出最小/大元素
5+
* Description:
6+
* 堆的构建
7+
* 堆的打印(前序遍历的应用)
8+
* 堆的插入(插入到堆尾,再自下向上调整为最小堆)
9+
* 堆的删除(删除堆顶元素并用堆尾元素添补,再自上向下调整为最小堆)
10+
* 堆排序(时间复杂度:O(nlgn),空间复杂度O(1),不稳定):升序排序一般用最大堆
11+
* @author rico
12+
* @created 2017年5月24日 下午9:23:22
13+
*/
14+
public class MinHeap {
15+
16+
private int[] heap; // 将所有元素以完全二叉树的形式存入数组
17+
private int size; // 堆中元素的个数
18+
19+
/**
20+
* 构造函数
21+
*
22+
* @description 构建一个大小为size的最小堆
23+
* @author rico
24+
* @created 2017年5月24日 下午8:19:46
25+
* @param size
26+
*/
27+
public MinHeap(int maxSize) {
28+
heap = new int[maxSize];
29+
}
30+
31+
/**
32+
* 构造函数
33+
*
34+
* @description 基于数组构造最小堆
35+
* @author rico
36+
* @created 2017年5月24日 下午8:18:56
37+
* @param arr
38+
*/
39+
public MinHeap(int[] arr, int maxSize) {
40+
heap = new int[maxSize > arr.length ? maxSize : arr.length];
41+
System.arraycopy(arr, 0, heap, 0, arr.length);
42+
size = arr.length;
43+
44+
int pos = (size - 2) / 2; // 最初调整位置:最后的分支节点(最后叶节点的父亲)
45+
while (pos >= 0) { //依次调整每个分支节点
46+
shiftDown(pos, size - 1);
47+
pos--;
48+
}
49+
}
50+
51+
/**
52+
* @description 自上向下调整为最小堆(从不是最小堆调整为最小堆),调整的前提是其左子树与右子树均为最小堆
53+
* @author rico
54+
* @created 2017年5月24日 下午7:52:39
55+
* @param start
56+
* @param end
57+
*/
58+
private void shiftDown(int start, int end) {
59+
int i = start; // 起始调整位置,分支节点
60+
int j = 2 * start + 1; // 该分支节点的子节点
61+
int temp = heap[i];
62+
while (j <= end) { // 迭代条件:子节点不能超出end(范围)
63+
if (j < end) {
64+
j = heap[j] > heap[j + 1] ? j + 1 : j; // 选择两孩子中较小的那个
65+
}
66+
if (temp < heap[j]) { // 较小的孩子大于父亲,不做任何处理
67+
break;
68+
} else { // 否则,替换父节点的值
69+
heap[i] = heap[j];
70+
i = j;
71+
j = 2 * j + 1;
72+
}
73+
}
74+
heap[i] = temp; // 一步到位
75+
}
76+
77+
/**
78+
* @description 自下向上调整为最小堆(原来已是最小堆,添加元素后,确保其还是最小堆)
79+
* @author rico
80+
* @created 2017年5月24日 下午9:09:37
81+
* @param start
82+
*/
83+
private void shiftUp(int start) {
84+
int j = start;
85+
int i = (j - 1) / 2; // 起始调整位置,分支节点
86+
int temp = heap[j];
87+
while (j > 0) { // 迭代条件:子节点必须不为根
88+
if (temp >= heap[i]) { //原已是最小堆,所以只需比较这个子女与父亲的关系即可
89+
break;
90+
} else {
91+
heap[j] = heap[i];
92+
j = i;
93+
i = (j - 1) / 2;
94+
}
95+
}
96+
heap[j] = temp; // 一步到位
97+
}
98+
99+
/**
100+
* @description 向最小堆插入元素(总是插入到最小堆的最后)
101+
* @author rico
102+
* @created 2017年5月24日 下午8:22:58
103+
* @param data
104+
*/
105+
public void insert(int data){
106+
if (size < heap.length) {
107+
heap[size++] = data; // 插入堆尾
108+
shiftUp(size-1); // 自下而上调整
109+
}
110+
}
111+
112+
113+
/**
114+
* @description 删除堆顶元素,以堆的最后一个元素填充
115+
* @author rico
116+
* @created 2017年5月24日 下午9:11:46
117+
*/
118+
public void remove() {
119+
if (size > 0) {
120+
heap[0] = heap[size-1]; // 删除堆顶元素,并将堆尾元素回填到堆顶
121+
size --; // 堆大小减一
122+
shiftDown(0, size-1); // 自上向下调整为最小堆
123+
}
124+
}
125+
126+
127+
/**
128+
* @description 堆排序:每次将最小元素交换到最后
129+
* @author rico
130+
* @created 2017年5月24日 下午9:42:31
131+
*/
132+
public void sort(){
133+
for (int i = size - 1; i >= 0; i--) {
134+
int temp = heap[0];
135+
heap[0] = heap[i];
136+
heap[i] = temp;
137+
138+
shiftDown(0, i-1);
139+
}
140+
141+
for (int i = size-1; i >= 0; i--) {
142+
System.out.print(heap[i] + " ");
143+
}
144+
}
145+
146+
/**
147+
* @description 打印根为 i 的最小堆
148+
* @author rico
149+
* @created 2017年5月24日 下午8:17:16
150+
* @param i
151+
*/
152+
public void printMinHeap(int i) {
153+
if (size > i) {
154+
System.out.print(heap[i]);
155+
if (2 * i + 1 < size || 2 * i + 2 < size) {
156+
System.out.print("(");
157+
printMinHeap(2 * i + 1);
158+
System.out.print(",");
159+
printMinHeap(2 * i + 2);
160+
System.out.print(")");
161+
}
162+
}
163+
}
164+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package cn.edu.tju.rico.test;
2+
3+
import cn.edu.tju.rico.heap.MinHeap;
4+
5+
public class MinHeapTest {
6+
public static void main(String[] args) {
7+
8+
int[] arr = {53, 17, 78, 9, 45, 65, 87, 23};
9+
MinHeap heap = new MinHeap(arr,20);
10+
System.out.println("堆:");
11+
heap.printMinHeap(0);
12+
System.out.println("\n---------------------------\n");
13+
System.out.println("向堆中插入元素7后,堆变为:");
14+
heap.insert(7);
15+
heap.printMinHeap(0);
16+
System.out.println("\n---------------------------\n");
17+
System.out.println("删除堆中末尾元素,堆变为:");
18+
heap.remove();
19+
heap.printMinHeap(0);
20+
System.out.println("\n---------------------------\n");
21+
System.out.println("堆排序结果为:");
22+
heap.sort();
23+
}
24+
}

0 commit comments

Comments
 (0)