Heap Sort
时间复杂度O(nlogn)
最好情况O(nlogn)
最坏情况O(nlogn)
空间复杂度O(1)
In-place
要想理解堆排序,首先需要理解堆这种数据结构。
堆(Heap)是一种特殊的完全二叉树,分为大顶堆和小顶堆,大顶堆中除叶子结点外的每个节点的子节点都小于其父节点,大顶堆中除叶子结点外的每个节点的子节点都大于于其父节点。
我们可以从中得到一个规律,假设数组arr长度为length,其编号中最后一个拥有子节点为叶子结点的编号为 length//2-1。以上图为例,数组长度为9, 最后一个拥有子节点为叶子结点的编号为9//2-1 = 4-1 = 3。该节点的左右子节点编号(若存在)为3*2+1 = 7和3*2+2 = 8。
推排序基本思想,类似于选择排序,每次选择一个最大的数放在他应该在的位置上,由于堆拥有树的性质,意味着每个堆的叶子节点不需要参与搜索,所以比选择排序更快。
其基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
Java:
public class HeapSort {
public HeapSort(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
MakeHeap(arr,arr.length-i);
}
}
public static void MakeHeap(int[] arr,int length){
int root = length/2-1;
while (root>=0){
if(root*2+2<=length-1){
if(arr[root]<arr[root*2+2]){
Switch(arr,root,root*2+2);
}
if(arr[root]<arr[root*2+1]){
Switch(arr,root,root*2+1);
}
}
if(root*2+1<=length-1){
if(arr[root]<arr[root*2+1]){
Switch(arr,root,root*2+1);
}
}
root--;
}
Switch(arr,root+1,length-1);
}
public static void Switch(int[]arr,int a, int b){
int tem;
tem = arr[a];
arr[a] = arr[b];
arr[b] = tem;
}
}
Python:
def HeapSort(num_list):
for i in range(len(num_list) - 1):
MakeHeap(num_list, len(num_list) - i)
def MakeHeap(num_list, length):
root = length // 2 - 1
while root >= 0:
if root * 2 + 2 <= length - 1:
if num_list[root] < num_list[root * 2 + 2]:
num_list[root], num_list[root * 2 + 2] = num_list[root * 2 + 2], num_list[root]
if num_list[root] < num_list[root * 2 + 1]:
num_list[root], num_list[root * 2 + 1] = num_list[root * 2 + 1], num_list[root]
if root * 2 + 1 <= length - 1:
if num_list[root] < num_list[root * 2 + 1]:
num_list[root], num_list[root * 2 + 1] = num_list[root * 2 + 1], num_list[root]
root -= 1
num_list[root + 1], num_list[length - 1] = num_list[length - 1], num_list[root + 1]
def main():
num_list = [10, 9, 56, 19, 28, 37, 34]
num_list2 = [5, 4, 3, 1, 2]
HeapSort(num_list)
print(num_list)