大家好,我是烤鸭:
今天分享一下基础排序算法之直接插入排序。
1. 直接插入排序:
原理:假设前面的数为有序数列,然后有序数列与无序数列的每个数比较,我们可以从右向左比较
思路:从第2个数开始,和1比较。这样前2个有序。
第3个和前2个比较,这样前3个有序。(如果是最小的,则第3个元素处在第1个位置,后面的元素后移1。)
第4个和前3个比较,同上。
直到第 n 个元素 和 前 n-1 个比较。
代码实现:
/*** 直接插入排序* directInsertSort** @param array 时间复杂度,O的n^2* 直接插入排序就是我们假设前面的数为有序数列,然后有序数列与无序数列的每个数比较,我们可以从右向左比较* 当 array[i]<=array[j]=*/public void directInsertSort(int[] array) {long nowTime = System.currentTimeMillis();int tem = 0;for (int i = 1; i < array.length; i++) {int j = i - 1;tem = array[i];for (; j >= 0 && array[j] > tem; j--) {array[j + 1] = array[j];//将大于array[i]的数整体后移一单位}array[j + 1] = tem;}System.out.println("直接插入排序,花费时间(s):" + ((System.currentTimeMillis() - nowTime) / 1000.0) + "s");}
2. 折半插入排序(优化):
思路:
其实和直接插入排序是类似的,只是在遍历元素的时候采用的是二分法,直插采用的是顺序遍历。
取 temp 作为当前元素,
begin从0开始,end到数组最后一个元素。
如果temp < 中间值,begin从中间值+1继续,否则 end 变为 end - 1 继续,
begin 到 i 整体后移。
如图:(图片来源 http://www.cnblogs.com/chengxiao/p/6103002.html)
代码实现:
/*** 折半插入排序* @param source* halfInsertSort** @param source 时间复杂度,O的n^2* 折半插入排序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次数,* 因此速度比直接插入排序算法快,但记录移动的次数没有变,所以折半插入排序算法的时间复杂度仍然为O(n^2),* 与直接插入排序算法相同*/public static void halfInsertSort(int[] source) {long nowTime = System.currentTimeMillis();int size = source.length;for (int i = 1; i < size; i++) {// 拿出来int temp = source[i];int begin = 0; // 标记排好序的数组的头部int end = i - 1; // 标记排好序数组的尾部// 只要头部一直小于尾部,说明temp还在2个标记范围内while (begin <= end) {// 取2个标记的中间数据的值int mid = (begin + end) / 2;// 比较,若比中间值大,则范围缩小一半if (temp > source[mid]) {begin = mid + 1;// 否则,范围也是缩小一半} else {end = mid - 1;}// 循环结束时,end<begin,即i应该插入到begin所在的索引}// 从begin到i,集体后移for (int j = i; j > begin; j--) {source[j] = source[j - 1];}// 插入isource[begin] = temp;}System.out.println("折半插入排序,花费时间(s):" + ((System.currentTimeMillis() - nowTime) / 1000.0) + "s");}
3. shell排序
思路:
Shell排序也是对直接插入排序的改进。它实质上是一种分组插入方法。
下面希尔排序的步长选择都是从n/2开始,每次再减半,直到最后为1。
时间复杂度 : O(nlog2^n)
/*** 希尔排序* 针对直接插入排序的下效率问题,有人对次进行了改进与升级,这就是现在的希尔排序。* 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。* 首先确定分的组数。* 然后对组中元素进行插入排序。* 然后将length/2,重复1,2步,直到length=0为止。* @param arr*/public void shellSort(int [] arr){long nowTime = System.currentTimeMillis();int len=arr.length;//单独把数组长度拿出来,提高效率while(len!=0){len=len/2;for(int i=0;i<len;i++){//分组for(int j=i+len;j<arr.length;j+=len){//元素从第二个开始int k=j-len;//k为有序序列最后一位的位数int temp=arr[j];//要插入的元素/*for(;k>=0&&temp<arr[k];k-=len){arr[k+len]=arr[k];}*/while(k>=0&&temp<arr[k]){//从后往前遍历arr[k+len]=arr[k];k-=len;//向后移动len位}arr[k+len]=temp;}}}System.out.println("希尔排序,花费时间(s):" + ((System.currentTimeMillis() - nowTime) / 1000.0) + "s");}
耗时对比:
10W 条随机 数据 运行如图:
可以看出希尔排序时间明显(比直插排序和折半排序)缩短。折半排序和直插排序时间差不多。
50W 条随机 数据 运行如图:
可以看出希尔排序时间明显(比直插排序和折半排序)缩短。折半排序和直插排序时间差不多。
100W 条随机 数据 运行如图:
可以看出希尔排序时间明显(比直插排序和折半排序)缩短。折半排序比直插排序耗时更多。
总结:
直接插入排序写法比较简单,平均时间复杂度为:O(n^2) 。
折半插入排序,平均时间复杂度为:O(n^2) 。
希尔排序,平均时间复杂度为:O(nlog2^n) 。
各种排序方法比较:
更多排序算法:
冒泡排序 : https://blog.csdn.net/Angry_Mills/article/details/81057900