排序算法之冒泡、插入、选择排序

简介:

冒泡排序(Bubble Sort)是一种简单的排序算法,它通过依次比较相邻的两个元素,判断两个元素是否满足大小关系,如果不满足则交换两个元素,每一次冒泡会让至少一个元素移动到它应该在的位置,这样n次冒泡就完成了n个数据的排序工作。这个算法的排序过程与气泡从水中往上冒的情况很相似,故美其名曰:冒泡排序。
作者:geekymv
https://www.bilibili.com/read/cv8872800/
出处: bilibili

 

逻辑:

比较两个相邻的元素,将值大的元素交换到右边。(从小到大排列)

代码实现:

例如数据如下:

1,23,2,12,11,2,5
排序后结果:
1,2,2,5,11,12,23

首先遍历数据集合:

public static void insertinSort2(int[] intArray){
        // 因为第一个不参与冒牌默认已经冒泡
        for (int i = 1; i < intArray.length; i++) {
            
        }
        System.out.println(Arrays.toString(intArray));
    }

然后根据拿到的数据遍历已经排好的数据,进行对比,如果小于则交换排列后的位置。代码如下:

// 先找大的放到最后面
        for (int i = 0; i < intArray.length-1; i++) {
            for (int j=0; j <intArray.length-1 ; j++) {
                if(intArray[j]>intArray[j+1]){
                    int a1 = intArray[j];
                    intArray[j]= intArray[j+1];
                    intArray[j+1]=a1;
                }
            }
            System.out.println(Arrays.toString(intArray));
        }

执行代码后发现有多条重复排序,也就是多余对比。

[1, 2, 12, 11, 2, 5, 23]
[1, 2, 11, 2, 5, 12, 23]
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]

打印结果如上。

首先把选取一个元素放到首位,然后和剩余数组数据进行遍历与该值比较。如果该值后面的数大于该数字,则进行位置互换。

我们可以把打印数组的输出语句放在第二个for循环,可以看到进行了多少次遍历。

// 先找大的放到最后面
        for (int i = 0; i < intArray.length-1; i++) {
            for (int j=0; j <intArray.length-1 ; j++) {
                if(intArray[j]>intArray[j+1]){
                    int a1 = intArray[j];
                    intArray[j]= intArray[j+1];
                    intArray[j+1]=a1;
                }
                System.out.println(Arrays.toString(intArray));
            }
        }

如上可以看到遍历了 array.length-1 * array.length-1 次。其实我们在冒泡的时候,每次冒泡之后都会完成一个数的排列。也就是后面冒泡不需要全量,是递减的进行冒泡。所以代码可以这样改。

// 先找大的放到最后面
        for (int i = 0; i < intArray.length-1; i++) {
            for (int j=0; j <intArray.length-1-i ; j++) {
                if(intArray[j]>intArray[j+1]){
                    int a1 = intArray[j];
                    intArray[j]= intArray[j+1];
                    intArray[j+1]=a1;
                }
                System.out.println(Arrays.toString(intArray));
            }
        }

第二次遍历的时候,减去i,也就是已经冒泡排序的个数。这样我数组长度为7,冒泡次数就是6,5,4,3,2,1共21次。比之前36次少了15次。

打印后结果为:

[1, 23, 2, 12, 11, 2, 5]
[1, 2, 23, 12, 11, 2, 5]
[1, 2, 12, 23, 11, 2, 5]
[1, 2, 12, 11, 23, 2, 5]
......
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]
[1, 2, 2, 5, 11, 12, 23]

还有另外一个问题,也就是排序成功后,依然在进行排序。如上打印所示,最后几次排序结果是一样的。也就是重复排序了。

我们可以加个标识,是否交换元素,如果没有交换元素则代表排序成功了。就不必进行排序了。代码如下:

for (int i = 0; i < intArray.length-1; i++) {
            boolean flag = false;
            for (int j=0; j <intArray.length-1-i ; j++) {
                if(intArray[j]>intArray[j+1]){
                    int a1 = intArray[j];
                    intArray[j]= intArray[j+1];
                    intArray[j+1]=a1;
                    flag = true;
                }
                System.out.println(Arrays.toString(intArray));
            }
            if(!flag){
                break;
            }
        }

打印之后可以看到排序次数明显少了三次。这个只是减少外层循环次数。还是多出来的打印是因为内存需要遍历整个数组。

 

 

 

 

 

 插入排序

for (int i = 1; i < A.length; i++) {
            int c = A[i];
            int j = i;
            System.out.println("~~~~~"+ c);
            for (; j >0 && A[j-1]>c ; j--) {
                    A[j]=A[j-1];
                System.out.println(Arrays.toString(A));
            }
            A[j] = c;
        }

同样的上面数组,这个方法冒泡十次就可以排好。

如下图所示:提出来一个数字,然后整体后移,这个数字放到前面。

 

 y-1的数字是跟y也就是选中的数字比大小。

 

 

 

记得刚开始写的时候记不起来,写的程序跟课程上的就一点出入。

 

 执行出来结果天差地别,就很疑惑为什么同样的判断放到表达式里面外面可以,里面却不行。

 

后来经过折腾发现。如果表达式放在for循环上可以理解为“门”,上面那种可以拦截不进入for循环,下面的则会进入for循环在判断。可以根据下面的代码进行理解。

 

 

 

选择排序:

简介:

选择排序:扫描序列,找到最小的元素与首位未排序的元素交换位置。接着循环这个动作直到最后一个元素,结束排序得到一个有序的序列。

代码实现:

例如数据如下:

1,23,2,12,11,2,5
排序后结果:
1,2,2,5,11,12,23

首先不变的就是遍历整个数组

for (int i = 0; i < A.length; i++) {

}

然后进行整个数组获取最小的元素。新起一个方法获取最小的元素下标。

复制代码
private static int getMinIndex(int[] a, int startIndex) {
        int minIndex = startIndex;
        for (int i = startIndex+1; i < a.length; i++) {
            if(a[i]<a[minIndex]){
                minIndex=i;
            }
        }
        return minIndex;
    }
复制代码

然后再交换元素:

复制代码
public static void selectSort(int[] A){
        for (int i = 0; i < A.length; i++) {
            int minIndex = getMinIndex(A,i);
            int c =A[i];
            A[i]=A[minIndex];
            A[minIndex] = c;
        }
    }

    private static int getMinIndex(int[] a, int startIndex) {
        int minIndex = startIndex;
        for (int i = startIndex+1; i < a.length; i++) {
            if(a[i]<a[minIndex]){
                minIndex=i;
            }
        }
        return minIndex;
    }
复制代码

 

 

冒泡算法对比相邻两个数,把最大的放在右边。一直换到最后。就冒出了最大数。如下图所示:

 

冒泡排序一直在交换,所以一直操作CPU写,所以耗时更长。

 

posted @ 2021-06-04 00:12  苦心明  阅读(162)  评论(0)    收藏  举报