Algorithm:No1 Sorting
背景
1 排序的概念 |
排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。 其目的是将一组数据元素(或记录)的“无序”序列,重新排列成一个关键字“有序”的序列 排序算法,就是如何使得记录按照要求排列的方法。 |
2、排序的分类 |
内部排序:整个排序过程不需要访问外存便能完成,的排序问题
外部排序:参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成 |
内部排序简图&算法复杂度 |
3、排序的相关概念 |
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。 |
4、八大排序算法 八大排序算法均属于内部排序。按照策略来分类,大致可分为:交换排序、插入排序、选择排序、归并排序和基数排序。 |
C++和Python |
5、排序算法的标准 |
(a)计算的复杂度(最差、平均、和最好性能),依据列表(list)的大小(n)。 一般而言,好的性能是 O(nlogn),且坏的性能是 O(n^2)。对于一个排序理想的性能是 O(n)。 而仅使用一个抽象关键比较运算的排序算法总平均上总是至少需要 O(nlogn)。 (c)稳定度:稳定的排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序。 (d)一般的方法:插入、交换、选择、合并等等。交换排序包含冒泡排序和快速排序。插入排序包含希尔排序,选择排序包括堆排序等。 |
八大排序算法
1、冒泡排序(Bubble Sort) |
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 |
算法步骤
|
2、选择排序(Selection Sort) |
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 |
算法步骤 n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:
|
表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。 |
3、插入排序(Insertion Sort) |
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。 |
算法步骤 一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
|
4、希尔排序(Shell Sort) |
1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。 |
算法步骤 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
|
希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版)》的合著者Robert Sedgewick提出的。 |
5、归并排序(Merge Sort) |
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。 |
算法步骤
|
6、快速排序(Quick Sort) |
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 |
算法步骤 快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
|
7、堆排序(Heap Sort) |
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 |
算法步骤
|
8、计数排序(Counting Sort) |
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 |
算法步骤
|
算法分析 计数排序是一个稳定的排序算法。当输入的元素是 n 个 0到 k 之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k),其排序速度快于任何比较排序算法。当k不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。 |
9、桶排序(Bucket Sort) |
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。 |
算法步骤
|
算法分析 桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。 |
10、基数排序(Radix Sort) |
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。 |
算法步骤
|
算法分析 基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要O(n)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。 基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。 |