最近开始准备找实习了,参加了几场比试,发现考官对排序算法钟爱有加,总会碰到这方面的题目,但是自己又记不清楚了。回归课本,重新温习了一遍。为了方便以后复习用,大概的描述下各个排序算法的特点和思想。
冒泡排序:
两层循环,第一层,从头到尾比较当前元素与下一个元素,若大于(从小到大排序)则交换,循环结束最大元素跑到最后。再对剩下的n-1重复执行此操作
快速排序:
是对冒泡排序的改进,采用分治策略思想减少比较次数和移动次数增大移动距离来达到优化的效果。也称作:划分交换排序。
选取一个基值(通常为数组第一个值),设置两个指针,一个正向i,一个反向运动j,先从尾至头寻找小于基值的位置j,再从头至尾寻找大于基值的i,当i=j时停止,再把基值与停止处的值交换,记录当前位置k。再对start到k-1、k+1到end分别进行快排。(递归求解)
直接选择排序:
与冒泡排序类似,但是不同之处在于冒泡排序每次比较大于该值就交换,而对于直接选择排序而言,每一趟遍历发现大于时不是立即交换,而是更新最大值以及最大值的下标指针,在此趟遍历结束后再交换,因而极大地减少了交换的次数,从而得到了优化。
堆排序:
是对直接选择排序的改进,改进的着眼点:如何减少关键字之间的比较次数,若能利用每趟比较后的结果,也就是在找出关键字值最小记录的同时,也找出关键字较小的几率,则可以减少后面的选择中所用的比较次数,从而提高整个排序过程的效率。基本思想是:将待排序的数存放在最小堆(或最大堆)中。根节点即为最小值,移走根节点,有序地放入数组中,然后调整堆,使其保持最小堆状态,重复此过程直到堆为空。排序完成
(直接)插入排序:
基本思想是将待排序的数按照其关键字大小插入到已经排序好的数组中。
for i=0 to n-1 {
j= i ;
while ( j!=0 &&A[j]<A[j-1]) {
swap( A[j],A[j-1] );
j=j-1;
}
}
在直接插入排序中,当插入第i个记录时,前面的i-1个记录已经排序好了,在寻找插入位置时,可以用折半查找来代替顺序查找,从而减少比较次数,达到优化效果,称作折半插入排序
希尔排序(分组插入排序):
将整个待排的序列分成若干个子序列,在子序列中分别进行直接插入排序,然后再对全体记录直接插入排序。
如上图,同一种颜色的代表一类,d代表步长
(希尔排序开始时增量比较大,每个子序列中的记录个数较少,从而排序的速度较快;档增量较小时,虽然每个子序列中的记录较多,但是整个序列已经基本有序,排序速度也较快)
归并排序:
采用分治思想,将多个有序的序列归并为一个有序的序列
分配法排序(基数排序):
是一种基于多关键字的排序,将数据按照第一个关键字分布到不同的桶(箱、基数)中,然后桶排序,重复迭代
总结:
补充:
1、 桶排序:
对给定的1到10之间的所有数进行排序:
1) 建立一个A[11]数组,初始化为0;
2) 从头至尾的对待排序列进行扫描,为5时,A[5]中值加一,一次类推
3) 正向或反向遍历数组,当某个数组单元的值不为0时,输出相应个数的值
时间复杂度:O(n)
适应场景:当某一序列的的分布范围比较小并且密集时,具有很大的优越性
改进策略:当分布范围不是从0开始时,放入取出时可以相应的减加一个基值,例:100~140的分布,可以放到0~40的数组里,然后增加或减少一个基数
相似算法:位图、散列
2、 位图法:
快速的对7位的无重复的一千多万个号码进行排序,最大号码是19000000:
1) 声明19000000个二进制位,初始化为0(一个int含32位,可想而知,声明二进制位可以极大的缩短空间)
2) 遍历待排序的数组,对相应下标的二进制位处置一
3) 从头或尾循环输出二进制位为1的值
局限性:每一个数出现的频率不能 超过1(二进制位不是0就是1),并且要求数的分布比较集中