为什么要学习排序算法?

Posted cdai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么要学习排序算法?相关的知识,希望对你有一定的参考价值。

为什么要学习排序算法?

根据统计,早起大型机CPU资源的四分之一都花在了数据排序上面。排序算法作为最基础的算法,各种操作系统、编程语言都提供了内置的实现。既然排序实现随处可见,我们为什么还要自己动手实现呢?虽然经典算法要动手写写加深印象的道理都懂,但直到最近才发现,每种排序算法里都“暗藏玄机”。排序算法看似简单,其实不同的算法中蕴涵着经典的算法策略。通过熟练掌握排序算法,就可以掌握基本的算法设计思想,包括暴力枚举法、时间空间置换、子问题的分治以及随机化。


1.选择排序:暴力搜索

1.1 “暴力”的定义

按照Wikipedia的定义,暴力搜索也叫穷举法。它是一种常用的解决问题策略或者算法范式,通过系统化产生所有可能解来找到最终答案:

In computer science, brute-force search or exhaustive search, also known as generate and test, is a very general problem-solving technique and algorithmic paradigm that consists of systematically enumerating all possible candidates for the solution and checking whether each candidate satisfies the problem’s statement.

所谓“暴力”是指“Just do it”。需要注意的是所有解空间是来自问题定义,而非来自输入数据的所有排列组合。按照《The Design & Analysis of Algorithms》一书的定义,暴力搜索就是一种基于问题定义的、最直接的解决问题方法(“usually directly based on the problem’s statement and definitions of the concepts involved”)。

1.2 例子

比如来自Leetcode经典的2 Sum问题,问题定义里说要找到两数之和等于某值,此处暴力搜索即为穷举输入数据中所有两个数可能的组合,然后找到符合条件的一对或者多对。所以,假设输入数据规模为N(比如长度为N的数组),搜索空间只是从N个数里取出两个数的组合。类似地,线性查找最小值、查找子字符串、查找平面上最近的两个点,都可以根据问题的定义直接得到算法实现。


2.堆排序:时间空间trade-off

2.1 简介

时间和空间置换(Time and space trade-off),即用额外的空间(通常是一种高效的数据结构)来换取之后更快的处理。 其实本质上,堆排序=选择排序+堆数据结构,通过花费额外的空间,来优化“选择”这个动作。这样每次选择剩余数据中最小值的操作,其时间复杂度就从原来的线性N降低到LogN。

2.2 预处理 vs 即时维护

除了像上面堆排序,数据结构预先初始化,将解题步骤分为两阶段,也可以在执行过程中,一边执行一边维护,只要保证当前所需的数据都在结构里即可。比如,还是这个经典的2 Sum问题。如果数组未排序的话,我们可以用哈希表来记录其他元素,从而省去暴力搜索时的内层循环。哈希表可以预先初始化,也可以一边遍历数组一边维护。


3.插入排序:减而治之

所谓的减而治之(Decrease-and-Conquer),也就是增量法。要解决输入规模为N的问题,我们先解决规模为N-1的子问题,然后思考如何利用N-1的解和当前数据得到N的解。在这个过程,其实我们一直在维护一个不变量(Invariant),从而保证了所有数据处理结束后结果的正确性。根据问题规模缩减的速度,可以分为常量递减和变量递减两种方式

3.1 常量递减

常量递减(Decrease-by-a-constant-factor)即问题规模以固定的速度缩减,比如:

  • 插入排序
  • 产生排列组合:同插入排序一样
  • 二分查找:每次减半

3.2 变量递减

变量递减(Decrease-by-a-variable-factor)每次问题规模缩减的程度可变:

  • 找中位数:递减程度由选取的分区元素决定。
  • 插值查找(Interpolation search):二分查找不考虑查找值的特点,每次都折半。而插值排序根据分区的第一个、最后一个值以及要查找的值,选取一个更靠前或者靠后的值来比较。这种思想类似于在电话簿里查找一个人的电话,假如名字是A开头,则更高效的方式不是翻到中间,而是电话薄的前面。

4.归并排序:分而治之

4.1 简介

与减而治之类似,分而治之(Divide-and-Conquer)将问题一分为二,解决两个子问题后再考虑如何合并得到最终结果。

4.2 “分”和“治”

分而治之两个最重要的例子就是归并排序和快速排序。有趣的是,两者在“分”和“治”上有着完全相反的实现比重。前者重在合并,划分几乎没有额外逻辑;而后者则重在划分,合并时没有额外动作。


5.快速排序:随机化

平均情况下,快速排序的时间复杂度很不错。然后最坏情况下,它却可能恶化到与插入排序差不多的N平方。算法设计里另一种重要的思想就是利用随机化,从概率上保证最坏的情况不会发生。比如对于快速排序来说,可以随机选取,或者采样后决定要用哪个值来做划分。

以上是关于为什么要学习排序算法?的主要内容,如果未能解决你的问题,请参考以下文章

(学习笔记)排序算法

(学习笔记)排序算法

为什么要学习排序算法?

为什么要学习排序算法?

排序算法精讲:选择排序和冒泡排序

超级具体解读基本排序算法(不看懊悔,带排序演示动画)