The Algorithms of sort - Python

https://github.com/TheAlgorithms/Python;本文内容出自于此。php

Sort Algorithms(排序算法)

Bubble(冒泡)

维基百科:冒泡排序英语:Bubble Sort,台湾另一种译名为:泡沫排序)是一种简单的排序算法。它重复地走访过要排序的序列,一次比较两个元素,若是他们的顺序错误就把他们交换过来。走访数列的工做是重复地进行直到没有再须要交换,也就是说该数列已经排序完成。这个算法的名字由来是由于越小的元素会经由交换慢慢“浮”到数列的顶端。git

算法描述

  1. 比较相邻的元素。若是第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素做一样的工做,从开始第一对到结尾的最后一对。这步作完后,最后的元素会是最大的数。
  3. 针对全部的元素重复以上的步骤,除了最后一个。
  4. 持续每次对愈来愈少的元素重复上面的步骤,直到没有任何一对数字须要比较。

因为它的简洁,冒泡排序一般被用来对于程序设计入门的学生介绍算法的概念。github

特性:算法

最差时间复杂度:O(n^2)数组

最好时间复杂度:O(n)架构

平均时间复杂度:O(n^2)less

Python代码实现:ide

View Code

输出结果:final: [2, 4, 8, 13, 14, 26, 27, 28, 33, 35]svg


 


Insertion(插入)

维基百科:插入排序英语:Insertion Sort)是一种简单直观的排序算法。它的工做原理是经过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,一般采用in-place排序(即只需用到O(1)的额外空间的排序),于是在从后向前扫描过程当中,须要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。oop

算法描述

通常来讲,插入排序都采用in-place在数组上实现。具体算法描述以下:

  1. 从第一个元素开始,该元素能够认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 若是该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤2~5

若是比较操做的代价比交换操做大的话,能够采用二分查找法来减小比较操做的数目。该算法能够认为是插入排序的一个变种,称为二分查找插入排序

算法复杂度

若是目标是把n个元素的序列升序排列,那么采用插入排序存在最好状况和最坏状况。最好状况就是,序列已是升序排列了,在这种状况下,须要进行的比较操做需(n-1)次便可。最坏状况就是,序列是降序排列,那么此时须要进行的比较共有{\displaystyle {\frac {1}{2}}n(n-1)}次。插入排序的赋值操做是比较操做的次数减去(n-1)次,(由于n-1次循环中,每一次循环的比较都比赋值多一个,多在最后那一次比较并不带来赋值)。平均来讲插入排序算法复杂度为O(n^2)。于是,插入排序不适合对于数据量比较大的排序应用。可是,若是须要排序的数据量很小,例如,量级小于千;或者若已知输入元素大体上按照顺序排列,那么插入排序仍是一个不错的选择。 插入排序在工业级库中也有着普遍的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序做为快速排序的补充,用于少许元素的排序(一般为8个或如下)。

特性:

最差时间复杂度:O(n^2)

最好时间复杂度:O(n)

Python代码的两种实现:

View Code
View Code

输出结果:final: [2, 4, 8, 13, 14, 26, 27, 28, 33, 35]


 


Merge(归并排序)

维基百科:归并排序英语:Merge sort,或mergesort),是建立在归并操做上的一种有效的排序算法,效率为O(n log n)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个很是典型的应用,且各层分治递归能够同时进行。

归并操做

归并操做(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操做。归并排序算法依赖归并操做。

迭代法

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  4. 重复步骤3直到某一指针到达序列尾
  5. 将另外一序列剩下的全部元素直接复制到合并序列尾

递归法

原理以下(假设序列共有n个元素):

  1. 将序列每相邻两个数字进行归并操做,造成floor(n/2)个序列,排序后每一个序列包含两个元素
  2. 将上述序列再次归并,造成floor(n/4)个序列,每一个序列包含四个元素
  3. 重复步骤2,直到全部元素排序完毕

特性:

最差时间复杂度:O(nlogn)

最好时间复杂度:O(n)

平均时间复杂度:O(n)

Python代码的实现:

View Code

 


Quick(快速排序)

 

 维基百科:快速排序英语:Quicksort),又称划分交换排序partition-exchange sort),一种排序算法,最先由东尼·霍尔提出。在平均情况下,排序n个项目要大O符号)O(nlogn)次比较。在最坏情况下则须要O(n^2)次比较,但这种情况并不常见。事实上,快速排序一般明显比其余O(nlogn)算法更快,由于它的内部循环(inner loop)能够在大部分的架构上颇有效率地被实现出来。

