1、排序原理
首先对要排序的数组元素的进行比较把它初始化成一个大根堆的形势,此时这个堆的堆顶既原数组的第一个元素是最大的,把它与最后一个元素交换位置,然后在把除了最后一个元素的所有元素重新排列成大根堆,拿第一个和此时的最后一个交换位置,依次执行直到剩余的最后一个元素的下标为0是结束,此时的结果就是排序后的结果。
2、实现步骤:
a)初始化稳定堆
a.1)先找出堆的一些规律,因为这些堆是完全二叉树的形势,所有他的父节点和左右孩子节点的关系应该是(假设父节点是k,则左孩子节点是left = (2 * k + 1),右孩子节点是right= left + 1);
a.2)开始把这个数组的元素按照堆的形势整理,先取第一个元素既k = 0;此时k既是父节点,然后找到他的两个孩子节点,用他们三个进行比较把他们三个组成的堆调整成大根堆;
a.3)如果成功了,就取出第二个元素既k = 1;继续上面的步骤,直到取出一个父节点,而他的左孩子节点或者右孩子节点不小于数组的长度时,结束取值,既不需要去取父节点了;此时堆的初步排序结束;
a.4)因为上面的那一步骤是以每一个最小的大根堆进行排序的(既只根据父节点,两个孩子节点排序,没有管孩子节点是否还有孩子节点)所有很可能后面的排序的时候会把前面的打乱,所有此时应该对上一步骤进行递归运算,把刚才排好的堆进行重新排序,直到所有的堆都已经是稳定堆时结束。(既每一次排序的时候如果有的堆不是稳定堆就要重新排序,当有一次递归的时候不需要排序了,说明此时的堆已经是稳定堆了结束递归);
b)开始排序
b.1)因为经过a步骤堆的最顶端已经是最大值,此时就把那个值和要排序的数组的最后一个值交换位置;
b.2)因为每次交换位置后就已经把数组的最大值排好序了,这个最大值就已经固定了,不需要排序了,所以,此时应该把要排序的长度减少1;
b.3)交换位置后此时的堆已经不是稳定堆,所以要重新整理堆,就把此时的顶当作父节点与他的两个孩子节点比较整理这个堆,如果父节点是和左孩子节点交换位置,那么左孩子节点就不一定是稳定堆了,(但是右孩子节点一定是稳定堆,不需要去整理它)此时就把刚才的左孩子节点当作父节点去整理他自己的两个孩子节点依次类推,如果交换的是右孩子节点,则方法相同,直到没有孩子节点或者交换后的堆依然是稳定堆此时结束整理;
b.4)不断的循环排序的几个步骤,直到要排序的长度小于2的时候结束,此时得到的结果就是排序后的结果。
3、实现代码:
- package sort;
-
- import java.util.Arrays;
-
- public class HeapSortTest {
-
-
-
-
- public static void main(String[] args) {
-
- int[] a = {50, 30, 60, 38, 423, 42, 5423};
- HeapSort(a);
- System.out.println("排序完成后的结果 :" + Arrays.toString(a));
-
- }
- private static void HeapSort(int[] a) {
- int length = a.length;
-
- initHeap(a);
- System.out.println("堆初始化后的结果: " + Arrays.toString(a));
- System.out.println();
-
- while(length > 1){
-
- System.out.println("每一次堆整理完成后的结果: " + Arrays.toString(a));
- exchange(a, length - 1, 0);
- System.out.println("每一次交换位置后的结果: " + Arrays.toString(a));
- System.out.println();
-
-
-
- length--;
- System.out.println("每一次需要排序的数组的长度 : " + length);
- int k = 0;
- while(k < length){
- int left = 2 * k + 1;
- int right = left + 1;
-
- int max = left;
-
- if (left < length) {
- if (right < length ) {
-
- if (a[right] > a[left]) {
-
- max = right;
- }
- }
-
- if (a[max] > a[k]) {
-
- exchange(a, max, k);
-
-
-
- k = max;
- }else {
-
- break;
- }
- }else {
-
- break;
- }
- }
- }
- }
-
-
-
- public static void initHeap(int[] a){
-
- boolean isExchange = false;
- int length = a.length;
- int k = 0;
- for (; k < length; k++) {
-
-
- int left = 2 * k + 1;
- int right = left + 1;
- int max = left;
- if (left < length) {
- if (right < length) {
- if (a[right] > a[left]) {
- max = right;
- }
- }
-
- if (a[max] > a[k]) {
- exchange(a, max, k);
- isExchange = true;
- }
- }else {
- break;
- }
-
- }
- if (isExchange) {
-
-
- initHeap(a);
- }
-
- }
-
-
-
- public static void exchange(int[] a, int max, int k){
- a[max] ^= a[k];
- a[k] ^= a[max];
- a[max] ^= a[k];
- }
- }
简化代码:
因为初始化堆和排序的方法非常相似,为了节省代码量,可以把初始化堆和排序的方法合并在一起;
- <pre class="java" name="code">package heapSort;
-
- import java.util.Arrays;
-
- public class HeapSortTest {
-
-
-
-
- public static void main(String[] args) {
-
- int[] a = {50, 30, 60, 38, 423, 42, 5423};
- heapSort(a, a.length, false);
- System.out.println("排序完成后的结果 :" + Arrays.toString(a));
-
- }
-
-
-
- public static void heapSort(int[] a, int length, boolean isHeap){
-
-
- boolean isExchange = false;
- int k = 0;
- for (; k < length;) {
-
-
- int left = 2 * k + 1;
- int right = left + 1;
- int max = left;
- if (left < length) {
- if (right < length) {
- if (a[right] > a[left]) {
- max = right;
- }
- }
-
- if (a[max] > a[k]) {
- exchange(a, max, k);
- isExchange = true;
- }
- }else {
- break;
- }
-
- if (!isHeap) {
-
- k ++;
- }else {
-
- k = max;
- }
- }
-
- if (!isHeap && isExchange) {
-
-
- heapSort(a, length,false);
- }else {
- if (length > 1) {
- System.out.println("每一次堆整理完成后的结果: " + Arrays.toString(a));
- exchange(a, length - 1, 0);
- System.out.println("每一次交换位置后的结果: " + Arrays.toString(a));
- System.out.println();
-
-
-
- length--;
- System.out.println("每一次需要排序的数组的长度 : " + length);
- heapSort(a, length, true);
- }
- }
- }
-
-
-
- public static void exchange(int[] a, int max, int k){
- a[max] ^= a[k];
- a[k] ^= a[max];
- a[max] ^= a[k];
- }
- }
结果:
堆初始化后的结果: [5423, 423, 60, 38, 30, 42, 50]
每一次堆整理完成后的结果: [5423, 423, 60, 38, 30, 42, 50]
每一次交换位置后的结果: [50, 423, 60, 38, 30, 42, 5423]
每一次需要排序的数组的长度 : 6
每一次堆整理完成后的结果: [423, 50, 60, 38, 30, 42, 5423]
每一次交换位置后的结果: [42, 50, 60, 38, 30, 423, 5423]
每一次需要排序的数组的长度 : 5
每一次堆整理完成后的结果: [60, 50, 42, 38, 30, 423, 5423]
每一次交换位置后的结果: [30, 50, 42, 38, 60, 423, 5423]
每一次需要排序的数组的长度 : 4
每一次堆整理完成后的结果: [50, 38, 42, 30, 60, 423, 5423]
每一次交换位置后的结果: [30, 38, 42, 50, 60, 423, 5423]
每一次需要排序的数组的长度 : 3
每一次堆整理完成后的结果: [42, 38, 30, 50, 60, 423, 5423]
每一次交换位置后的结果: [30, 38, 42, 50, 60, 423, 5423]
每一次需要排序的数组的长度 : 2
每一次堆整理完成后的结果: [38, 30, 42, 50, 60, 423, 5423]
每一次交换位置后的结果: [30, 38, 42, 50, 60, 423, 5423]
每一次需要排序的数组的长度 : 1
排序完成后的结果 :[30, 38, 42, 50, 60, 423, 5423]