OC 堆排序

作者: sakuragi | 来源:发表于2019-06-29 23:50 被阅读3次

今天去参加一个公司的面试,其中有道题是请说出快速排序和堆排序的区别。妈蛋,瞬间有种这7年程序员白当的感觉,我竟然不知道什么是堆排序。而快速排序也是前两天准备面试的时候临时看了看,毫不夸张的说,这两个算法,在我把每个算法研究了很长时间后,现在叫我来写,我也不保证能完全正确。咱得承认差距,认清现实。算法这东西只有多刷题,写多了自然就会了。

首先我们从字面意思上解释下什么是堆排序,为什么叫堆排序呢,因为整个排序过程中使用的数据结构 而得来。

而我连什么是堆都不知道,没办法,只有去翻大学的教材,我的大学教材是严蔚敏编的《数据结构 C语言版》。开始我没有找到堆这种数据结构的定义,没办法只有百度百科。在我刚刚写这篇文章的时候,我不服气,又回去翻书,发现堆的定义在教材的排序算法-堆排序中。我都不知道自己上大学的时候在干嘛~所以告诫还在读大学的盆友,认认真真的学习,我就是鲜活的例子啊。
堆的定义如下:首先我们可以用一维数组表示堆,堆可以看做是一颗完全二叉树。(完全二叉树的意思是除去最后一层的节点后,其余全是满二叉树)这颗完全二叉树还具备这样的特点才能叫堆。
完全二叉树中所有非终端结点的值均不大于(或者不小于)其左右孩子结点的值。

堆排序的过程

假设我们要将数组升序排序
首先我们将拿到的数组理解成一科完全二叉树,在这颗完全二叉树上原地进行建大堆(什么是大堆,大堆就是最大的值在根结点的堆,为什么这里要建大堆,我们稍后会解释)。

大堆怎么建的问题

我们可以用递归的思想,从下往上依次建。

  /* 
   *@param array 待排序的数组
   *@param start  结点序号(从0开始),待排序的父结点。
   *@param  end   完全二叉树的最后一个尾结点序号,用来判断临
   *界情况                              
   */
+(void)createMaxHeapWithArray:(NSMutableArray<NSNumber*> *)array start:(int)start end:(int)end {
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) {
        //比较两个儿子的大小
        if (son + 1 <= end &&
            [array[son] intValue] < [array[son+1] intValue]) {
            son ++;
        }
        if ([array[dad] intValue] > [array[son] intValue]) {
            return;
        } else {
            [array exchangeObjectAtIndex:dad withObjectAtIndex:son];
            //因为交互打乱了原来的顺利,这里继续对打乱的顺序进行再一次排序,所以dad = son ,son = dad * 2 + 1,直到满足return的条件或者找到了尾结点
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

排序过程

刚刚我们实现了一个函数给定一个数组,开始值和数组对应的完全二叉树的结尾值,我们可以建堆。
接下来我们看看算法的实现

  + (void)heapSortWithArray:(NSMutableArray<NSNumber*> *)array {
    int len =(int) array.count;
    //这里是关键,从最后一个非叶子结点开始,这里就是递归的思想。
    for (int i = len / 2 - 1; i >= 0; i-- ){
        [self createMaxHeapWithArray:array start:i end:len-1];
    }
    
    //交换堆的根结点和尾结点的值,然后对交换后的除去尾结点的最大值的完全二叉树建大堆,一直交换,直到只剩下跟结点。
    for (int i = len - 1; i > 0 ; i -- ) {
        [array exchangeObjectAtIndex:0 withObjectAtIndex:i];
        [self createMaxHeapWithArray:array start:0 end:i-1];
    }
    
    [self printArray:array];
}

其实完全搞明白了也不是很难理解,在我们使用递归的时候,一定要弄清楚临界条件。

好了,堆排序就介绍到这里,方便自己以后来理解,归纳和总结也是一种能力。在面试的过程中,能清楚表达自己的意思很重要。

相关文章

  • OC 堆排序

    今天去参加一个公司的面试,其中有道题是请说出快速排序和堆排序的区别。妈蛋,瞬间有种这7年程序员白当的感觉,我竟然不...

  • 堆排序(oc代码实现)

    概念 堆是一棵顺序存储的完全二叉树,分为大根堆和小根堆 分类 小根堆每个结点的关键字都不大于其孩子结点的关键字。 ...

  • 堆排序算法-OC实现

    简介 堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并...

  • 排序算法

    准备工作 一、快速排序 二、归并排序 三、堆排序 四、 二分查找 /*二分查找*/ 五、 冒泡排序 /*OC 冒...

  • 堆排序(swift、oc双语实现)

    预备知识 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复...

  • 堆排序

    目录 1.堆排序介绍 2.堆排序图文说明 3.堆排序的时间复杂度和稳定性 4.堆排序实现 堆排序介绍 堆排序(He...

  • 堆排序---基础篇

    本文主要介绍堆排序的一些基本过程和分析。 大纲 堆排序简介 堆排序代码实现 1. 堆排序简介 1.1 堆排序的存储...

  • 堆和堆排序

    最小K个数 堆排序 堆排序

  • 使用OC写算法之堆排序

    完全二叉树的基本概念 可能你会疑问,为什么我们明明讲的是堆排序,怎么又扯上了二叉树的概念了,答案就是,我们这里的堆...

  • JS实现堆排序

    原理 堆排序原理 实现 说明 堆排序对大文件很有效 堆排序是不稳定排序

网友评论

    本文标题:OC 堆排序

    本文链接:https://www.haomeiwen.com/subject/rtpmcctx.html