06-冒泡排序,选择排序,插入排序基本思路及代码实现

6.3 冒泡排序

6.3.1基本思想

​ 基本思想:给定待排序的一组数,从下标小的元素开始,依次和后一个相邻元素比较,满足条件则交换,使得较大的元素逐渐向后移动,就像水底的气泡一样逐渐上浮

6.3.2流程分析

在这里插入图片描述

通过上图的流程分析,可以发现:

  • 对于给定长度为n的待排序数组,需要进行n-1次外层循环,进行趟数的比较
  • 在内层循环中,每一趟的比较次数在逐次减少
  • 如果在其中某一趟中,没有发生比较和交换,则说明数组已经是有序的状态,可以提前退出
6.3.3代码实现

代码中分为对冒泡排序的逐层解析,冒泡排序以及其优化三部分

package com.kevin.sortAlgorithm;

import java.util.Arrays;

/**
 * @author : kevin ding
 * @date : 2022/2/28 21:07
 * @description :   冒泡排序:基本思想是通过对 待排序的一组数,从下标小的元素开始,依次和后一个相邻元素比较,满足条件则交换,使得较大的元素逐渐向后移动,就像水底的气泡一样逐渐上浮
 */
public class BubbleSortDemo {
    
    
    public static void main(String[] args) {
    
    
        // int[] array = {32, 11, 46, 23, 2};
        // int[] array = {2, 11, 14, 29, 23};
        // System.out.println("排序之前,结果为:");
        // System.out.println(Arrays.toString(array));
        // sortAnalysis(array);
        // bubbleSort(array);

        int[] array = new int[80000];
        for (int i = 0; i < array.length; i++) {
    
    
            array[i] = (int) (Math.random() * 8000000);
        }


        Long startTime = System.currentTimeMillis();
        bubbleSortOptimize(array);
        Long endTime = System.currentTimeMillis();
        System.out.println("冒泡排序 所耗费的时间是:" + (endTime-startTime) + "ms");       // 6621ms


    }

