堆排序

1、堆的定义
堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:
Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]。(初始i为0)在最大堆中,最大元素放在根节点中,且对任一非根节点,它的值小于或等于其双亲节点值。最小对则相反,根节点是最小元素。

2、堆排序的思想
利用最大堆(最小堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
1)将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

3、操作过程如下:
首先根据该数组元素构建一个完全二叉树,得到
这里写图片描述
然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下:
这里写图片描述这里写图片描述这里写图片描述

20和16交换后导致16不满足堆的性质,因此需重新调整
这里写图片描述
这样就得到了初始堆。即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。有了初始堆之后就可以进行排序了。
这里写图片描述这里写图片描述
此时3位于堆顶不满堆的性质,则需调整继续调整
这里写图片描述这里写图片描述这里写图片描述
这里写图片描述这里写图片描述这里写图片描述
这里写图片描述这里写图片描述这里写图片描述

从上述过程可知,堆排序其实也是一种选择排序,是一种树形选择排序。只不过直接选择排序中,为了从R[1…n]中选择最大记录,需比较n-1次,然后从R[1…n-2]中选择最大记录需比较n-2次。事实上这n-2次比较中有很多已经在前面的n-1次比较中已经做过,而树形选择排序恰好利用树形的特点保存了部分前面的比较结果,因此可以减少比较次数。

4、java代码

public class HeapSort {

    public static void main(String[] args) {
        HeapSort heapSort = new HeapSort();
        int[] a = { 17, 8, 45, 84, 2, 94 };
        heapSort.heapSort(a, a.length - 1);
    }

    public void heapSort(int[] arrays, int e) {
        if (e > 0) {
            initSort(arrays, e);// 初始化堆,找出最大的放在堆顶
            // snp(arrays);
            arrays[0] = arrays[e] + arrays[0];
            arrays[e] = arrays[0] - arrays[e];
            arrays[0] = arrays[0] - arrays[e];
            // snp(arrays);
            heapSort(arrays, e - 1);
        } else {
            snp(arrays);
        }
    }

    public void snp(int[] arrays) {
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i] + " ");
        }
        System.out.println();
    }

    public void initSort(int[] arrays, int e) {
        int m = (e + 1) / 2;
        for (int i = 0; i < m; i++) {
            boolean flag = buildHeap(arrays, e, i);
            // 如果孩子之间有交换,就要重新开始
            if (flag) {
                i = -1;
            }
        }
    }

    // 返回一个标记,如果有根与孩子交换就要重新从顶根开始查找不满足最大堆树结构
    public boolean buildHeap(int arrays[], int e, int i) {
        int l_child = 2 * i + 1;// 左孩子
        int r_child = 2 * i + 2;// 右孩子
        if (r_child > e) { // 判断是否有右孩子,没有的话直接比较,小于交换
            if (arrays[i] < arrays[l_child]) {
                arrays[i] = arrays[i] + arrays[l_child];
                arrays[l_child] = arrays[i] - arrays[l_child];
                arrays[i] = arrays[i] - arrays[l_child];
                return true;
            } else {
                return false;
            }
        }
        // 在根与两个孩子之间找出最大的那个值进行交换
        if (arrays[i] < arrays[l_child]) {
            if (arrays[l_child] > arrays[r_child]) {
                // 交换根与左孩子的值
                arrays[i] = arrays[i] + arrays[l_child];
                arrays[l_child] = arrays[i] - arrays[l_child];
                arrays[i] = arrays[i] - arrays[l_child];
                return true;
            } else {
                // 交换根与右孩子的值
                arrays[i] = arrays[i] + arrays[r_child];
                arrays[r_child] = arrays[i] - arrays[r_child];
                arrays[i] = arrays[i] - arrays[r_child];
                return true;
            }
        } else if (arrays[i] < arrays[r_child]) {
            // 交换根与右孩子的值
            arrays[i] = arrays[i] + arrays[r_child];
            arrays[r_child] = arrays[i] - arrays[r_child];
            arrays[i] = arrays[i] - arrays[r_child];
            return true;
        }
        return false;
    }// buildHeap

}

5、性能分析如下:
1)空间效率。在这里我们并未用到辅助单元。
2)时间复杂度。建堆时间为O(n),之后有n-1次向下调整操作,每次调整的时间复杂度为O(h),故在最好,最坏和平均的情况下,堆排序的复杂度为O(nlog2n)。
3)稳定性。在进行筛选时,有可能把后面相同关键字的元素调整到前面,所以堆排序算法是不稳定算法。例如,表L={1,2,2},构建初始堆时,可能将2交换到堆顶,此时L={2,1,2},最终排序序列为L={1,2,2},显然,2与2的相对次序已经发生了变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值