堆排序
一、基本概念
1、堆排序是一种利用堆这一数据结构来排序的排序算法。堆近似于完全二叉树、有着完全二叉树的性质。
补充
大根堆(大顶堆)与小根堆(小顶堆)介绍
大根堆:任意根值都要大于等于其左右孩子值的堆(完全二叉树)
小根堆:任意根值都要小于等于其左右孩子值的堆
二、基本算法思想
1、先将数组建成一个大根堆(排升序建大根堆,排降序建小根堆),此时堆顶元素是最大值元素。
2、将堆顶元素与数组最后一个元素交换,则最大值已就位(只需把n-1个元素重新调整建堆,已就位的最大值无需参与建堆)。
3、用向下调整算法调整堆(元素交换后已不是大根堆,需要重新调整成大根堆)。
4、再将堆顶元素与数组倒数第二个元素交换,则次大值已就位。再调整堆。。。。
5、依次类推。。。。
思考
1、向下调整算法怎样实现呢?(怎样去把一个堆调整成大根堆呢)
2、我们要怎样去建立一个大根堆呢?
三、算法实现
实现向下调整算法
1、基本介绍
通过从上到下的算法排序,将一个堆变成大根堆或者小根堆。
注意此堆(完全二叉树)的左边堆(根节点的左子树)和右边堆(根节点的右子树)一定要是大根堆(或者小根堆)才行。
2、演示
3、具体代码
void AdjustHeap(int* arr, int n, int root) {
int parent = root;
int child = parent * 2 + 1;
while (child < n) {//当左右孩子都不存在时跳出
if (child+1 < n && arr[child] < arr[child + 1]) {//注意有可能右孩子不存在
child += 1;
}
if (arr[child] > arr[parent]) {
Swap(&arr[child], &arr[parent]);//交换两数
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
建大根堆
寻找非叶子节点的第一个根节点
最后一个叶子节点下标为n-1(n为数组元素个数),则其父母节点为(n-2)/2
根据完全二叉树性质得来
//建大根堆
for (int i = (n - 2)/2; i >= 0; i--) {
AdjustHeap(arr, n, i);//向下调整算法
}
四、整合得堆排序
堆排序:
1.建大根堆(排升序)
2.把最后一个元素与堆顶元素交换(此时最大元素已经就位,只需排n-1个元素)
3.向下调整算法调整好堆
4.把倒数第二个元素与堆顶元素交换,调整好堆。。。。。依次类推
void AdjustHeap(int* arr, int n, int root) {
int parent = root;
int child = parent * 2 + 1;
while (child < n) {//当左右孩子都不存在时跳出
if (child+1 < n && arr[child] < arr[child + 1]) {//注意有可能右孩子不存在
child += 1;
}
if (arr[child] > arr[parent]) {
Swap(&arr[child], &arr[parent]);//交换两数
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
void HeapSort(int* arr, int n) {
//建大根堆
for (int i = (n - 2)/2; i >= 0; i--) {
AdjustHeap(arr, n, i);//向下调整算法
}
//最后一个元素与堆顶元素交换(此时最大元素已经就位,只需排n-1个元素)
int end = n-1;
while (end>0) {
Swap(&arr[end], &arr[0]);//交换完大根堆已被破环,需调整
AdjustHeap(arr, end, 0);//调整再次变成大根堆
end--;
}
}
五、时间复杂度计算
堆排序主要有两步:1、把数组建成一个大根堆 2、向下调整算法调整堆
1、建大根堆
该建堆方式是从倒数第二层的节点(叶子节点的上一层)开始,从右向左,从下到上的运用向下调整算法进行调整,而建成的。
当n很大时,可以把完全二叉树近似为满二叉树。考虑到最坏的情况:
第一层的一个节点向下调整了h-1次;
第二层的二个节点都向下调整了h-2次;
第三层的四个节点都向下调整了h-3次;
。。。。
所以时间复杂度t(n)=1*(h-1)+2*(h-2)+…+2^(h-2)*1
用高中的错位相减法得出时间复杂度结果为O(n);
2、向下调整算法调整堆
最多调整完全二叉树高度次。
所以时间复杂度为O(logN);
所以堆排序时间复杂度为O(N*logN)。堆排序是一种很优秀的算法。