堆排序的过程:
堆排序正是利用小根堆(或大根堆)来选取当前无序区中关键字小(或最大)的记录实现排序的。我们不妨利用大根堆来排序。每一趟排序的基本操作是: 将当前无序区调整为一个大根堆 ,选取关键字最大的堆顶记录,将它和无序区中的最后一个记录交换。这样,正好和直接选择排序相反,有序区是在原记录区的尾部形成并逐步向前扩大到整个记录区。
完整源码:http://yuncode.net/code/c_503a2ccccb89623
- 016 public class HeapSort {
- 017
- 018 /**
- 019 * 排序算法的实现,对数组中指定的元素进行排序
- 020 *
- 021 * @param array
- 022 * 待排序的数组
- 023 * @param from
- 024 * 从哪里开始排序
- 025 * @param end
- 026 * 排到哪里
- 027 * @param c
- 028 * 比较器
- 029 */
- 030 public void sort(Integer[] array, int from, int end) {
- 031 // 创建初始堆
- 032 initialHeap(array, from, end);
- 033
- 034 /*
- 035 * 对初始堆进行循环,且从最后一个节点开始,直接树只有两个节点止 每轮循环后丢弃最后一个叶子节点,再看作一个新的树
- 036 */
- 037 for (int i = end - from + 1; i >= 2; i--) {
- 038 // 根节点与最后一个叶子节点交换位置,即数组中的第一个元素与最后一个元素互换
- 039 swap(array, from, i - 1);
- 040 // 交换后需要重新调整堆
- 041 adjustNote(array, 1, i - 1);
- 042 }
- 043
- 044 }
- 045
- 046 /**
- 047 * 初始化堆 比如原序列为:7,2,4,3,12,1,9,6,8,5,10,11 则初始堆为:1,2,4,3,5,7,9,6,8,12,10,11
- 048 *
- 049 * @param arr
- 050 * 排序数组
- 051 * @param from
- 052 * 从哪
- 053 * @param end
- 054 * 到哪
- 055 * @param c
- 056 * 比较器
- 057 */
- 058 private void initialHeap(Integer[] arr, int from, int end) {
- 059 int lastBranchIndex = (end - from + 1) / 2;// 最后一个非叶子节点
- 060 // 对所有的非叶子节点进行循环 ,且从最一个非叶子节点开始
- 061 for (int i = lastBranchIndex; i >= 1; i--) {
- 062 adjustNote(arr, i, end - from + 1);
- 063 }
- 064 }
- 065
- 066 /**
- 067 * 调整节点顺序,从父、左右子节点三个节点中选择一个最大节点与父节点转换
- 068 *
- 069 * @param arr
- 070 * 待排序数组
- 071 * @param parentNodeIndex
- 072 * 要调整的节点,与它的子节点一起进行调整
- 073 * @param len
- 074 * 树的节点数
- 075 * @param c
- 076 * 比较器
- 077 */
- 078 private void adjustNote(Integer[] arr, int parentNodeIndex, int len) {
- 079 int minNodeIndex = parentNodeIndex;
- 080 // 如果有左子树,i * 2为左子节点索引
- 081 if (parentNodeIndex * 2 <= len) {
- 082 // 如果父节点小于左子树时
- 083 if ((arr[parentNodeIndex - 1]
- 084 .compareTo(arr[parentNodeIndex * 2 - 1])) < 0) {
- 085 minNodeIndex = parentNodeIndex * 2;// 记录最大索引为左子节点索引
- 086 }
- 087
- 088 // 只有在有或子树的前提下才可能有右子树,再进一步断判是否有右子树
- 089 if (parentNodeIndex * 2 + 1 <= len) {
- 090 // 如果右子树比最大节点更大
- 091 if ((arr[minNodeIndex - 1]
- 092 .compareTo(arr[(parentNodeIndex * 2 + 1) - 1])) < 0) {
- 093 minNodeIndex = parentNodeIndex * 2 + 1;// 记录最大索引为右子节点索引
- 094 }
- 095 }
- 096 }
- 097
- 098 // 如果在父节点、左、右子节点三都中,最大节点不是父节点时需交换,把最大的与父节点交换,创建大顶堆
- 099 if (minNodeIndex != parentNodeIndex) {
- 100 swap(arr, parentNodeIndex - 1, minNodeIndex - 1);
- 101 // 交换后可能需要重建堆,原父节点可能需要继续下沉
- 102 if (minNodeIndex * 2 <= len) {// 是否有子节点,注,只需判断是否有左子树即可知道
- 103 adjustNote(arr, minNodeIndex, len);
- 104 }
- 105 }
- 106 }
- 107
- 108 /**
- 109 * 交换数组中的两个元素的位置
- 110 *
- 111 * @param array
- 112 * 待交换的数组
- 113 * @param i
- 114 * 第一个元素
- 115 * @param j
- 116 * 第二个元素
- 117 */
- 118 public void swap(Integer[] array, int i, int j) {
- 119 if (i != j) {// 只有不是同一位置时才需交换
- 120 Integer tmp = array[i];
- 121 array[i] = array[j];
- 122 array[j] = tmp;
- 123 }
- 124 }
- 125
- 126 /**
- 127 * 测试
- 128 *
- 129 * @param args
- 130 */
- 131 public static void main(String[] args) {
- 132 Integer[] intgArr = { 5, 9, 1, 4, 2, 6, 3, 8, 0, 7, 0, -7, -1, 34 };
- 133 HeapSort heapsort = new HeapSort();
- 134 heapsort.sort(intgArr, 0, intgArr.length - 1);
- 135 for (Integer intObj : intgArr) {
- 136 System.out.print(intObj + " ");
- 137 }
- 138 }
- 139
- 140 }
转载于:https://blog.51cto.com/laoye/1011799