您的位置:首页 > 其它

几种经典排序算法的总结

2011-02-10 22:24 211 查看
假期即将结束,用最后这两天温习一下几种经典排序算法,总结一下,如有错误,请不吝指出:

1.基本概念:
1).稳定排序:当待排元素中有相同元素时,排序完后这些相同元素的相对位置与原来一致。
例如『1a,2a,5,4,1b,3,2b』排序完后『1a,1b,2a,2b,3,4,5』
2).原地排序:指排序时只需要使用到固定大小的临时空间,不需要使用与元素个数或元素类型相关大小的额外空间。

2.排序分类:
1).按排序方式分:
插入排序:直接插入排序,希尔排序;
交换排序:快速排序,冒泡排序;
选择排序:直接选择排序,堆排序;
归并排序:归并排序;
分配排序:桶排序,基数排序;
2).按一般平均时间复杂度分:
O(n2):直接插入排序,冒泡排序,直接选择排序;
O(nlg(n)):快速排序,堆排序,归并排序;
O(n1+a),0<a<1:希尔排序;
O(n):桶排序,基数排序;

假设待排数组为R[1...n],类型为简单int型,取值为[1, 100],从小到大排序。

3.直接插入排序:

3.1基本思想:把数组分为无序区和有序区,从无序区取出一个元素,插入到有序区中。排序开始时,有序区为R[1],无序区为R[2...n],选择R[2],插入到R[1]之前(之后),此时R[1,2]为有序区,R[3...n]为无序区。继续这个步骤,直到R[1...n]都为有序区,排序完成。

3.2 关键点:查找插入的位置,在查找时,可以利用临时变量保存待排元素,然后依次向后移动比待排元素大的元素,为它留出位置。

3.2 算法分析:原地排序,稳定排序,在待排数组基本有序时比较次数少,效率较好,平均时间复杂度O(n2)。

4.冒泡排序:

4.1基本思想:每一趟“冒泡”过程,通过比较和交换把最大的元素移动到R
。排序开始时,比较R[1]和R[2],如果R[1] > R[2],交换R[1]和R[2],然后比较R[2]和R[3],如果R[2] < R[3],继续比较R[3]和R[4],以此类推到R
,完成第一趟冒泡,此时R
为最大元素。然后开始第二趟从R[1]到R[n-1]的冒泡,第三趟...直到第N-1趟,R[1]肯定是最小元素,排序完成。

4.2关键点:相邻元素的比较与交换,以及最后冒泡的终点为n, n-1, n-2...到2,如果每次都冒泡到n,排序后元素为从大到小。

4.3算法分析:原地排序,稳定排序,在待排数组基本有序时交换少,效率交好,平均时间复杂度O(n2)

5.直接选择排序:

5.1基本思想:同样分为无序区和有序区,每一次选择,都选择当前无序区中最小的元素,并与无序区的第一个元素交换,然后该元素所在位置变为有序区。排序开始时,R[1...n]为无序区,比较所有n个元素,找到最小值R[k],与R[1]交换,此时R[1]为有序区,R[2...n]为无序区。然后继续在无序区中查找最小元素,直到有序区为R[1...n],排序完成。

5.2关键点:跟踪记录当前找到的最小元素的值与位置,完成查找后,与无序区的第一个元素交换。

5.3算法分析:原地排序,稳定排序,不管待排数组是否基本有序,算法每次都要比较无序区的所有元素,平均时间复杂度为O(n2)

6.快速排序:

6.1基本思想:分治法的思想,首先选择一个基准元素R[k](设其排序后的位置为m),然后遍历所有待排元素,将比基准元素小的元素放在其左边R[1...m],比它大的元素放在其右边R[m+1...n],形成R[1...m]R[m]R[m+1...n]的布局,然后进一步分别对左,右两边调用快速排序算法进一步排序。

6.2关键点:首先是基准元素的选择,一般选择第一个元素或最后一个元素,也可以使用概率算法随机选择一个元素;其次是数组是否越界的判断,注意在R[1,2]R[3]R[4...n]或R[1...n-3]R[n-2]R[n-1,n]等特殊边界情况下的数据交换和判断,防止越界。

6.3算法分析:目前大家比较喜欢的排序方法,原地排序,稳定排序,当时当待排数据基本有序时,反而效率下降,在最坏情况下时间复杂度达到O(n2),但可以用概率算法随机化,平均时间复杂度O(nlg(n))

