/** * 堆排序思路: * 1.拷贝数组 * 2.按i/2位置开始构造大堆或者小堆 * 堆排序交换(从下往上,将大值向下交换) * 3.进行排序,将堆顶与尾标识进行交换 * * 堆排序属于选择排序 */public class HeapSort { public int[] sort(int[] sourceArray) { // 对 arr 进行拷贝,不改变参数内容 int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); // 获取数组的长度 int len = arr.length; // 构造大堆 buildMaxHeap(arr, len); for (int i = len - 1; i > 0; i--) { swap(arr, 0, i);//将堆顶即树根与最后一个值进行交换,即把最大值逐步往后放,来完成排序 len--; heapify(arr, 0, len);//大堆位置交换 } return arr; } /** * 大堆 * b0 * b1 b2 * b3 b4 b5 b6 *b7 b8 b9 * * 左孩子节点下标i = 父节点下标z*2+1 * 右孩子节点下标i = 父节点下标z*2+2 * 进行二叉树大堆构造的时候,只需要知道最后一个节点的父节点,然后从该父节点下标往前构造即可 * 最后一个节点的父节点的下标 i = length */ //构建堆的时候,需要从最下层往上层排,按从小到大顺序往上排,然后将上面小的值和其子节点大的值互换位置 private void buildMaxHeap(int[] arr, int len) { //节点(在数组中下标为i) //其左孩子节点下标 = 2i+1 //其有孩子节点下标 = 2i+2 for (int i = (int) Math.floor(len / 2); i >= 0; i--) { //从后往前,从下往上进行排序 heapify(arr, i, len); } } // 判断父节点和子节点的大小关系,并进行位置交换 private void heapify(int[] arr, int i, int len) { // i下标 节点位置为 父节点位置 // 2*i+1 left节点位置为 左孩子节点位置 // 2*i+2 right节点位置为 右孩子节点位置 int left = 2 * i + 1; int right = 2 * i + 2; int largest = i; // 如果left节点下标大于等于len了,说明 i 节点是没有左孩子节点的 if (left < len // 此时largest的值 = i,即父节点和左孩子节点比较大小 // 如果左孩子节点大于父节点 && arr[left] > arr[largest]) { // 则把以i节点为子树中的最大值确定为左孩子节点 largest = left; } // 如果right节点下标大于等于len了,说明 i 节点是没有右孩子节点的 if (right < len // 如果上面的if成立,则此时largest的值 为 left // 那么如果右孩子节点的值大于 largest节点即左孩子节点的值 && arr[right] > arr[largest]) { // 则以i节点为子树中的最大值确定为右孩子节点 largest = right; } // 如果largest发生了改变,不为 i 值,则进行位置交换 if (largest != i) { swap(arr, i, largest); //发生了交换 heapify(arr, largest, len); } } private void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public void println(int [] a) { for(int x:a) { System.out.print(" "+x); } System.out.println(""); } public static void main(String[] args) { HeapSort heapSortTest = new HeapSort(); int[] nums = {5,9,6,8,7,3,5,10,15,22,69,36}; heapSortTest.println(heapSortTest.sort(nums)); }}