排序算法 总结&思考(一)
2013-05-28 16:33
246 查看
--前言
排序算法是最基本而且最基础的问题,特别是在C语言中。在C++,JAVA等面向对象设计中通常会提供相应的库函数,使得编程者不必要考虑详细的设计处理,调用即可。即便如此,这一问题仍然是面试笔试中必然涉及到的话题。写一篇自己对各种排序算法的认识,作为以后找工作的基础吧
1.简单易懂 の 直接插入排序(InsertSort)
谈到排序,日常接触最多的例子就是扑克牌的顺序调整,因为分配到的是洗匀的卡牌,所以需要对此进行排序,方便后续出牌
(这里只考虑按int大小排序,至于实际扑克点数大小,个人打牌习惯,不在范围之内~~)
我们一般会从左至右,依次把每一张非顺序的牌放在左边正确的位置,比如5会插在4和6之间,依此进行至结束。这种方式最直观最易理解,操作也最方便
算法来源于现实,而高于现实--计算机中实际应用往往比现实模型要复杂
一般使用数组进行排序,那么我们的“插入操作”就不仅仅是把卡牌插在两张卡的缝隙之间这么简单。数组是固定的,要在中间插入一个数据需要把后面所有数字平移一位!这是插入排序速度的瓶颈
这一瓶颈使得在平均情况和最坏情况下,时间复杂度都是O(n²)。值得高兴的是,在最好的情况下(已经排好序),时间复杂度为O(n),所以在基本有序的序列中,使用直接插入排序还是比较有效的
直接插入排序的伪代码:
2. 创造有序 の 希尔排序(ShellSort)
基于直接插入排序在基本有序的情况下表现较好,一种改进的插入排序算法--希尔排序诞生。原理是先通过数次小集合的顺序调整,使得最后整个序列排序时达到基本有序的状态,减少移动元素的开销
D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成.
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。关于增量算法的选择请参考更多资料
希尔排序由于增量选取和控制方式的不同,代码实现也不尽相同。下面是一个简单的C语言实现:
这种改进使得希尔排序时间复杂度可以达到O(nlogn)-O(n²)之间。根据增量的不同,最佳平均情况时间复杂度可以达到O(n^1.3),最好和最坏情况同直接插入排序(O(n),O(n²)),在这里只提及这种思想即止(平常应用中大量采用快排,shell排序因为流程控制复杂些,比较少见)
3 一目十行 の 简单选择排序(SelectSort)
有趣的是,逻辑上“简单”一词在现实中和计算机中的影响大不一样。生活中,我们一般会选择“怎么简单怎么做”,还是以扑克牌为例子,有些人会从手中数量不多的牌中,从小到大依次选择并取出牌,放置在新的位置进行排序。而在计算机中,这一逻辑非常清晰简单的算法却被评价为效率最低的算法
原因很简单:思维方式&应用场景决定了这点。计算机没有"一目十行"的能力,无法从中快速挑出点数最小的牌,并且,牌的总数量一般比较少,如果要从上百张牌中一个个挑选,恐怕超人才有这种速度吧~
4 快速稳定 の 堆排序(HeapSort)
堆排序已经在前面一篇文章中介绍过了,所以这里就不再多言。堆排序也是基于“选出”最小元素的选择排序类,只是因为它建立了独有的数据结构,使得每次操作的开销平均到O(logn)级别,是一个较优的排序算法
需要注意的是,标题中的“稳定”并不是指的通常说称排序算法的稳定性,而是说堆排序在任何情况下时间复杂度都达到O(nlogn)。排序算法的稳定性也很好理解,相同元素在排序过程中是否会保证顺序不变(某些特殊情况可能会用到这点),如果是,则称算法是稳定的。除直接插入排序外,其他三个算法都是不稳定的
插入排序类和选择排序类思想比较简单,后面将介绍另4种应用较广的其他类算法
(未完待续)
排序算法是最基本而且最基础的问题,特别是在C语言中。在C++,JAVA等面向对象设计中通常会提供相应的库函数,使得编程者不必要考虑详细的设计处理,调用即可。即便如此,这一问题仍然是面试笔试中必然涉及到的话题。写一篇自己对各种排序算法的认识,作为以后找工作的基础吧
1.简单易懂 の 直接插入排序(InsertSort)
谈到排序,日常接触最多的例子就是扑克牌的顺序调整,因为分配到的是洗匀的卡牌,所以需要对此进行排序,方便后续出牌
(这里只考虑按int大小排序,至于实际扑克点数大小,个人打牌习惯,不在范围之内~~)
我们一般会从左至右,依次把每一张非顺序的牌放在左边正确的位置,比如5会插在4和6之间,依此进行至结束。这种方式最直观最易理解,操作也最方便
算法来源于现实,而高于现实--计算机中实际应用往往比现实模型要复杂
一般使用数组进行排序,那么我们的“插入操作”就不仅仅是把卡牌插在两张卡的缝隙之间这么简单。数组是固定的,要在中间插入一个数据需要把后面所有数字平移一位!这是插入排序速度的瓶颈
这一瓶颈使得在平均情况和最坏情况下,时间复杂度都是O(n²)。值得高兴的是,在最好的情况下(已经排好序),时间复杂度为O(n),所以在基本有序的序列中,使用直接插入排序还是比较有效的
直接插入排序的伪代码:
for i = [1,n) t = x[i] for(j=i; j>0 && x[j-1]>t; j--) x[j] = x[j-1] x[j] = t
2. 创造有序 の 希尔排序(ShellSort)
基于直接插入排序在基本有序的情况下表现较好,一种改进的插入排序算法--希尔排序诞生。原理是先通过数次小集合的顺序调整,使得最后整个序列排序时达到基本有序的状态,减少移动元素的开销
D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成.
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。关于增量算法的选择请参考更多资料
希尔排序由于增量选取和控制方式的不同,代码实现也不尽相同。下面是一个简单的C语言实现:
const int n = 5; int i, j, temp; int gap = 0; int a[] = {5, 4, 3, 2, 1}; while (gap<=n) { gap = gap * 3 + 1; } while (gap > 0) { for ( i = gap; i < n; i++ ) { j = i - gap; temp = a[i]; while (( j >= 0 ) && ( a[j] > temp )) { a[j + gap] = a[j]; j = j - gap; } a[j + gap] = temp; } gap = ( gap - 1 ) / 3; }
这种改进使得希尔排序时间复杂度可以达到O(nlogn)-O(n²)之间。根据增量的不同,最佳平均情况时间复杂度可以达到O(n^1.3),最好和最坏情况同直接插入排序(O(n),O(n²)),在这里只提及这种思想即止(平常应用中大量采用快排,shell排序因为流程控制复杂些,比较少见)
3 一目十行 の 简单选择排序(SelectSort)
有趣的是,逻辑上“简单”一词在现实中和计算机中的影响大不一样。生活中,我们一般会选择“怎么简单怎么做”,还是以扑克牌为例子,有些人会从手中数量不多的牌中,从小到大依次选择并取出牌,放置在新的位置进行排序。而在计算机中,这一逻辑非常清晰简单的算法却被评价为效率最低的算法
原因很简单:思维方式&应用场景决定了这点。计算机没有"一目十行"的能力,无法从中快速挑出点数最小的牌,并且,牌的总数量一般比较少,如果要从上百张牌中一个个挑选,恐怕超人才有这种速度吧~
void SelectSort(SqList *L) { int i,j,min; for(i=1;i<L->length;i++) { min = i; for (j = i+1;j<=L->length;j++) { if (L->r[min]>L->r[j]) min = j; } if(i!=min) swap(L,i,min); } }因为每一个元素的选择都需要扫描剩下的所有元素,这种比较导致简单选择排序在任何情况下时间复杂度都是O(n²),运行起来可就不“简单”了
4 快速稳定 の 堆排序(HeapSort)
堆排序已经在前面一篇文章中介绍过了,所以这里就不再多言。堆排序也是基于“选出”最小元素的选择排序类,只是因为它建立了独有的数据结构,使得每次操作的开销平均到O(logn)级别,是一个较优的排序算法
需要注意的是,标题中的“稳定”并不是指的通常说称排序算法的稳定性,而是说堆排序在任何情况下时间复杂度都达到O(nlogn)。排序算法的稳定性也很好理解,相同元素在排序过程中是否会保证顺序不变(某些特殊情况可能会用到这点),如果是,则称算法是稳定的。除直接插入排序外,其他三个算法都是不稳定的
插入排序类和选择排序类思想比较简单,后面将介绍另4种应用较广的其他类算法
(未完待续)
相关文章推荐
- 排序算法 总结&思考(二)
- 【每日算法】排序算法总结(复杂度&稳定性)
- 排序算法总结&&java代码实现
- 2016实习生笔试&面试总结思考
- 【每日算法】排序算法总结(复杂度&稳定性)
- 面试中的 10 大排序算法总结-->http://write.blog.csdn.net/postedit?ref=toolbar
- 排序算法的总结,思考和优化
- 【转载】年终总结 & 算法数据的思考 & 结尾彩蛋
- 总结 & 思考 & 平常心
- 排序算法的思考和总结(一)-冒泡和选择排序
- (转载)年终总结 & 算法数据的思考 & 结尾彩蛋
- 排序算法终结总结<Java实现>
- 各种排序算法总结(基于数组)
- 泛形-->总结
- 黑马程序员—iOS- <项目笔记>UI控件常见属性总结(上)
- Project Charter,个人思考总结
- NoSuchMethodException: org.apache.hadoop.io.ArrayWritable.<init>问题解决总结
- 学生信息管理系统总结 之 "常见小问题"
- GDOI2017模拟10.31&11.01总结
- 面试中的排序算法总结