堆是一种数据结构,注意不是二叉树,是数组结构,但是处理堆时可以看成完全二叉树,分为大根堆和小根堆。
一:首先初始化堆,保证每个root左右孩子的值均不大于它,且该点需对每个子树的root成立
//我这里是调整为大根堆
void init(vector<int>&v) {
for (int i = v.size() - 1; i > 0; i--) {
if (v[i] > v[(i - 1) / 2]) { //完全二叉树性质,若孩子结点大于父节点 交换
int j = i;
while (j>=0&&v[j] > v[(j - 1) / 2]) {
swap2(v, j, (j - 1) / 2);
j = (j - 1) / 2;
}
}
}
}
二:调整堆,由于是大根堆,根节点的值最大,应该出堆,出堆方法就是让其到此时堆的最后一个位置,最后一个位置来到堆顶。由于此时堆结构的性质被破坏,需要重新调整堆。
void heapify(vector<int>&v,int cur_size) {
int i = 0;
while ((2*i+1)<cur_size) {
int large = (2 * i + 2) < cur_size&&v[2 * i + 2] > v[2 * i + 1] ?( 2 * i + 2) : (2 * i + 1);
if (v[large] > v[i])
swap2(v, i, large);
i = large;
}
}
三:完整堆排序
void heapSort(vector<int>&v) {
init(v);
int cur_size = v.size();
while (cur_size) {
cout << v[0];
swap2(v,0,cur_size-1);
cur_size--;
heapify(v, cur_size);
}
}
//JAVA 代码
public class HeapSort {
public static void main(String[] args) {
int[] arr = {1,2,0,10,3,1,4,1};
heapSort(arr);
for (int i : arr) {
System.out.println(i);
}
}
private static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
initHeap(arr);
heapify(arr, arr.length);
}
//初始化成大根堆
private static void initHeap(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = arr.length - 1; i > 0; i--) {
int parentIndex = (i - 1) >> 1;
//比父节点大就交换
if (arr[parentIndex] < arr[i]) {
swap(arr, i, parentIndex);
//交换之后当前结点可能需要下沉
down(arr, i, arr.length);
}
}
}
private static void heapify(int[] arr, int curLen) {
if (curLen < 2) {
return;
}
int i = 0;
//当前结点下沉
down(arr, i, curLen);
//当前根节点val为最大,和末节点交换,再递归
swap(arr, 0, curLen - 1);
heapify(arr, curLen - 1);
}
//下沉当前节点
private static void down(int[] arr, int j, int curLen) {
while (j <= (curLen - 2) >> 1) {
int maxLoc = getMaxIndexInChildren(arr, j, curLen);
if (arr[j] >= arr[maxLoc]) {
break;
}
swap(arr, j, maxLoc);
j = maxLoc;
}
}
//得到孩子结点中较大的那个的index
private static int getMaxIndexInChildren(int[] arr, int i, int curLen) {
int leftNum = arr[2 * i + 1];
if (2 * i + 2 < curLen) {
int rightNum = arr[2 * i + 2];
return leftNum > rightNum ? 2 * i + 1 : 2 * i + 2;
} else {
return 2 * i + 1;
}
}
}