相关连接:
参考代码:
public static void heapSort(int[] nums){
int len = nums.length;
//1.建最大堆:从下到上,从左到右
for(int i = len / 2 - 1; i >= 0; i--){
heapify(nums, i, len);
}
//2.每次调整第0个元素和 “最后一个元素” 的位置
for (int i = len - 1; i > 0; i--) {
swap(nums, 0, i);//将第0个元素和 “最后一个元素” 的位置进行交换
heapify(nums, 0, i);//交换后重新从第0个元素开始将剩下的元素调整为最大堆
}
}
public static void heapify(int[] nums, int i, int n){
int l = i * 2 + 1;//左孩子索引
int r = i * 2 + 2;//右孩子索引
int maxIndex = i;
if(l < n && nums[l] > nums[maxIndex])maxIndex = l;
if(r < n && nums[r] > nums[maxIndex])maxIndex = r;
if(maxIndex != i){//说明子节点中有比根节点大的值,要交换
swap(nums, maxIndex, i);//交换
heapify(nums, maxIndex, n);//交换后将以第maxIndex个结点为根节点的结点调整为最大堆
}
}
public static void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
相关说明:
1.随机的数组其实可以当成一个堆,所以直接在数组(堆)上进行操作就行。
2.升序,一般将堆转化为最大堆,降序,一般将堆转化为最小堆。
3.从下到上,从右到左,找到第一个非叶子结点开始进行转化。
4.转化时,如果左右孩子的值都不比结点大,不用调整,跳过,转化下一个结点;否则,将父节点值和子节点值中较大的进行交换,然后将进行交换的子节点重新转化为最大堆,这里注意:重新转化时是从上到下转化,因为此时只有该子节点有可能比他的子节点小,而该子节点的子节点肯定符合最大堆,不用从下到上进行调整。
5.进行最大堆调整时,从第len / 2 - 1个结点从后到前进行调整,一直调整到第0个结点。
6.转化完成后,开始排序:
将根节点的最大元素和第len - 1个元素进行交换,交换后根元素不符合最大堆,而他的子元素符合最大堆,所以从上到下转换为最大堆。注意是对剩下的len - 1个元素进行调整(对应关系)。
从将根节点的最大元素和第len - 2个元素进行交换,交换后根元素不符合最大堆,而他的子元素符合最大堆,所以从上到下转换为最大堆。注意是对剩下的len - 2个元素进行调整(对应关系)。
…
最后只剩下一个索引为0的元素,也为最小的元素,不用进行排序,所以循环len - 1次。
7.索引为i的元素,左孩子索引为2 * i + 1,右孩子索引为2 * i + 2;
8.时空复杂度:建堆O(N);排序O(logN),时间复杂度O(NlogN)