【学习笔记】八大排序(待更新)

八大排序(待更新)

 

一、 冒泡排序

1.什么是冒泡排序?

冒泡排序的英文是Bubble Sort ,是一种最基础的交换排序,之所以叫冒泡排序,是因为每个元素都可以像小气泡一样,根据自身大小一点一点地向数组一侧移动。

原理:

每一趟只能确定将一个数归位,即第一趟只能确定将末尾上的数归位,第二趟只能将倒数第二位上的数归位,以此类推下去。如果有 n 个数进行排序,只需将 n-1 个数归位,也就是要进行n-1 趟操作。

而每一趟都需要从第一位开始进行相邻的两个数的比较,将较大的数放后面,比较完毕之后向后挪一位继续比较下面两个相邻的数大小关系,重复此步骤,直到最后一个还没归位的数。

2.动图展示

 

3.时间复杂度

比较4个数排完序需要3趟,第一趟需要比较三次,第二趟需要比较两次,第三趟需要比较一次,总共需要比较3+2+1 = 6次

如果有n个数,则需要比较 (n-1)+(n-2)+......2+1次,显然这是一个等差数列

 

根据复杂度的规则,去掉最低价项(n/2),且去掉常数系数,可以得到复杂度为O(n^2)

 

4.冒泡排序初始版

package com.wzt.array;
​
import java.util.Arrays;
​
public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] a = {23,14,6,89,77,3};
        int[] result = bubbleSort(a);
        System.out.println(Arrays.toString(result));
​
    }
    public static int[] bubbleSort(int[] array){
        int temp = 0;
        for (int i = 0; i < array.length-1; i++) {   //外层循环控制的是趟数 
            for (int j = 0; j < array.length-(i+1); j++) {    //里层循环控制的是每趟比较的次数  其中i+1是第几趟
                if (array[j] > array[j+1]){
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
        }
        return array;
    }
}
​

存在的问题

如果在第二趟结束后数组已经有序,如下

[23,14,6,89,77] 第一趟-------> [14,6,23,77,89] 第二趟-------> [6,14,23,77,99]

那么按照以上代码,算法依旧会兢兢业业地执行第三趟、第四趟,造成了时间上的浪费

我们可以利用布尔量作为标记,如果在本轮排序中,元素有交换,则说明数列无序,如果没有元素交换,说明元素已经有序,直接跳出大循环

package com.wzt.array;
​
import java.util.Arrays;
​
public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] a = {23,14,6,89,77,3};
        int[] result = bubbleSort(a);
        System.out.println(Arrays.toString(result));
​
    }
    public static int[] bubbleSort(int[] array){
        int temp = 0;
        for (int i = 0; i < array.length-1; i++) {   //外层循环控制的是趟数
            boolean flag = false;
            for (int j = 0; j < array.length-(i+1); j++) {    //里层循环控制的是每趟比较的次数  其中i+1是第几趟
                if (array[j] > array[j+1]){
                    flag = true;    //如果发生了元素交换,则令flag为true
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
            //执行完一趟之后,判断是否有元素交换,有则说明数组无序,没有说明有序,直接跳出大循环
            if(!flag){
                break;
            }
        }
        return array;
    }
}
​

新问题

如果数组中前半部分是无序的,而后半部分是有序的,比如(3,4,2,1,5,6,7,8),这个数组后半部分许多元素已经有序,但每一趟依然往后比较了许多次

 

第一趟:

3和4比较,3小于4,不用交换

然后4与2 比较 ,4大于2,交换位置

然后4与1比较,交换位置

然后,后面是有序数组,但依旧需要两两比较

4与5比较,5与6比较,6与7比较,7与8比较

然后进入第二趟

 

第二趟:

3与2比较,交换位置

3与1比较,交换位置

然后发现,后面又是有序数组了

3与4比较,4与5比较,....... 白白比较了很多次

 

如何优化?

对于这个问题,关键在于数列有序区的界定,如果按照冒泡排序代码原始版分析的话,有序区的长度和排序的轮数是相等的,比如第一轮排序后,有序区长度是1,第二轮排序后有序区长度是2......

但是,实际数列有序区会大于这个数,也就是上面的例子,第二轮中,后面5个数都在有序区内,因此后面的比较就没有意义了。

我们可以这样做来避免这种情况,在每一轮排序的最后,记录一下最后一次元素交换的位置,那个位置是无序区数列的边界,在往后就是有序区了。

 

package com.wzt.array;
​
import java.util.Arrays;
​
public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] a = {23,14,6,89,77,3};
        int[] result = bubbleSort(a);
        System.out.println(Arrays.toString(result));
​
    }
    public static int[] bubbleSort(int[] array){
        int temp = 0;
        //无序数列的边界,再往后就是有序区了
        int indexBorder = array.length-1;
        //记录每一次元素交换的位置
        int location = 0;
​
        for (int i = 0; i < array.length-1; i++) {   //外层循环控制的是趟数
            boolean flag = false;
            for (int j = 0; j < indexBorder; j++) {    //比较到哪个地方的位置
                if (array[j] > array[j+1]){
                    flag = true;    //如果发生了元素交换,则令flag为true
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                    location = j;    //记录最后一次元素交换的位置
                }
            }
            indexBorder = location;    //把元素交换的位置给无序数列的边界
            //执行完一趟之后,判断是否有元素交换,有则说明数组无序,没有说明有序,直接跳出大循环
            if(!flag){
                break;
            }
        }
        return array;
    }
}
​
 
posted @ 2022-07-16 08:54  GrowthRoad  阅读(31)  评论(0编辑  收藏  举报