堆排序:
学习网站:https://www.cs.usfca.edu/~galles/visualization/HeapSort.html
//先了解两个概念
// 大顶堆:每个节点的值都大于或者等于它的左右子节点的值。
// 小顶堆:每个节点的值都小于或者等于它的左右子节点的值。
//堆排序的基本思想是:
// 1、将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;
// 2、将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;
// 3、重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。
// 最后,就得到一个有序的序列了
package com.suirui.sort.heapsort;
//先了解两个概念
// 大顶堆:每个节点的值都大于或者等于它的左右子节点的值。
// 小顶堆:每个节点的值都小于或者等于它的左右子节点的值。
import com.suirui.sort.SwapElem;
/**
* Created by zongx on 2020/1/14.
*/
//堆排序的基本思想是:
// 1、将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;
// 2、将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;
// 3、重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。
// 最后,就得到一个有序的序列了。
public class HeapSort {
public void sort(int[] arr) {
//1、构建大顶堆
buildMaxHeap(arr,arr.length);
//2、第一个值现在就是最大的,后面再依次对去除前一个值的数组进行建立堆
// 此时,取第一个值比较困难,我们可以将第一个值与最后一个值交换,然后对length-1长度的数组,再建立最大堆,并再次交换
for (int i = 0; i <= arr.length - 1; i++) {
SwapElem.swap(arr,0,arr.length - 1- i);
buildMaxHeap(arr,arr.length-i-1);
}
}
private void buildMaxHeap(int[] arr,int len) {
//从底部开始构建大顶堆,第一个底部树形结构是中间-1节点与最后两个节点,依次类推,直到整个数组变为大顶堆
int i = len/2-1;//中间节点的选取,必须要能够在*2 +1或+2后包含最后一个数值
for (; i>=0; i--) {
//将以i作为根节点的树形结构,变为大顶堆
buildMaxHeapHelper(arr,i,len);
}
}
private void buildMaxHeapHelper(int[] arr, int i, int len) {
int left = 2 * i + 1;//i节点的左孩子
int right = 2 * i + 2;//i节点的右孩子
int maxIndex = len-1;//孩子节点极值
int largestNode = i;//默认当前i节点值最大,后边会进行最大堆排序
//以i节点,进行最大堆排序
//1、先比较根节点与左孩子的值,将大值节点坐标作为largestNode
if(left <= maxIndex && arr[left] > arr[largestNode]){
largestNode = left;//此处注意不要交换值,因为是取根节点与左右子树的最大值,所以还要比较右孩子
}
//2、比较根节点与左孩子的最大值和右孩子的值,将大值节点坐标作为largestNode
if(right <= maxIndex && arr[right] > arr[largestNode]){
largestNode = right;
}
//3、判断最大值坐标是否还是根节点坐标,如果发生了变化,则交换最大值和根节点坐标的值,然后递归这个值的新堆
if (largestNode != i) {
SwapElem.swap(arr,i,largestNode);
buildMaxHeapHelper(arr,largestNode,len);//已经交换值,所以largestNode的坐标是要再进行排序的堆
}
}
}