排序——选择排序之堆排序

堆排序(HeapSort)是利用完全二叉树特性的一种选择排序。

定义如下:

设n个元素的数据序列{K0,k1,k2,...,kn-1},当且仅当满足下列关系时,称为最小/大堆。Ki<=K2i+1且Ki<=K2i+2或Ki>=K2i+2,i=0,1,2,...,[n/2-1]换言之,将{{K0,K1,...,Kn-1}}序列看成是一棵完全二叉树的层次遍历序列,如果任意一个结点元素<=/>=其孩子结点元素,则称该序列为最小/大堆,根结点值最小/大。

堆排序简单说来就是:将一个数据序列建成最小/大堆,则根结点值最小/大。

代码实现如下:


package g;

public class HeapSort {
    public static int[] randomInt(int n, int size) {
        int[] value = new int[n];
        for (int i = 0; i < value.length; i++) {
            value[i] = (int) (Math.random() * size);
        }
        return value;
    }

    public static void print(int[] keys) {
        for (int i : keys) {
            System.out.print(i + " ");            
        }
        System.out.println();
    }

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

    // 将keys数组中以parent为根的子树调整成最小/大堆,子序列范围为parent~end
    // 私有方法,只被堆排序方法调用,确保parent、end在范围内
    public static void sift(int[] keys, int parent, int end, boolean minheap) {
        System.out.print("sift   " + parent + ".." +end+ "\t");
        // child是parent的左孩子,因为根据二叉树性质5,完全二叉树中的第i(0<=i<n)个结点,如果有孩子
        // 则左孩子为第2i+1个结点,右孩子为第2i+2个结点
        int child = 2 * parent + 1;
        int value = keys[parent];
        // 沿较小/大值孩子结点向下筛选
        while (child <= end) {
            if (child < end && (minheap ? keys[child] > keys[child + 1] : keys[child] < keys[child + 1])) {
                // child记住孩子值较小/大者
                child++;
            }
            // 若父母结点值较小/大
            if (minheap ? value > keys[child] : value < keys[child]) {
                // 将较小/大孩子结点值上移
                keys[parent] = keys[child];
                // parent、child两者都向下一层
                parent = child;
                child = 2 * parent + 1;
            } else {
                break;
            }

        }
        // 当前子树的原根值调整后的位置
        keys[parent] = value;
        print(keys);
    }

    // 堆排序(降序),最小堆
    public static void heapSort(int[] keys) {
        heapSort(keys, true);
    }

    // 堆排序,当minheap为true时,创建最小堆,降序排序;否则创建最大堆,升序排序
    public static void heapSort(int[] keys, boolean minheap) {
        // 创建最小/大堆,根结点值最小/大
        for (int i = keys.length / 2 - 1; i >= 0; i--) {
            sift(keys, i, keys.length - 1, minheap);
        }
        // 每趟将最小/大值交换到后面,再调整成最小/大堆
        for (int i = keys.length - 1; i > 0; i--) {
            // 交换keys[0]与keys[i]
            swap(keys, 0, i);
            sift(keys, 0, i - 1, minheap);
        }
    }
      public static void main(String[] args){
          int[] values=HeapSort.randomInt(10, 100);
          System.out.print("关键字序列:");
          HeapSort.print(values);
          HeapSort.heapSort(values);
      }
}

输出如下:

关键字序列:64 57 29 75 8 53 98 78 78 53
sift   4..9    64 57 29 75 8 53 98 78 78 53
sift   3..9    64 57 29 75 8 53 98 78 78 53
sift   2..9    64 57 29 75 8 53 98 78 78 53
sift   1..9    64 8 29 75 53 53 98 78 78 57
sift   0..9    8 53 29 75 57 53 98 78 78 64
sift   0..8    29 53 53 75 57 64 98 78 78 8
sift   0..7    53 57 53 75 78 64 98 78 29 8
sift   0..6    53 57 64 75 78 78 98 53 29 8
sift   0..5    57 75 64 98 78 78 53 53 29 8
sift   0..4    64 75 78 98 78 57 53 53 29 8
sift   0..3    75 78 78 98 64 57 53 53 29 8
sift   0..2    78 98 78 75 64 57 53 53 29 8
sift   0..1    78 98 78 75 64 57 53 53 29 8
sift   0..0    98 78 78 75 64 57 53 53 29 8



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值