先说重点:
1.最大的区别就是内层循环的次数
2.插入排序的内层循环在插入的过程中不是真的把整体向后挪出一个空再插入值,而是那个待插入值从后面一个一个往前拱到该去的位置,然后发现前面拱不动了停下,下一个值开始从后面拱
一开始我觉得这两个算法的代码特别像,有一些博客抄来抄去也没写对,然后看了下面这个网站豁然开朗,👉这个网页👈可视化了常见排序算法,看完还不明白再看我的拙见。
很多教程都讲插入排序是像打扑克时候一样直接把几张牌往后挪然后插进去,这太有迷惑性了,实际上算法是一张一张往前挪
举个例子
比如手里有 1,2,6,8,9五张牌已经排好了,抓到一张3怎么办,
我们常以为是一步到位
1, 2,6,8,9,3
👇
1,2,3,6,8,9
---------------------------------------------------------分割线-------------------
其实代码里是
1, 2,6,8,9,3
👇
1, 2,6,8,3,9
👇
1, 2,6,3,8,9
👇
1, 2,3,6,8,9
这就是插入排序实际上的内层循环。
那么问题来了,这不是冒泡排序吗?
不是! 结果看肯定是一样的,但冒泡排序会有最后两步,
-
3是否小于2?如果是,那么交换位置
-
2是否小于1?如果是,那么交换位置
而插入排序不会有这两步,所以我们到后面会发现插入排通常比选择排序快很多因为少了很多步比较(应该是这样吧0.0)
并且要明确的一点:冒泡排序中等待被比较的数组,是未经排序的,而插入排序中等待被比较的数组是上一轮排序完的。换句话说“插入排序相当于我已经排好扑克了,从后面找到第一个比我手里小的,那前面的都是排过序的肯定更小,不用往前看了。但冒泡排序不是,这个比我手里的小,可能下一个比我手里的大,我得继续比到头。”
我的理解:
冒泡循环内层,比较次数是固定的,是一定要从这一头比较到另一头的
而插入排序,通常不需要比较到另一头就可以break跳出这一内层循环,开始下一内层循环
————————————————————————————————————————
直接看代码,冒泡循环
package SORTS;
import java.util.Arrays;
public class maopao extends tool_method {
public static void maopao_method(Comparable[] arr) {
long startTime=System.nanoTime();
//=========================================================
for (int j = 0; j < arr.length; j++) {
for (int i = 0; i < arr.length -1 - j; i++) {
if (bigger(arr[i], arr[i + 1])) {
//bigger 函数自己写的就是判断第一个形参是否大于第二个形参
《《《《《《《《《《《《
exchange(arr, i, i + 1); 《《《《算法实现部分《《
《《《《《《《《《《《
//exchange 函数自己写的 第一个形参是数组,后两个参数是数组索引,交换两个数
}
}
}
//==========================================================
long overTime=System.nanoTime();
System.out.print("共用时:");
System.out.println(overTime-startTime);
System.out.println(Arrays.toString(arr));
}
}
可以发现循环次数是固定的,无论比较结果是什么,后面的比较都要继续进行。
下面看插入排序标准写法
public class cahru extends tool_method {
public static void charu_method(Comparable[] arr) {
long startTime=System.nanoTime();
for (int i = 1;i<arr.length-1;i++){
for (int j = i-1;j<0;j--){
if (bigger(arr[j],arr[i])){
exchange(arr,i,j);//把这个元素放到那
}
else break; //插入排序在发现前面的比后面的小的时候就不会继续比较了,
// 这是和冒泡排序的区别,冒泡排序会从最后比较到最开始
}
}
long overTime=System.nanoTime();
System.out.print("共用时:");
System.out.println(overTime-startTime);
System.out.println(Arrays.toString(arr));
}
这个break是跳出循环,拉开和冒泡排序性能差距的关键
还有个插入排序的代码是我一开始自己想的,就是模拟了我们正常打牌直接插入位置,把其他牌向后移的操作。
就刚才说的这种
1, 2,6,8,9,3
👇
1,2,3,6,8,9
public static void charu2(Comparable[] arr){
long startTime=System.nanoTime();
//下面的形参名字看起来长其实都是拼音 别学我 我只是做测试时候怕自己记不住名字
for (int daicharu_index = 1;daicharu_index<arr.length-1;daicharu_index++){
for (int beicharu_index =daicharu_index-1;beicharu_index>0;beicharu_index--){
if (bigger(arr[beicharu_index],arr[daicharu_index])){
Comparable temp = arr[daicharu_index];
//下面这个for循环是向后挪一大块数组的操作
for (int xianghouyi = daicharu_index;xianghouyi<beicharu_index+1;xianghouyi--){
exchange(arr,xianghouyi,xianghouyi-1);
}
arr[beicharu_index+1] = temp;
}
}
}
long overTime=System.nanoTime();
System.out.print("共用时:");
System.out.println(overTime-startTime);
System.out.println(Arrays.toString(arr));
}
三个for循环显然比上面复杂
但是经过实测,还是比冒泡排序快
排序时间测试代码如下
public class sort_demo {
public static void main(String[] args) {
Integer[] array1 = {23,43,5,67,23,32,56,87,2,1};
Integer[] array2 = {23,656,89,7,46,89,5,13,5689,4165,8,2,89,56,9712,65
,89,487,6,2,86,87,6,226,89,741,1,6,481,236,6578,85};
System.out.println("原数组是");
System.out.println(Arrays.toString(array2));
System.out.println();
System.out.println("冒泡排序的结果是");
maopao.maopao_method(array2);
System.out.println();
System.out.println("选择排序的结果是");
xuanze.xuanze_method(array2);
System.out.println();
System.out.println("插入排序的方法:");
cahru.charu_method(array2);
System.out.println("我自己写的插入排序:");
cahru.charu2(array2);
}
}
结果如下
"C:\Program Files\Java\jdk-9\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=49927:D:\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVACODE\Project1\out\production\Project1 SORTS.sort_demo
原数组是
[23, 656, 89, 7, 46, 89, 5, 13, 5689, 4165, 8, 2, 89, 56, 9712, 65, 89, 487, 6, 2, 86, 87, 6, 226, 89, 741, 1, 6, 481, 236, 6578, 85]
冒泡排序的结果是
共用时:88600
[1, 2, 2, 5, 6, 6, 6, 7, 8, 13, 23, 46, 56, 65, 85, 86, 87, 89, 89, 89, 89, 89, 226, 236, 481, 487, 656, 741, 4165, 5689, 6578, 9712]
选择排序的结果是
共用时:42300
[1, 2, 2, 5, 6, 6, 6, 7, 8, 13, 23, 46, 56, 65, 85, 86, 87, 89, 89, 89, 89, 89, 226, 236, 481, 487, 656, 741, 4165, 5689, 6578, 9712]
插入排序的方法:
共用时:1100
[1, 2, 2, 5, 6, 6, 6, 7, 8, 13, 23, 46, 56, 65, 85, 86, 87, 89, 89, 89, 89, 89, 226, 236, 481, 487, 656, 741, 4165, 5689, 6578, 9712]
我自己写的插入排序:
共用时:19400
[1, 2, 2, 5, 6, 6, 6, 7, 8, 13, 23, 46, 56, 65, 85, 86, 87, 89, 89, 89, 89, 89, 226, 236, 481, 487, 656, 741, 4165, 5689, 6578, 9712]
进程已结束,退出代码 0
今天就学mo习yu这么多
明天继续