排序好多问

  1. 基于比较的排序的下界是什么。

排序是为了一组数按从大到小(或从小到大)的顺序进行排列,也就是说它要在所有的排列中选择一种排列,而所有的排列的总数有n!种,而我们通过比较去排序,从这个层面上来看就是排除n!-1种顺序的可能性。假设待排序的数有ABCD...,对于一次比较 假设 A > B, 那么A必然就在B的前面,所有能够排除n!/2 种可能的顺序,依次类推至少需要log2(n!)(小于nlogn,这两者同等规模就不证明了哈)比较。

  1. 快速排序的有什么问题,如何改进的?

快排的思想很简单,一个典型的分而治之的思想,根据某个pivot(轴,基准值),将数组分为比它大和比它小的二部分,然后对这两部分分别排序。对于这样的算法描述,实现过程种应该注意些什么呢?

首先pivot的选择非常重要,因为如果每次都选择了一个最大数,那意味着需要做n(数组长度)次划分,时间复杂度就退化到。因此就会有一些选自己策略,比如随机在数组种选择一个pivot,或者取头中末三个数,挑其中中等大小的数作为pivot。

然后选择了pivot,怎么把数组分成两部分呢,最简单的思想无非是搞二个缓存区A,B,然后顺序扫描数组,大的放A,小的放B,然后再写回数组,但这样引入了O(N)的空间复杂度。于是乎问题来了,怎么原地划分呢(这些个思路很容易被应用到一些算法题中https://leetcode.com/problems/remove-duplicates-from-sorted-array/)?

第一种思路 单向扫描的方式

showcode吧,感觉说起来好麻烦。


排序好多问_第1张图片
image
 while(j <= end){
            if(A[j] <= pivot){
                i++;
                Swap(A, i, j);
                j++;//j继续向前,扫描下一个
            }else{
                j++;//大于pivot的元素增加一个
            }
        }

它的不足地方在于只要遇上小于等于的数据就要做一次swap,所以改进的方法就有双端扫描的方式:

 while(i < j){
     while(i < j && A[j] > pivot){
                j--;
     }

      A[i] = A[j];
     while(i < j && A[i] <= pivot){
            i++;
     }            
     A[j] = A[i];
 }

以及后面还有什么把=情况也给划分出来,以及考虑选取两个pivot等等。


排序好多问_第2张图片
image
  1. 堆排序好像不怎么受欢迎,这是为嘛呢?

看到一种解释是CPU不友好,因为像其他的排序算法,数据的读取顺序其实大部分时候都是顺序的,而对于基于数组堆排序而言,nums[i] 要和nums[2i+1] nums[2i+2]进行比较,这个下标的跨度可能就很大了,这样就不利于CPU缓存了,因为违反了缓存基于局部性的原理。

  1. timsort是什么神奇的的排序算法

算法的思想不做过多介绍,核心就是利用了计算数据中的有序段,并适时合并的思路,但讲真挺佩服实现的人的,排序感觉是一个研究烂了的领域,竟然还有人在如此基础的领域做出这种进步,不容易呀,不像那些成天趁深度学习热度,各种发水文的人(酸溜溜的,我有羡慕成分,哈哈),膜拜大佬Tim Peters。

  1. 基数排序,桶排序,计数排序什么情况下适用呢

对于这些个线性排序,我首先树立的观点是,一旦一个算法能够比处理同类算法要快上一个量级,却没有带来其他方面的复杂度,那基本上是对问题做了特殊的假设,不适宜通用场景。而对于这些个线性排序方法,计数排序是要求数据可能的值的个数是比较少的是可以确定的。桶排序相当于是计数排序的一个泛化版本了,核心思想都是将数据在线性时间内划分到各个区间,区间之间的顺序是已知的,SO只要关注于区间里的排序,只要每个区间里的数据量够小,那么就能保证全体排序的线性时间,但其实也是对数据分布做了假设,如果数据可能的值域特别宽广,那桶太多了,必然从时间空间上看都是不合适的。而基数排序对数据的要求在于它是定长的(可以预处理成定长),而且不能太长,然后通过每一位它的取值是很少的,所以可以通过计数桶排序的方式搞定。所以它对数据的假设是,选定一个基后,数据位数不能太大。

  1. 冒泡 插入排序 选择排序这种时间复杂度的算法肿么会有人用它呢?

每种算法都会有它的适用场景,就算时间复杂度高,这也显示的渐进的趋势,也就是说数据量大用它衡量才是OK的,如果只有几百个,那么时间复杂度某种程度上就失去了意义,或者说哪些复杂度里的被忽略的常数级别的,以及复杂度的系数的作用就会体现出来,这也是java中再数据量小的时候就直接采用插入排序搞起来的原因了(冒泡选择啥的好像真没啥好的啦啦啦)。

  1. 一个工业级的排序算法是肿么样的?

一个工业级别的排序算法往往是各种算法的组合,在什么什么场景下用特定的算法,数据少的时候可以用二分插入,多的时候用快排,或者timsort等等。其实其他方面也一样,每一种算法从论文里长出来,都是针对它要解决的哪个问题点的,所以很难一招打遍天下无敌手。

参考
https://blog.csdn.net/Holmofy/article/details/71168530

你可能感兴趣的:(排序好多问)