数据结构--堆排序

        堆是一种特殊的完全二叉树,满足每一个结点的值比左右子树的所有结点都大(大顶堆)/小(小顶堆)。由于是完全二叉树,我们不需要用借助指针来存储树,用一个数组即可。

         如 a = [1,2,3,4,5,6]表示的树:

 

         a[i] 的左节点为 a[2*i+1],右结点为 a[2*i+2]。所以对一个数组使用堆排序在原数组上进行就可以了。

public static void main(String[] args) {
int[] nums = {3,2,1,5,7,4,8,0,10,9,-2,-1,6};
heapSort(nums);
System.out.println(Arrays.toString(nums));
}

private static void heapSort(int[] nums) {
//自底向上对所有非叶子结点调整一遍,不满足大顶堆的结点全沉下去后,最终构造成了大顶堆
for (int i = nums.length / 2 - 1; i >= 0; i--) {
adjustHeap(nums, i, nums.length - 1);
}

//将大顶堆的根(最大值)与待排序数组最后的元素做个交换,这个最大值位置得到了确定。然后对新的根结点做一次调整,再构成大顶堆。重复上述过程
for (int i = nums.length - 1; i >= 1; i--) {
swap(nums, 0, i);
adjustHeap(nums, 0, i - 1);
}
}

//调整大顶堆:start结点如果比子结点小,就将start结点下沉下去,把更大的子结点提上来。若下沉后发现仍有新子结点大于父结点,继续下沉,直到子结点大于end。
private static void adjustHeap(int[] nums, int start, int end) {
if (nums == null || start < 0 || end >= nums.length) {
return;
}

for (int i = start; 2 * i + 1 < end;) {
int maxChild = 2 * i + 1;
//在不大于end的前提下,找到最大的子结点
if (maxChild + 1 <= end && nums[maxChild] < nums[maxChild + 1]) {
maxChild += 1;
}
//若最大子结点大于父结点,交换。更新父结点指向的新位置
if (nums[maxChild] > nums[i]) {
swap(nums, maxChild, i);
i = maxChild;
} else {
break;
}
}
}

private static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
 

posted on 2019-08-29 17:56  千山万水楼外楼  阅读(202)  评论(0编辑  收藏  举报

导航