算法

 
快速排序采用“分而治之、各个击破”的观念,此为原地(In-place)分区版本。

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。

步骤为:

  1. 从数列中挑出一个元素,称为"基准"(pivot),
  2. 从新排序数列,全部比基准值小的元素摆放在基准前面,全部比基准值大的元素摆在基准后面(相同的数能够到任何一边)。在这个分区结束以后,该基准就处于数列的中间位置。这个称为分区(partition)操做。
  3. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法必定会结束,由于在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

在简单的伪代码中,此算法能够被表示为:

 function quicksort(q)
     var list less, pivotList, greater
     if length(q) ≤ 1 {
         return q
     } else {
         select a pivot value pivot from q
         for each x in q except the pivot element
             if x < pivot then add x to less
             if x ≥ pivot then add x to greater
         add pivot to pivotList
         return concatenate(quicksort(less), pivotList, quicksort(greater))
     }

特性:

最差时间复杂度:O(n^2)

最好时间复杂度:O(n)或O(nlogn)

平均时间复杂度:O(n^2)

Python代码的实现:

View Code

 


Selection(选择排序)

选择排序(Selection sort)是一种简单直观的排序算法。它的工做原理以下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而后,再从剩余未排序元素中继续寻找最小(大)元素,而后放到已排序序列的末尾。以此类推,直到全部元素均排序完毕。

选择排序的主要优势与数据移动有关。若是某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,所以对n个元素的表进行排序总共进行至多(n-1)次交换。在全部的彻底依靠交换去移动元素的排序方法中,选择排序属于很是好的一种。

特性:

最差时间复杂度:O(n^2)

最好时间复杂度:O(n^2)

平均时间复杂度:O(n^2)

Python代码的实现:

View Code

 


Shell(希尔排序)

维基百科:希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。

希尔排序是基于插入排序的如下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操做时,效率高,便可以达到线性排序的效率
  • 但插入排序通常来讲是低效的,由于插入排序每次只能将数据移动一位

算法实现

原始的算法实如今最坏的状况下须要进行O(n2)的比较和交换。V. Pratt的书对算法进行了少许修改,可使得性能提高至O(n log2 n)。这比最好的比较算法的O(n log n)要差一些。

希尔排序经过将比较的所有元素分为几个区域来提高插入排序的性能。这样可让一个元素能够一次性地朝最终位置前进一大步。而后算法再取愈来愈小的步长进行排序,算法的最后一步就是普通的插入排序,可是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

假设有一个很小的数据在一个已按升序排好序的数组的末端。若是用复杂度为O(n2)的排序(冒泡排序插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,因此小数据只需进行少数比较和交换便可到正确位置。

一个更好理解的希尔排序实现:将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法自己仅仅对原数组进行排序(经过增长索引的步长,例如是用i += step_size而不是i++)。

例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],若是咱们以步长为5开始进行排序,咱们能够经过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10

而后咱们对每列进行排序:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45

将上述四行数字,依序接在一块儿时咱们获得:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,而后再以3为步长进行排序:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45

排序以后变为:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94

最后以1步长进行排序(此时就是简单的插入排序了)。

特性:

最差时间复杂度:O(n^2)

最好时间复杂度:O(n)

平均时间复杂度:取决于步长

Python代码的实现:

View Code

 


 

冒泡,插入,选择排序的平均时间复杂度比较:

相关文章
相关标签/搜索