堆排序的JAVA实现
网上有很多版本需要buildHeap heapify两个方法,我觉得没必要写成两个方法。
package pri.wdw.algorithm.sort;
import java.util.Arrays;
/**
* <p>@author wdw</p>
* <p>@date 2020/4/20 21:21</p>
* <p>@description </p>
*/
public class HeapSort {
/**
* 堆的定义:
* 完全二叉树的定义:
* 编号为i的节点
* 父节点:(i-1)/2
* 左孩子:(2*i)+1
* 右孩子:(2*i)+2
* 最后一个非叶子节点的编号:假设堆共有n个节点,那么最后一个非叶子节点的编号为n/2 -1
*/
public static void main(String[] args) {
int[] arr = {9, 8, 7, 4, 5, 1, 10, 3, 3, 44, 13, 4421, -2, 4, 321, 2};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* 思想:每次都将数组堆化,获取一个最大堆,然后将堆顶元素与末尾元素进行交换
*/
public static void heapSort(int[] arr) {
int maxHeapSize = arr.length;
for (int i = maxHeapSize; i >= 2; i--) {
heapify(arr, i);
swap(arr, 0, i - 1);
}
}
/**
* 对任意长度数字进行堆化操作(构建大顶堆)
*
* @param arr
* @param heapSize 需要堆化的数组的长度,每次p
*/
private static void heapify(int[] arr, int heapSize) {
//从最后一个非叶子节点开始递归
while (heapSize >= 2) { // 也可以 heapSize / 2 - 1 >= 0即 current >= 0
int current = heapSize / 2 - 1;
//左右两个孩子节点的坐标
int lChild = current * 2 + 1;
int rChild = current * 2 + 2;
//找到 leftChile,rightChild当中比较大的那一个和当前节点进行swap(需要前提保证这两个节点在堆化Size之内)
int maxIndex = current;
if (lChild < heapSize && rChild < heapSize) {
int maxChild = arr[lChild] > arr[rChild] ? lChild : rChild;//先找出两个孩子两个其中大的那个
if (arr[maxChild] > arr[current])
maxIndex = maxChild;
} else if (rChild >= heapSize && lChild < heapSize && arr[lChild] > arr[current]) {
maxIndex = lChild;
} else if (lChild >= heapSize && rChild < heapSize && arr[rChild] > arr[current]) {
maxIndex = rChild;
}
if (maxIndex != current)
swap(arr, current, maxIndex); //交换节点
//根据条件依次找到非叶子节点(堆的元素数为偶数,减去 1)
if (heapSize % 2 == 0)
heapSize -= 1;
else
heapSize -= 2;
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}