7.堆排序:

7.1基本思想:
将待排数组看成一棵完全二叉树的遍历,即R[1]是树根,R[2]和R[3]是R[1]的孩子,R[4]和R[5]是R[2]的孩子,以此类推,R[1...n]可以构造为一棵完全二叉树。
堆的概念:分为大根堆和小根堆,大根堆R[i] > R[2i]且R[i] > R[2i+1],小根堆R[i] < R[2i]且R[i] < R[2i+1],从树的角度看就是大根堆的任意父节点的值,都比其两个孩子节点大,小根堆反之。



算法通过构造大根堆来获得当前最大元素,每次的最大元素都处于R[1],即树根位置。第一次构造后,当前最大元素处于R[1],然后交换R[1]与最后一个元素R
。此时R
为有序区,R[1...n-1]为无序区。第二次构造堆从R[1...n-1]中构造,然后交换R[1]和R[n-1],以此类推。

7.2关键点:每次比较需要从k无序区最后一个元素R[k]到R[2],分别与各自父节点比较,即R[(k - 1)/2],并保证R[(k - 1) / 2] > R[k],从而完成每次的堆构造。


7.3算法分析:原地排序,非稳定排序,堆排序是选择排序的优化,选择排序每次都要比较所有剩余的元素,做了很多重复工作,堆排序在每次构造堆时,都会调整堆,使得后面的构造更加快速,时间复杂度为O(nlg(n))。

8.归并排序:

8.1算法思想(2路归并):有R[1...m]和R[m+1...n]两个已经排序好的序列,有临时序列T[1...n],从R[1...m]和R[m+1...n]的开头R[1]和R[m+1]开始,选择较小的元素放入T[1],如果R[1]较小,则接下来比较R[2]和R[m+1],选择较小的放入T[2],以此类推,比较完R[1...m]或R[m+1...n],最后把另一个未使用完的序列接着放到T[1...n]中。

与快速排序类似,但是归并是自底向上,从相邻的2个元素的排序归并,到相邻的2路共4个元素的归并,最后到2路共n个元素的归并。

8.2关键点:归并时,某一路剩余未归并的元素要接到临时序列的后面。


8.3算法分析:非原地排序,稳定排序,在最后一次归并时空间复杂度为O(n),时间复杂度为O(nlg(n))

9.希尔排序:

9.1算法思想:按步长分阶段排序。步长为d,将所有距离为d的元素划分为一组,在组内进行插入排序。不断减少d值(可以d/=2),最后在d=1阶段完成后,排序完成。

9.2关键点:步长d最后必须为1,保证所有元素都在同一组,完成排序。注意元素个数无法整除d时,分组边界的判断。

9.3算法分析:原地排序,非稳定排序,是插入排序的优化,每阶段只需完成d次的插入排序,每次数据量为n/d,时间复杂度为 O(n1+a),0<a<1,a跟d的长度选择有关。

10.桶排序:

10.1算法思想:算法适用于已知元素关键值取值范围的数组。设建立100个“桶”,遍历所有元素R[1...n],当R[k] == v时,把R[k]放入第v个桶,在所有的元素分配完后,从第一个桶到最后一个桶串起来,就是排序好的数组。

10.2关键点:元素关键值取值范围必须知道,否则可能需要无限个“桶”。“桶”可用链表实现,元素R[k]放入“桶”v可实现为R[k]接到链表v的后面。

10.3算法分析:稳定排序,使用链表时,不需要额外空间,但仍需要申请链表头作为“桶”,为非原地排序。只需要遍历分配R[1...n],然后收集,时间复杂度都为O(n),因此算法时间复杂度为O(n)

11.基数排序:

11.1算法思想:桶排序的升级,对于有多个关键值类型的元素数组,分别对每种关键值类型进行桶排序。关键字可以是数值,可以是字符串。例如数字排序可以对其个位,十位,百位...都分别进行桶排序,桶个数为数值取值0~9共10个;如果是字符串,可以对其每一位的字符,进行桶排序,桶个数为字符的取值a~z共26个。

11.2关键点:关键值的划分,关系到桶的个数,也关系到所需桶排序的次数。

11.3算法分析:稳定排序,非原地排序,每个关键字的桶排序在n的时间内完成,共有m个关键字,算法时间复杂度为O(m * n)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: