你们好,我是阿濠,今篇内容跟你们分享的是排序算法之插入排序,很高兴分享到segmentfault与你们一块儿学习交流,初次见面请你们多多关照,一块儿学习进步.
插入式排序属于内部排序法
,是对于欲排序的元素
以插入的方式
找寻该元素的适当位置
,以达到排序
的目的。.算法
1.把n个待排序的元素
当作为一个有序表和一个无序表
2.开始时有序表
中只包含一个元素
,无序表
中包含有n-1个元素
3.排序过程
中每次从无序表中取出第一个元素
,把它的排序元素依次与有序表元素进行比较
4.将它插入
到有序表中的适当位置
,使之成为新的有序表
。segmentfault
由一群牛,考试成绩分别是: 100,34,119,1
使用插入排序法
将其排成一个从小到大的有序数列。
数组
步骤思路:
1.把n个待排序的元素
当作为一个有序表和一个无序表
2.假设当前有序表
为待排序的第一个元素
,每次从无序表中取出第一个元素
,把它的排序元素依次与有序表元素进行比较
3.将它插入
到有序表中的适当位置
,使之成为新的有序表
。性能
//插入排序 public static void insertSort(int[] arr) { //使用逐步推导的方式来说解,便利理解 //第一轮{110,34,119,1}==>{34,101,119,1} //当前有序表包含一个元素为110 //待插入数便是无序表:34,119,1 第一轮为34 int interValue=arr[1];//arr[1]=34 int interIndex= 1 - 1;//即arr[1]前一个位置 //给insertVal找到插入的位置 //说明 //1. insertIndex >= 0保证在给insertVal找插入位置,不越界 //2. insertVal < arr[insertIndex] 待插入的数, 尚未找到插入位置 //3. 从小到大排序,则若34小于110,则须要让位 while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循环时,说明插入位置找到,insetIndex + 1 arr[interIndex +1 ] = interValue; System.out.println("第一轮排序结果:"); System.out.println(Arrays.toString(arr)); } 运行结果以下: 第一轮排序结果:[34, 110, 119, 1] //第二轮 interValue=arr[2]; interIndex=2 - 1; while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循环时,说明插入位置找到,insetIndex + 1 arr[interIndex +1 ] = interValue; System.out.println("第二轮排序结果:"); System.out.println(Arrays.toString(arr)); 运行结果以下: 第一轮排序结果:[34, 110, 119, 1] 第二轮排序结果:[34, 110, 119, 1] //第三轮 interValue=arr[3]; interIndex=3 - 1; while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循环时,说明插入位置找到,insetIndex + 1 arr[interIndex +1 ] = interValue; System.out.println("第三轮排序结果:"); System.out.println(Arrays.toString(arr)); 运行结果以下: 第一轮排序结果:[34, 110, 119, 1] 第二轮排序结果:[34, 110, 119, 1] 第三轮排序结果:[1, 34, 110, 119]
规律已经出来了,变化排序元素、比较交换
是类似
,改变的是从无序表中取出的元素
,即进行以下代码抽整:学习
//使用for循环来把代码进行简化 for(int i = 1; i<arr.length;i++){ int interValue=arr[i]; int interIndex= i - 1; //给insertVal找到插入的位置 //说明 //1. insertIndex >= 0保证在给insertVal找插入位置,不越界 //2. insertVal < arr[insertIndex] 待插入的数, 尚未找到插入位置 //3. 从小到大排序,则若34小于110,则须要让位 while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循环时,说明插入位置找到,insetIndex + 1 if(interIndex+1 !=i){ arr[interIndex +1 ] = interValue; } System.out.println("第"+(i)+"轮排序结果:"); System.out.println(Arrays.toString(arr)); } //运行结果以下: 第1轮排序结果:[34, 110, 119, 1] 第2轮排序结果:[34, 110, 119, 1] 第3轮排序结果:[1, 34, 110, 119]
1.最好的状况
,也就是要排序的表自己就是有序的
,此时只有数据比较
,没有数据移动
,时间复杂度为O(n)
。spa
2.最坏的状况
,即待排序的表是逆序的状况
,此时须要比较次数为:2+3+…+n=(n+2)(n-1)/2 次
,而记录移动的最大值也达到了(n+4)(n-1)/2次
. 3d
3.若是排序记录是随机的
,那么根据几率相同的原则,平均比较和移动次数约为 (n^2) / 4次
,所以,得出直接插入排序发的时间复杂度为O(n^2)
。code
能够看出一样的是时间复杂度blog
直接插入排序法
比冒泡和简单选择排序
的性能要好一些
。排序
直接插入排序是稳定的
,不会改变相同元素的相对顺序
。
二分(折半)插入
(Binary insert sort) 排序是一种在直接插入排序
算法上进行小改动
的排序算法
。其与直接排序算法最大的区别在于查找插入位置时使用的是二分查找的方式
,在速度上有必定提高。
步骤思路:
通常来讲,插入排序都采用in-place在数组上实现
。
一、从第一个元素开始
,该元素能够认为已经被排序
二、取出下一个元素
,在已经排序的元素序列中
二分查找到第一个比它大的数的位置
三、将新元素插入到该位置后
四、重复上述两步
假设插入数字:4
使用二分查找找到 mid
void BinInsertSort(int a[], int n) { int key, left, right, middle; for (int i=1; i<n; i++) { key = a[i];//当前认为被排序的数 left = 0; right = i-1;//当前认为被排序的数的右边 //将开始和结束的下标进行比较,若是不一致则遍历下一个 while (left<=right) { middle = (left+right)/2;//进行二分 //数组值比中间下标的数组值小,则在数组前一半中进行查找,即将end-1 if (a[middle]>key){ right = middle-1; } //若是而要计算的值比中间值大,则在数组后半段查找,即将start+1 else{ left = middle+1; } } for(int j=i-1; j>=left; j--) { a[j+1] = a[j]; } a[left] = key; } }
1.稳定
2.空间代价:O(1)
3.时间代价:插入每一个记录须要O(log i)比较
,最多移动i+1次
,最少2次
。最佳状况O(n log n),最差和平均状况O(n^2)
。
二分插入排序
是一种稳定的排序。
当n较大时
,总排序码比较次数比直接插入排序的最差状况好得多
,但比最好状况要差
,所元素初始序列已经按排序码接近有序时,直接插入排序比二分插入排序比较次数少
。
二分插入排序元素移动次数与直接插入排序相同
,依赖于元素初始序列
。