堆结构和堆排序
1. 什么是堆 ?
2. 完全二叉树和数组前缀范围的对应
任何节点 i 的父亲节点 = (i - 1) / 2,i 的左孩子 = i * 2 + 1,i 的右孩子 = i * 2 + 2
单独的变量size 来控制堆的大小, i * 2 + 1 < size 有左孩子、i * 2 + 2 < size 有右孩子
3. 向上调整大根堆、 向下调整大根堆
// 向上调整大根堆
public static void heapInsert(int[] arr, int child) {
int parent = (child - 1) / 2;
while (arr[child] > arr[parent]) {
swap(arr,child,parent);
child = parent;
parent = (child - 1) / 2;
}
}
// 向下调整大根堆
// 方法1:
public static void heapify1(int[] arr, int parent, int size) {
int child = parent * 2 + 1;
while (child < size) {
if (child + 1 < size && arr[child + 1] > arr[child]) {
child++;
}
if (arr[child] > arr[parent]) {
swap(arr,child,parent);
parent = child;
child = parent * 2 + 1;
}else {
break;
}
}
}
// 方法2:
public static void heapify2(int[] arr, int p, int size) {
int c = p * 2 + 1;
while (c < size) {
// 有左孩子
// 选左右最大孩子
int best = c + 1 < size && arr[c + 1] > arr[c] ? c + 1: c;
best = arr[best] > arr[p] ? best : p;
if (best == p) {
break;
}
swap(arr,best,p);
p = best;
c = p * 2 + 1;
}
}
public static void swap(int[] arr,int x,int y) {
int tmp = arr[x];
arr[x] = arr[y];
arr[y] = tmp;
}
4. 怎么把一颗完全二叉树改成 大/小根堆 ?
方法1: 向下调整建堆
方法2: 向上调整建堆
public static void createBigHeap(int[] arr) {
// 向上调整建堆
/*
for (int i = 0;i < arr.length;i++) {
heapInsert(arr,i);
} */
// 从最后一颗子树开始 向下调整建堆
int parent = (arr.length - 1 - 1) / 2;
for (int i = parent;i >= 0;i--) {
heapify2(arr,i,arr.length);
}
}
5. 堆的删除与插入
public int poll() {
int tmp = elem[0];
Swap(0,usedSize-1);
usedSize--;
siftDown(0,usedSize);
return tmp;
}
堆的插入:
public void offer(int data) {
if (elem.length == usedSize) {
this.elem = Arrays.copyOf(elem,elem.length*2);
}
elem[usedSize++] = data;
siftUp(usedSize-1);
}
大根堆排升序 小跟堆排降序
class Solution {
// 向上调整大根堆
public static void heapInsert(int[] arr, int child) {
int parent = (child - 1) / 2;
while (arr[child] > arr[parent]) {
swap(arr,child,parent);
child = parent;
parent = (child - 1) / 2;
}
}
// 向下调整大根堆
public static void heapify1(int[] arr, int parent, int size) {
int child = parent * 2 + 1;
while (child < size) {
if (child + 1 < size && arr[child + 1] > arr[child]) {
child++;
}
if (arr[child] > arr[parent]) {
swap(arr,child,parent);
parent = child;
child = parent * 2 + 1;
}else {
break;
}
}
}
public static void heapify2(int[] arr, int p, int size) {
int c = p * 2 + 1;
while (c < size) {
// 有左孩子
// 选左右最大孩子
int best = c + 1 < size && arr[c + 1] > arr[c] ? c + 1: c;
best = arr[best] > arr[p] ? best : p;
if (best == p) {
break;
}
swap(arr,best,p);
p = best;
c = p * 2 + 1;
}
}
public static void createBigHeap(int[] arr) {
// 向上调整建堆
/*
for (int i = 0;i < arr.length;i++) {
heapInsert(arr,i);
} */
// 向下调整建堆
int parent = (arr.length - 1 - 1) / 2;
for (int i = parent;i >= 0;i--) {
heapify2(arr,i,arr.length);
}
}
public static void swap(int[] arr,int x,int y) {
int tmp = arr[x];
arr[x] = arr[y];
arr[y] = tmp;
}
// 堆排序
public static void heapSort(int[] arr) {
createBigHeap(arr);
int n = arr.length;
while (n > 1) {
swap(arr,0,--n);
heapify1(arr,0,n);
}
}
public static int[] sortArray(int[] nums) {
if (nums.length > 1) {
heapSort(nums);
}
return nums;
}
public static void main(String[] args) {
int[] arr = {3,1,5,2,7};
sortArray(arr);
}
}