点击上方“方志朋”,选择“置顶或者星标”
你的关注意义重大!
这是程序之路公众号的第一篇文章,最初是1月27号发布,后面发现有瑕疵,个别符号书写有误,并且堆排序以下标为1开始,对一些想学习排序的人造成了困扰,所以重新修正了这篇文章(修改了符号书写问题,堆排序改为下标从0开始),并且写了完整的测试代码,增加排序时间和排序结果打印,上传到Github,地址:https://github.com/cxzl/SortingTest,重新发布本文,希望对大家有所帮助。
注:
lgN在这里为1og2N简写
为了方便描述,本文默认用int类型比较,从小到大排序
本文排序算法以java语言实现
本文的排序都是比较排序
比较次数和赋值和交换次数有的排序不好分析,可能不准确
一.插入排序
对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
从第一个元素开始,该元素认为已经被排序;
取出下一个元素,在已排序的元素序列中从后向前扫描;
如果已排序元素大于新元素,新元素继续比较前一个元素,直到找到已排序的元素小于或者等于新元素的位置;
将新元素插入到该位置后;
重复步骤2~4。
java实现
public static void insertionSort(int[] a){
int insertIndex,insertElement;
for(int i = 1; i < a.length; i++){
//外层循环,默认第一个元素有序,从第二个元素开始,时间复杂度N
insertIndex = i - 1; //插入的位置,默认有序数列的最后一个元素的位置
insertElement = a[i]; //新插入的元素,默认外层循环的元素
while(insertIndex >= 0 && a[insertIndex] > insertElement){
//内层循环,只要新元素比待插入位置的元素小就继续,时间复杂度N
a[insertIndex + 1] = a[insertIndex]; //比待插入元素大的元素后移一位
insertIndex--; //插入位置前移一位
}
a[insertIndex + 1] = insertElement; //内层循环结束,把新元素放到插入位置后面
}
}
插入排序为两层循环嵌套,时间复杂度O(N2),插入排序的while循环是先比较,移动待插入的位置,循环结束才真正交换数据位置。这里需要注意,常用的for循环嵌套进行插入排序会每次比较都和前面元素交换直到插入到待插入位置,上面的内循环用while寻找待插入位置,把其他元素后移的算法更合理,每次插入只一次进行一次交换。
因插入排序每次只比较相邻一位数据,对于逆序较多的数组效率低,衍生算法希尔排序,会大幅加快逆序交换,后面详细介绍。
二.选择排序
在未排序序列中找到最小元素,放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾,循环直到所有元素均排序完毕。
初始状态:无序区为R[1..n],有序区为空;
第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n]。该趟排序从当前无序区中选出最小的记录 R[k],将它与无序区的第1个记录R[i]交换,使R[1..i]和R[i+1..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
循环n-1次,排序完成。
java实现
public static void selectionSort(int[] a){
int minIndex,temp;
for(int i = 0; i < a.length - 1; i++){
//外层循环,从无序区第一个元素开始到数组倒数第二个元素,时间复杂度N
minIndex = i; //每次外层循环假设无序区第一个元素是最小元素
for(int j = i + 1; j < a.length; j++){
//内层循环,从假设的最小元素的后一个位置开始,到数组最后一个元素,时间复杂度N
if(a[j] < a[minIndex]){
//判断内层循环的元素是否小于假设的最小元素
minIndex = j; //如果比最小元素小,标记该元素的位置为新的最小元素的位置,内层循环完毕,会找出无序区的最小值
}
}
temp = a[i];
a[i] = a[minIndex];
a[minIndex] = temp; //无序区真正最小值和第一个元素交换位置,下一次循环无序区从下一个值开始
}
}
选择排序为两层for循环嵌套,内层循环始终去找最小值,放到最前面。交换次数比冒泡排序少很多,所以实际执行效率比冒泡排序快。
衍生算法,双向选择排序(每次循环,同时选出最大值放在末尾,最小值放在前方),可以提高选择效率。
三.冒泡排序
重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换
初始状态:无序区为R[1..n],有序区为空&