- 二叉堆是一种特殊的完全二叉树,只不过它存储在数组中。
(1)大顶堆:每个结点都大于等于它的两个子结点的二叉堆。
(2)大顶堆:每个结点都小于等于它的两个子结点的二叉堆。
- 如果根结点的下标是 0,那么对于某个结点 i:
(1)其左结点下标:2 * i + 1
(2)其右结点的下标:2 * i + 2
(3)其父结点的下标:(i - 1) / 2
- 大顶堆的实现:
(1)swim():如果堆的有序状态因为某个结点变的比它的父结点更大而被打破,那么我们就需要通过交换它和它的父结点来修复堆。交换后,这个节点比它的两个子结点都大(一个是曾经的父结点,另一个比它更小,因为它是曾经父结点的子结点),但这个结点仍然可能比它现在的父结点更大,我们可以一遍遍地用同样的方法恢复秩序。
(2)sink():如果堆的有序状态因为某个结点变的比它的两个子结点或是其中之一更小了而被打破,那么我们就需要通过交换它和它的两个子结点中的较大者来修复堆。交换可能会在子结点处继续打破堆的有序状态,因此我们需要不断地用相同的方式将其修复。
class Heap{
int[] pq;
int n = 0;
public Heap(int maxN){
pq = new int[maxN];
}
public void insert(int e){
pq[n++] = e;
swim(n - 1);
}
public boolean less(int i, int j){
return pq[i] < pq[j];
}
public void exch(int i, int j){
int temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;
}
public void swim(int k){
while(k > 0 && less((k - 1) / 2, k)){
exch((k - 1) / 2, k);
k = (k - 1) / 2;
}
}
public void sink(int k){
while(2 * k + 1 <= n - 1){
int bigger = 2 * k + 1;
if(bigger + 1 < n && less(bigger, bigger + 1)){
bigger++;
}
if(!less(k, bigger)){
break;
}
exch(k, bigger);
k = bigger;
}
}
}
public class HeapSort {
public static void main(String[] args) {
int[] nums = {
3, 7, 8, 3, 4, 2, 9, 1};
heapSort(nums);
System.out.println(Arrays.toString(nums));
}
public static void heapSort(int[] nums){
int n = nums.length;
for(int k = n / 2 - 1; k >= 0; k--){
sink(nums, k, n);
}
while(n > 0){
exch(nums, 0, --n);
sink(nums, 0, n);
}
}
public static void sink(int[] nums, int k, int n){
while(2 * k + 1 <= n - 1){
int bigger = 2 * k + 1;
if(bigger + 1 < n && less(nums, bigger, bigger + 1)){
bigger++;
}
if(!less(nums, k, bigger)){
break;
}
exch(nums, k, bigger);
k = bigger;
}
}
public static boolean less(int[] nums, int i, int j){
return nums[i] < nums[j];
}
public static void exch(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}