    public static void sortAnalysis(int[] array){
    
    
        // 定义临时变量,用于两数之间的交换
        int temp = 0;
        // 第一趟排序    总共进行了array.length-1次循环比较
        for(int j = 0; j < array.length - 1; j++){
    
    
            // 如果当前值大于其下一个,两者交换
            if(array[j] > array[j+1]){
    
    
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第 1 趟排序之后,结果为:");
        System.out.println(Arrays.toString(array));


        // 第 2趟排序    总共进行了array.length-1-1次循环比较
        for(int j = 0; j < array.length - 1 - 1; j++){
    
    
            // 如果当前值大于其下一个,两者交换
            if(array[j] > array[j+1]){
    
    
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第 2 趟排序之后,结果为:");
        System.out.println(Arrays.toString(array));

        // 第 3 趟排序    总共进行了array.length-1-2次循环比较
        for(int j = 0; j < array.length - 1 - 2; j++){
    
    
            // 如果当前值大于其下一个,两者交换
            if(array[j] > array[j+1]){
    
    
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第 3 趟排序之后,结果为:");
        System.out.println(Arrays.toString(array));

        // 第 4 趟排序    总共进行了array.length-1-3 次循环比较
        for(int j = 0; j < array.length - 1 - 3; j++){
    
    
            // 如果当前值大于其下一个,两者交换
            if(array[j] > array[j+1]){
    
    
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第 4 趟排序之后,结果为:");
        System.out.println(Arrays.toString(array));
    }

    public static void bubbleSort(int[] array){
    
    
        // 通过对sortAnalysis的分析,发现规律,每趟的排序,只需要改动for循环中的上界 ,并且上界值在逐渐减小,其他代码全部进行复用,用循环来代替:
        // 发现总共循环的趟数是array.length-1次,每趟中比较的次数少一次
        int temp = 0;   // 用于交换的临时变量
        for(int i = 0; i < array.length-1; i++){
    
    
            for (int j = 0; j < array.length-1-i; j++) {
    
    
                if(array[j] > array[j+1]){
    
    
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }

            }
            System.out.println("第 " + (i+1) +" 趟排序之后,结果为:");
            System.out.println(Arrays.toString(array));
        }
    }

    /**
     * @description 对bubbleSort方法的优化
     * @param array
     */
    public static void bubbleSortOptimize(int[] array){
    
    
        // 通过分析发现,若在其中某一趟循环的时候,数组已经处于有序状态,则无需进行接下来的几趟循环,可以直接退出
        int temp;           // 用于进行数据交换的临时变量
        boolean flag;   // 用于进行判断是否需要接着循环的标记

        for(int i = 0; i < array.length-1; i++){
    
    
            // 在每一轮循环开始之前,需要将标记位置为false
            flag = false;
            for (int j = 0; j < array.length-1-i; j++) {
    
    
                if(array[j] > array[j+1]){
    
    
                    // 如果进行了循环,就将标记置为true
                    flag = true;
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
            // 每趟循环结束之后,判断标记位的值
            if(!flag){
    
    
                // 表示没有进去进行交换,即已经处于由于状态,可直接退出
                break;
            }
        }

    }
}
6.3.4 冒泡排序的最终版代码:
/**
 * @description bubbleSort方法的最终版本
 * @param array
 */
public static void bubbleSort(int[] array){
    
    
    // 通过分析发现,若在其中某一趟循环的时候,数组已经处于有序状态,则无需进行接下来的几趟循环,可以直接退出
    int temp;           // 用于进行数据交换的临时变量
    boolean flag;   // 用于进行判断是否需要接着循环的标记

    for(int i = 0; i < array.length-1; i++){
    
    
        // 在每一轮循环开始之前,需要将标记位置为false
        flag = false;
        for (int j = 0; j < array.length-1-i; j++) {
    
    
            if(array[j] > array[j+1]){
    
    
                // 如果进行了循环,就将标记置为true
                flag = true;
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }

        }
        // 每趟循环结束之后,判断标记位的值
        if(!flag){
    
    
            // 表示没有进去进行交换,即已经处于由于状态,可直接退出
            break;
        }
    }
}

6.4 选择排序

6.4.1 选择排序的思想:

​ 第一次从array[0]-arr[n-1]中选取最小值,与array[0]交换,第二次从array[1]array[n-1]中选取最小值,array[1]交换,第三次从array[2]array[n-1]中选取最小值,与arr[2]交换,…, 第n-1次从array[n-2]array[n-1]中选取最小值,与array[n-2]交换,总共通过n-1次,得到一个按排序码从小到大排列的有序序列。

选择排序的图解:
在这里插入图片描述

6.4.2 代码实现:

代码中分为对选择排序的逐层解析,选择排序以及其优化三部分

package com.kevin.sortAlgorithm;

import sun.security.util.AuthResources_it;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @author : kevin ding
 * @date : 2022/3/1 21:44
 * @description : 选择排序思想:第1次,array[0] - array[n-1]的所有数中,默认最小值为array[0], 从array[0+1] - arr[n-1]中找到最小值,与array[0]进行交换,使得0索引位置为最小值;
 *                            第2次,array[1] - array[n-1]的所有数中,默认最小值为array[1], 从array[1+1] - arr[n-1]中找到最小值,与array[1]进行交换,使得1索引位置为最小值;
 *                            第3次,array[2] - array[n-1]的所有数中,默认最小值为array[2], 从array[2+1] - arr[n-1]中找到最小值,与array[2]进行交换,使得2索引位置为最小值;
 *                            ... 一直到第 n-1 次
 */
public class SelectSortDemo {
    
    
    public static void main(String[] args) {
    
    
        // int[] array = {32, 11, 46, 23, 2};
        // System.out.println("排序之前,结果为:");
        // System.out.println(Arrays.toString(array));

        // 对于  100000个数据进行排序,求其时间
        int[] array = new int[80000];
        for (int i = 0; i < array.length; i++) {
    
    
            array[i] = (int) (Math.random() * 8000000);
        }

        Long startTime = System.currentTimeMillis();
        selectSort(array);
        Long endTime = System.currentTimeMillis();

        System.out.println("选择排序所耗费的时间是:" + (endTime-startTime) + "ms");        // 1539

    }

    public static void selectSortAnalysis(int[] array){
    
    

        // 定义辅助变量 temp用于进行交换,minIndex存放最小值对应的索引下标
        int temp;
        int minIndex;

        // 第1次:每次循环只需要改变minIndex的初始值,及for循环的起始值即可
        minIndex = 0;
        for(int j = 0+1; j<array.length; j++){
    
    
            // 如果当前位置的值小于minValue,更换最小值及最小值的索引
            if(array[minIndex] > array[j]){
    
    
                minIndex = j;
            }
        }
        // 循环结束之后,找到了当前的最小值,与array[0]进行交换
        temp = array[minIndex];
        array[minIndex] = array[0];
        array[0] = temp;

        System.out.println("第 1 趟选择之后,结果为:");
        System.out.println(Arrays.toString(array));


        // 第2次:每次循环只需要改变minIndex的初始值,及for循环的起始值即可
        minIndex = 1;
        for(int j = 1+1; j<array.length; j++){
    
    
            // 如果当前位置的值小于minValue,更换最小值及最小值的索引
            if(array[minIndex] > array[j]){
    
    
                minIndex = j;
            }
        }
        // 循环结束之后,找到了当前的最小值,与array[0]进行交换
        temp = array[minIndex];
        array[minIndex] = array[1];
        array[1] = temp;

        System.out.println("第 2 趟选择之后,结果为:");
        System.out.println(Arrays.toString(array));

        // 第3次:每次循环只需要改变minIndex的初始值,及for循环的起始值即可
        minIndex = 2;
        for(int j = 2+1; j<array.length; j++){
    
    
            // 如果当前位置的值小于minValue,更换最小值及最小值的索引
            if(array[minIndex] > array[j]){
    
    
                minIndex = j;
            }
        }
        // 循环结束之后,找到了当前的最小值,与array[0]进行交换
        temp = array[minIndex];
        array[minIndex] = array[2];
        array[2] = temp;

        System.out.println("第 3 趟选择之后,结果为:");
        System.out.println(Arrays.toString(array));

        // 第4次: 每次循环只需要改变minIndex的初始值,及for循环的起始值即可
        minIndex = 3;
        for(int j = 3+1; j<array.length; j++){
    
    
            // 如果当前位置的值小于minValue,更换最小值及最小值的索引
            if(array[minIndex] > array[j]){
    
    
                minIndex = j;
            }
        }
        // 循环结束之后,找到了当前的最小值,与array[0]进行交换
        temp = array[minIndex];
        array[minIndex] = array[3];
        array[3] = temp;

        System.out.println("第 4 趟选择之后,结果为:");
        System.out.println(Arrays.toString(array));

    }


    public static void selectSort(int[] array){
    
    
        // 通过对selectSortAnalysis代码分析发现,对于一个长度为n的数组,需要循环n-1次,每次循环时从未排序的序列中找最小值,
        // 查找范围在逐渐缩小,下界在发生变化,上界一直为数组的最后一个元素,且每次默认的最小值索引逐次递增
        int temp;
        int minIndex;

        for (int i = 0; i < array.length-1; i++) {
    
    
            minIndex = i;
            for (int j = i+1; j <array.length ; j++) {
    
    
                // 如果当前位置的值小于minValue,更换最小值及最小值的索引
                if(array[minIndex] > array[j]){
    
    
                    minIndex = j;
                }
            }
            // 每次遍历结束之后,将和当前第i个元素进行交换,使得最小值始终 位于第一个
            temp = array[minIndex];
            array[minIndex] = array[i];
            array[i] = temp;

            // System.out.println("第 "+ (i+1)+" 趟选择之后,结果为:");
            // System.out.println(Arrays.toString(array));
        }
    }

    public static void selectSortOptimize(int[] array){
    
    
        // 对选择排序进行分析,每次遍历结束找到最小值的索引之后进行交换,如果当前i即为最小值索引,则交换没有意义,可进行优化
        int temp;
        int minIndex;

        for (int i = 0; i < array.length-1; i++) {
    
    
            minIndex = i;
            for (int j = i+1; j <array.length ; j++) {
    
    
                // 如果当前位置的值小于minValue,更换最小值及最小值的索引
                if(array[minIndex] > array[j]){
    
    
                    minIndex = j;

                }
            }
            // 每次遍历结束之后,将和当前第i个元素进行交换,使得最小值始终 位于第一个
            // 当i和minIndex不相等的时候, 才进行交换
            if(i != minIndex){
    
    
                temp = array[minIndex];
                array[minIndex] = array[i];
                array[i] = temp;
            }


            System.out.println("第 "+ (i+1)+" 趟选择之后,结果为:");
            System.out.println(Arrays.toString(array));
        }
    }
}
6.4.3 最终选择排序代码
public static void selectSort(int[] array){
    
    
    // 对选择排序进行分析,每次遍历结束找到最小值的索引之后进行交换,如果当前i即为最小值索引,则交换没有意义,可进行优化
    int temp;
    int minIndex;

    for (int i = 0; i < array.length-1; i++) {
    
    
        minIndex = i;
        for (int j = i+1; j <array.length ; j++) {
    
    
            // 如果当前位置的值小于minValue,更换最小值及最小值的索引
            if(array[minIndex] > array[j]){
    
    
                minIndex = j;
            }
        }
        // 每次遍历结束之后,将和当前第i个元素进行交换,使得最小值始终 位于第一个
        // 当i和minIndex不相等的时候, 才进行交换
        if(i != minIndex){
    
    
            temp = array[minIndex];
            array[minIndex] = array[i];
            array[i] = temp;
        }
        System.out.println("第 "+ (i+1)+" 趟选择之后,结果为:");
        System.out.println(Arrays.toString(array));
    }
}

6.5 插入排序

6.5.1介绍

对于欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。

6.5.2 思想

把一组待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素(最左边元素),无序表中包含有n-1个元素(后面n-1个元素),排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。

插入排序图解:
在这里插入图片描述

6.5.3 代码实现:

包括对插入排序的逐层分析,以及实现

package com.kevin.sortAlgorithm;

import com.kevin.arrayStack.ArrayStack;

import java.sql.Array;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @author : kevin ding
 * @date : 2022/3/1 22:16
 * @description : 插入排序 思想:对于一组待排序的数据,看成是一个有序列表和无序列表,初始时,有序列表只包含一个元素,无需列表包含n-1个元素,从array[1] ~ array[n-1],
 *                              分别将其下标与前面有序元素进行比较,找到适当的位置,并插入到该位置,以达到排序的目的;
 *                              每次对于待排序的元素,其左半部分已经是有序状态,右半部分是待排序的元素
 */
public class InsertSortDemo {
    
    
    public static void main(String[] args) {
    
    
        // int[] array = {32, 11, 46, 23, 2};
        // System.out.println("排序之前,结果为:");
        // System.out.println(Arrays.toString(array));
        //
        // // insertSortAnalysis(array);
        //
        // insertSort(array);

        // 对于  100000个数据进行排序,求其时间
        int[] array = new int[80000];
        for (int i = 0; i < array.length; i++) {
    
    
            array[i] = (int) (Math.random() * 8000000);
        }


        Long startTime = System.currentTimeMillis();
        insertSort(array);
        Long endTime = System.currentTimeMillis();

        System.out.println("插入排序 所耗费的时间是:" + (endTime-startTime) + "ms");       // 395ms

    }

    public static void insertSortAnalysis(int[] array){
    
    
        // 定义变量 insertValue为当前带插入的元素,insertIndex为带插入元素的位置
        int insertValue;
        int insertIndex;
        // 第一次排序: 选择array[1]为待排数,
        insertValue = array[1];
        insertIndex = 1;
        // 给待排元素insertValue往前找到合适的位置
        while(insertIndex > 0 && insertValue < array[insertIndex-1] ){
    
    
            // 带插入元素小于前一个,且不能越界
            array[insertIndex] = array[insertIndex-1];
            insertIndex -= 1;
        }
        // 当退出循环的时候,要么inserIndex已经到了第一个位置,要么已经在合适的位置,insertIndex即为合适的插入位置
        array[insertIndex] = insertValue;

        System.out.println("第一轮插入之后:");
        System.out.println(Arrays.toString(array));


        // 第2次排序: 选择array[1]为待排数,
        insertValue = array[2];
        insertIndex = 2;
        // 给待排元素insertValue往前找到合适的位置
        while(insertIndex > 0 && insertValue < array[insertIndex-1] ){
    
    
            // 带插入元素小于前一个,且不能越界
            array[insertIndex] = array[insertIndex-1];
            insertIndex -= 1;
        }
        // 当退出循环的时候,找到了正确的位置
        array[insertIndex] = insertValue;

        System.out.println("第2轮插入之后:");
        System.out.println(Arrays.toString(array));


        // 第3次排序: 选择array[1]为待排数,
        insertValue = array[3];
        insertIndex = 3;
        // 给待排元素insertValue往前找到合适的位置
        while(insertIndex > 0 && insertValue < array[insertIndex-1] ){
    
    
            // 带插入元素小于前一个,且不能越界
            array[insertIndex] = array[insertIndex-1];
            insertIndex -= 1;
        }
        // 当退出循环的时候,找到了正确的位置
        array[insertIndex] = insertValue;

        System.out.println("第3轮插入之后:");
        System.out.println(Arrays.toString(array));

        // 第4次排序: 选择array[1]为待排数,
        insertValue = array[4];
        insertIndex = 4;
        // 给待排元素insertValue往前找到合适的位置
        while(insertIndex > 0 && insertValue < array[insertIndex-1] ){
    
    
            // 带插入元素小于前一个,且不能越界
            array[insertIndex] = array[insertIndex-1];
            insertIndex -= 1;
        }
        // 当退出循环的时候,找到了正确的位置
        array[insertIndex] = insertValue;

        System.out.println("第4轮插入之后:");
        System.out.println(Arrays.toString(array));
    }

    public static void insertSort(int[] array){
    
    
        // 通过对上面的逐步分析,可以将外层通过循环来进行控制每一轮的选择:
        int insertValue;
        int insertIndex;

        // 从1开始到n-1
        for (int i = 1; i < array.length; i++) {
    
    
            insertValue = array[i];
            insertIndex = i;
            // 给待排元素insertValue往前找到合适的位置
            while(insertIndex > 0 && insertValue < array[insertIndex-1] ){
    
    
                // 带插入元素小于前一个,且不能越界
                array[insertIndex] = array[insertIndex-1];
                insertIndex -= 1;
            }
            // 当退出循环的时候,找到了正确的位置
            array[insertIndex] = insertValue;
        }
    }
}
6.5.4 最终版插入排序代码
public static void insertSort(int[] array){
    
    
    // 通过对上面的逐步分析,可以将外层通过循环来进行控制每一轮的选择:
    int insertValue;
    int insertIndex;
    // 从1开始到n-1
    for (int i = 1; i < array.length; i++) {
    
    
        insertValue = array[i];
        insertIndex = i;
        // 给待排元素insertValue往前找到合适的位置
        while(insertIndex > 0 && insertValue < array[insertIndex-1] ){
    
    
            // 带插入元素小于前一个,且不能越界
            array[insertIndex] = array[insertIndex-1];
            insertIndex -= 1;
        }
        // 当退出循环的时候,找到了正确的位置
        array[insertIndex] = insertValue;

    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43155804/article/details/123218201
今日推荐