算法--排序--堆排

这一篇再画下重点,看一下堆排。

在将堆排之前,有必要先澄清两个概念:堆和堆排序。

堆是一种数据结构,属于完全二叉树的一种。根据数据排列的特点,可以分为大顶堆(最大堆)和小顶堆(最小堆)。所谓的大顶堆,就是满足父节点不小于左、右子节点的树;小顶堆,则是父节点不大于左、右子节点的树。由此,我们也可以得出一个结论:大顶堆(小顶堆)是整个堆最大(小)的元素。

堆排序则是利用堆的性质来进行排序的一种算法。什么性质呢?就是我们刚刚得到的结论——大顶堆(小顶堆)是整个堆最大(小)的元素。具体来说,就是从下往上,拿每一个元素与堆顶元素交换(堆顶元素为最值,这样交换的结果实际上是拿到了排序后的最大或者最小值),交换过后,堆的性质可能会遭到破坏,需要通过沉降重新将剩余元素建立为堆,然后再交换、再沉降…直到到达堆顶。

这样也可以看出,大顶堆适合从小到大排序,小顶堆适合从大到小排序;排序的顺序和堆的名称刚好是相反的。

堆排序的实现一般分为两步:建堆和沉降(维护堆)。这两步其实是一个过程,建堆的过程就是不断地沉降维护。

通过图示,看一下建堆的过程,假设有一个长度为5的数组a=[1,5,8,4,7]。

建堆
堆排

至此,排序的二星双煞介绍完了,需要重点掌握。

条件:
数据量大,特别适合海量数据的排序,后面讲Top K问题,还会用到它。


原理:
(1)通过沉降,建立一个堆;
(2)从下往上,依次交换每个元素与堆顶元素,并维护剩余元素为一个堆;

(n)到达堆顶,结束。


时间复杂度:

nlog(n)


笔面试出现的频率:

在线笔试常考题,多以选择为主,让你选择建堆或者第一次交换之后的数组顺序,偶有填空。面试第一轮,手写代码的命中率比较高,笔者面过的今日头条、腾讯考过(都是以Top K的形式),其他听闻360和58也有考过。

要求必须快速准确地写出代码,并能清晰地讲明原理,画出沉降的过程。


实现:

heapify()是重点,使用了"三个if",切记切记。

public class HeapSort {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a = { 1, 17, 3, 4, 5, 6, 7, 16, 9, 10, 11, 12, 13, 14, 15, 8 };
        heapSort(a);
        print(a);
    }

    public static void print(int[] array) {
        for (int i = 0; i < array.length; i++)
            System.out.print(array[i] + ", ");
        System.out.println("\n");
    }

    //核心
    public static void heapify(int[] array, int index, int length) {
        int left = index * 2 + 1;
        int right = index * 2 + 2;
        int largest = index;
        if (left < length && array[left] > array[index]) {
            largest = left;
        }
        if (right < length && array[right] > array[largest]) {
            largest = right;
        }
        if (index != largest) {
            swap(array, largest, index);
            heapify(array, largest, length);
        }
    }

    public static void buildHeap(int[] array) {
        int length = array.length;
        for (int i = length / 2 - 1; i >= 0; i--) {
            heapify(array, i, length);
        }
    }

    public static void heapSort(int[] array) {
        buildHeap(array);
        int length = array.length;
        for (int i = length - 1; i >= 0; i--) {
            swap(array, 0, i);
            heapify(array, 0, i);
        }
    }

    public static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值