吴军的硅谷来信-排序算法

358 阅读3分钟

班里统计所有同学的考试排名成绩,50人左右

1.遍历,冒泡排序

第一次挑出成绩最好的,第一次挑出第二号的,依次循环下去。第一次比较49次,第二次比较48次

2.插缝,插入排序

  • 拿出一张白纸写上一个人的分数,再拿第二张白纸写上第二人分数,
  • 如果第二个大于第一个则放在第一个上面。
  • 第三个如果大于第一个小于第二个,放在第一和第二中间,如下图

image.png

要提高效率,关键在于减少不必要的比较。

3.归并排序

少做事情的思想

简单版本

  • ,把数组一分为二,各自进行冒泡排序,让把两个排好的数组进行合并。
  • 合并的时候,由于左边依次从左边第一个,与右边的第一个比较,较小的拿出放到结果列表里。
  • 如上面的 2和6 ,取2。
  • 继续比较:4和6 ,取4。
  • 继续比较:19和6 ,取6。
  • 继续比较:19和10 ,取10。
  • 继续比较:19和13 ,取13。
  • 继续比较:19和20 ,取19。
  • 继续比较:40和20 ,取20。
  • 继续比较:最后一个40。

这里关键在于:由于左右两边都是排好序,最小的元素肯定是两个数组中其中一个。所以永远按两个元素的首元素比较取出,则永远都能拿到最小值。

image.png

升级版本

通过递归的方式,把数组继续拆分到单个不能再拆分。然后再回溯合并。 此过程叫做分治法(Divide and Conquer),也叫二路归并

  • 自上而下的递归
  • 自下而上的迭代 使用网上的流行图:

mergeSort.gif

依次拆分到最小元素如:(3,44) (38,5),然后开始 (小排序+小排序) 合并成一个新的有序数组

4.快速排序

  1. 在一堆无序的数字里(最大为100)。挑选一个,比如51,这个51就是叫做枢值
  2. 把所有小于51的分为A组,所有大于等于51放B组。
  3. 依次继续再A组里面随机选一个值比如30做枢值(由于A组都是小于51,所有拿到的值一定在0-50之间)
  4. 则A被分解成:C组0-29,D组30到50。
  5. 同理 B 取出的是 70,则分成:E组51-69,F组70到100。
  6. 直到不能再细分组为止。

由于每次分组操作对下一次都是有意义的,没有做过多的无用功。

快速排序与归并排序比较

举例高中生找尖子

如果有一个200000的高中生,都在一个高中上课,每次要找到里面的尖子。效率肯定低。

  1. 归并排序: 把200000分别放到10所学习,每个学校各自找排序,10个学校各自排序,找到最前面尖子,再合并。

  2. 快速排序:

  • 如果我们按几个分数线划分, 小于60,大于等于60 。
  • 然后在60- 100之间,再找90-100,60-90。
  • 这里其实可以忽略 小于60 和 60-90,因为我们只找,尖子,所以只关心90-100。

延展

  • 算法复杂度 一般有: N* N的平方 , 或者 N*logN 。为了让计算机专家专注于量级上的变化。忽略了前面N。只关注于N的平方或logN。
  • 根据高德纳的思想,使用微积分中的大写O来表示,所有同等复杂度的算法,在大O的概念下都是相等的。
  1. 冒泡排序是 O(n的平方),插入排序也是 O(n的平方)。是同一个量级。
  2. 归并排序和快速排序算法复杂度是logN。