数据结构与算法——堆排序

package eightsort;

import java.util.Arrays;

/**
 * 堆排序的基本思想
 * 1.初始化堆:将数列a[1...n]构造成最大堆。
 * 2.交换数据:将a[1]和a[n]交换,使a[n]是a[1...n]中的最大值;然后将a[1...n-1]重新调整为最大堆。 接着,将a[1]和a[n-1]交换,使a[n-1]是a[1...n-1]中的最大值;然后将a[1...n-2]重新调整为最大值。 依次类推,直到整个数列都是有序的。
 * 数组实现的二叉堆的性质
 * 1.索引为i的左孩子的索引是 (2*i+1);
 * 2.索引为i的左孩子的索引是 (2*i+2);
 * @author zzc
 * @date 2019.4.14
 */
public class heapSort {
    public static void main(String[] args) {
        int[] array = new int[] { 2, 1, 4, 3, 6, 5, 8, 7 };
        sort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void sort(int[] array) {
        //从最后一个非叶子节点开始,向上对于整棵树进行大顶对调整
        //每一层都是从下向上,从左到右
        for (int i = array.length / 2 - 1; i >= 0; i--) {
            adjustHeap(array, i, array.length);
        }
        // 建堆结束
        for (int j = array.length - 1; j > 0; j--) {
            // 把大顶堆的根元素,放到数组的最后,就是每一次的堆调整之后,都会把最大的元素放到自己的最终位置
            swap(array, 0, j);
            //继续调整剩下的数组
            adjustHeap(array, 0, j);
        }
    }

    /**
     *
     * @description 整个堆排序最关键的地方
     */
    public static void adjustHeap(int[] array, int i, int length) {
        // 先把当前元素取出来,因为当前元素可能要一直移动
        int temp = array[i];
        // 在堆建成,且完成第一次交换之后,实质上i=0;也就是说,是从根所在的最小子树开始调整的
        // 接下来的讲解,都是按照i的初始值为0来讲述的
        // 这一段很好理解,如果i=0;则k=1;k+1=2
        // 实质上,就是根节点和其左右子节点记性比较,让k指向这个不超过三个节点的子树中最大的值
        // 这里,必须要说下为什么k值是跳跃性的。
        // 首先,举个例子,如果a[0] > a[1]&&a[0]>a[2],说明0,1,2这棵树不需要调整,那么,下一步该到哪个节点了呢?肯定是a[1]所在的子树了,
        // 也就是说,是以本节点的左子节点为根的那棵小的子树
        // 而如果a[0}<a[2]呢,那就调整a[0]和a[2]的位置,然后继续调整以a[2]为根节点的那棵子树,而且肯定是从左子树开始调整的
        // 所以,这里面的用意就在于,自上而下,自左向右一点点调整整棵树的部分,直到每一颗小子树都满足大根堆的规律为止

        //从当前节点的子节点开始,依次遍历下面的节点,找到一个最大的数值
        for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
            // 让k先指向子节点中最大的节点
            //如果右子节点的索引小于数组长度并且,左子节点小于右子节点,k+1
            //就是找有子节点的子节点,进行下一次循环
            if (k + 1 < length && array[k] < array[k + 1]) {
                k++;
            }
            // 如果左子节点大于当前节点,交换值
            if (array[k] > temp) {
                swap(array, i, k);
                // 下面就是非常关键的一步了
                // 如果子节点更换了,那么,以子节点为根的子树会不会受到影响呢?
                // 所以,循环对子节点所在的树继续进行判断
                i = k;
            } else {
                // 如果不用交换,那么,就直接终止循环了
                break;
            }
        }
    }
    /**
     * 交换元素
     *
     * @param arr
     * @param a
     *            元素的下标
     * @param b
     *            元素的下标
     */
    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值