最大堆:每一个结点都比其子结点大的二叉树。
堆排序思想:把所有数据建成一个最大堆,不停的把堆顶的元素取出来依次排列,取一个数之后,剩下的数要维持最大堆结构
那么堆排序主要分为
- 建成最大堆
- 维持堆结构
建最大堆 :时间复杂度为O(n)
注意:在使用数组表示的堆结构中,结点arr[index]的父结点为arr[(index - 1) / 2].
建堆思想: 把数组中的每一个数遍历一次,如果它比父结点要大就与父结点交换,知道它小于等于父结点
//arr:所有数据所在数组 index:当前处理的数下标
//因为(0 - 1) / 2 = 0所以不会越界
void buildHeap(int arr[], int index) {
while (arr[index] > arr[(index - 1) / 2]) {
swap(arr[index], arr[(index - 1) / 2]);
index = (index - 1) / 2;
}
}
维持堆的结构:时间复杂度log(n),每一次维持堆为log(n)
注意:一个结点arr[index]的左孩子为arr[index * 2 + 1],右孩子为arr[index * 2 + 2]
维持堆结构思想:从arr[0]开始,选取它和它的左右孩子中最大的那个,如果最大的是自己,不是左右孩子,结束;如果最大的是左右孩子中的一个,将其与父结点交换位置;重复上述过程。
代码如下:
//curIndex:当前处理的数的下标 heapSize:目前堆的大小
//leftChild: 当前数的左孩子
//largestIndex:当前数与其左右孩子中最大的数的下标
void heapify(int arr[], int curIndex, int heapSize) {
int leftChild = curIndex * 2 + 1;
int largestIndex;
while (leftChild < heapSize) {
largestIndex = leftChild + 1 < heapSize && arr[leftChild] < arr[leftChild + 1]
? leftChild + 1 : leftChild;
largestIndex = arr[largestIndex] > arr[curIndex] ? largestIndex : curIndex;
if (curIndex == largestIndex){
break;
}
swap(arr[largestIndex], arr[curIndex]);
curIndex = largestIndex;
leftChild = curIndex * 2 + 1;
}
}
堆排序主函数如下
void heapSort(int arr[], int heapSize) {
if (heapSize < 2) return;
//建立最大堆
for (int i = 0; i < heapSize; i++) {
buildHeap(arr,i);
}
swap(arr[0], arr[--heapSize]);
while (heapSize){
heapify(arr, 0, heapSize);
swap(arr[0], arr[--heapSize]);
}
}