【尚硅谷】数据结构与算法——排序算法2.0


前言

跟着B站的尚硅谷学习数据结构与算法,语言为java,目前是第九个代码内容——排序
课程传送门:尚硅谷——排序算法2.0


一、冒泡排序

1.基本介绍

冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序交换,使值较大的元素逐渐从前移向后部,就像水底下的水泡一样逐渐往上冒。

因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行交换,就说明序列有序,因此要在排序过程中设置一个标志 flag 判断元素是否进行过交换。从而减少不必要的比较。(这里说的优化,可以在冒泡排序写好后,再进行)

2.应用实例

我们举一个具体的案例来说明冒泡法,我们将五个无序的数: 3、9、-1、10、20

在这里插入图片描述
冒泡排序规则:
1)一共进行数组的 大小-1 次大的循环
2)每一趟排序的次数再逐渐的减少
3)如果发现再某次排序中,没有发生一次交换,可以提前结束冒泡排序,这就是优化。

使用冒泡排序法将其排成一个从小到大的有序数列。

package com.sort;


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

public class BubbleSort {
    public static void main(String[] args) {
        int arr[] = {3,9,-1,10,20};

        //为了容量理解,我们把冒泡排序的演变过程展示给大家

        //测试
        System.out.println("排序前");
        System.out.println(Arrays.toString(arr));

        bubbleSort(arr);

        System.out.println("排序后");
        System.out.println(Arrays.toString(arr));


    }

    public static void bubbleSort(int arr[]){
        //第一场排序,就是将最大的数排在最后
        int temp = 0;
        boolean flag = false;
        for (int i = 0; i < arr.length-1; i++){
            for (int j = 0; j < arr.length - 1 - i; j++){
                //如果前面的数比后面的数大,则交换
                if (arr[j] > arr[j+1]){
                    flag = true;
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }

            System.out.println("第" + (i+1) + "趟排序后的数组");
            System.out.println(Arrays.toString(arr));

            if (!flag){
                break;
            }else {
                flag = false;
            }
        }
    }
}

3.速度测试

package com.sort;


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

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = new int[80000];
        for (int i = 0; i < 80000; i++){
            arr[i] = (int)(Math.random() * 8000000);
        }

        Date data1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String date1Str = simpleDateFormat.format(data1);
        System.out.println("排序前的时间是 = " + date1Str);

        bubbleSort(arr);

        Date data2 = new Date();
        String date2Str = simpleDateFormat.format(data2);
        System.out.println("排序后的时间是 = " + date2Str);
    }

    public static void bubbleSort(int arr[]){
        //第一场排序,就是将最大的数排在最后
        int temp = 0;
        boolean flag = false;
        for (int i = 0; i < arr.length-1; i++){
            for (int j = 0; j < arr.length - 1 - i; j++){
                //如果前面的数比后面的数大,则交换
                if (arr[j] > arr[j+1]){
                    flag = true;
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }

            if (!flag){
                break;
            }else {
                flag = false;
            }
        }
    }
}

二、选择排序

1.基本介绍

选择排序(select sorting)也是一种简单的排序方法。它的基本思路是:第一次从 arr[0]~arr[n-1] 中选取最小值,与 arr[0] 交换,第二次从 arr[1]~arr[n-1] 中选取最小值,与 arr[1] 交换,第三次从 arr[2]~arr[n-1] 中选取最小值,与 arr[2] 交换,…,第 i 次从 arr[i]~arr[n-1] 中选取最小值,与 arr[i] 交换。总共经过 n-1 次,得到一个按排序码从小到大排序的有序列表。

在这里插入图片描述

2.应用实例

有一群牛,颜值分别是101,34,119,1 请使用选择排序从低到高进行排序[ 101, 34, 119, 1]

在这里插入图片描述
选择排序规则:
1.选择排序一共有数组大小-1 轮排序
2.每 1 轮排序,又是一个循环
-先假定当前的这个数是最小数
-然后和后面的每一个数作比较,如果发现有当前数更小的数,就重新确定最小数,并得到下标
-当遍历到数组的最后时,就得到本轮最小数和下标
-交换(代码)

package com.sort;

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

public class SelectSort {
    public static void main(String[] args) {
        int[] arr = {101,34,119,1,-1,2,5,778};

        System.out.println("排序前");
        System.out.println(Arrays.toString(arr));

        selectSort(arr);

        System.out.println("排序后");
        System.out.println(Arrays.toString(arr));
    }

    //选择排序
    public static void selectSort(int[] arr){
        //在推导的过程中,有所规律
        for (int i = 0; i < arr.length; i++){
            int minIndex = i;
            int min = arr[i];
            for (int j = i + 1; j < arr.length;j++){
                if (min > arr[j]){
                    min = arr[j];
                    minIndex = j;
                }
            }

            //将最小值放在arr[0],即交换
            if (minIndex != i){
                arr[minIndex] = arr[i];
                arr[i] = min;
            }

            System.out.println("第"+ i +"轮后");
            System.out.println(Arrays.toString(arr));
        }


        //使用逐步推导的方式来,讲解选择排序
        //第一轮
        //原始数组: 101 34 119 1
        //第一轮排序: 1 34 119 101
        //算法:先简单后复杂,就是把一个复杂的算法,拆分成简单的问题

//        //第一轮
//        int minIndex = 0;
//        int min = arr[0];
//        for (int j = 0 + 1; j < arr.length;j++){
//            if (min > arr[j]){
//                min = arr[j];
//                minIndex = j;
//            }
//        }
//
//        //将最小值放在arr[0],即交换
//        if (minIndex != 0){
//            arr[minIndex] = arr[0];
//            arr[0] = min;
//        }
//
//        System.out.println("第一轮后");
//        System.out.println(Arrays.toString(arr));
//
//        //第二轮
//        minIndex = 1;
//        min = arr[1];
//        for (int j = 1 + 1; j < arr.length;j++){
//            if (min > arr[j]){
//                min = arr[j];
//                minIndex = j;
//            }
//        }
//
//        //将最小值放在arr[0],即交换
//        if (minIndex != 1){
//            arr[minIndex] = arr[1];
//            arr[1] = min;
//        }
//
//
//        System.out.println("第二轮后");
//        System.out.println(Arrays.toString(arr));
//
//        //第三轮
//        minIndex = 2;
//        min = arr[2];
//        for (int j = 2 + 1; j < arr.length;j++){
//            if (min > arr[j]){
//                min = arr[j];
//                minIndex = j;
//            }
//        }
//
//        //将最小值放在arr[0],即交换
//        if (minIndex != 2){
//            arr[minIndex] = arr[2];
//            arr[2] = min;
//        }
//
//
//        System.out.println("第三轮后");
//        System.out.println(Arrays.toString(arr));
    }
}

3.速度测试

package com.sort;

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

public class SelectSort {
    public static void main(String[] args) {
        int[] arr = new int[80000];
        for (int i = 0; i < 80000; i++){
            arr[i] = (int)(Math.random() * 8000000);
        }

        Date data1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String date1Str = simpleDateFormat.format(data1);
        System.out.println("排序前的时间是 = " + date1Str);

        selectSort(arr);

        Date data2 = new Date();
        String date2Str = simpleDateFormat.format(data2);
        System.out.println("排序后的时间是 = " + date2Str);
    }

    //选择排序
    public static void selectSort(int[] arr){
        //在推导的过程中,有所规律
        for (int i = 0; i < arr.length; i++) {
            int minIndex = i;
            int min = arr[i];
            for (int j = i + 1; j < arr.length; j++) {
                if (min > arr[j]) {
                    min = arr[j];
                    minIndex = j;
                }
            }

            //将最小值放在arr[0],即交换
            if (minIndex != i) {
                arr[minIndex] = arr[i];
                arr[i] = min;
            }

        }
    }
}

三、插入排序

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

1.基本介绍

插入排序(Insertion Sorting)的基本思想是:把 n 个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含 n-1 个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之称为新的有序表。

2.应用实例

有一群小牛,考试成绩分别是:101,34,119,1 请从小到大排序

ppackage com.sort;

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

public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {101,34,119,1};
        insertSort(arr);
    }

    //插入排序
    public static void insertSort(int[] arr){
        //使用逐步推导的方法来讲解,便于理解
        for (int i = 0; i < arr.length; i++){
            int insertVal = arr[i];
            int insertIndex = i - 1;

            while (insertIndex >= 0 && insertVal < arr[insertIndex]){
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            //当退出while循环时,说明插入的位置找到, insertIndex + 1
            if (insertIndex + 1 != i){
                arr[insertIndex + 1] = insertVal;
            }


            System.out.println("第" + i + "轮排序");
            System.out.println(Arrays.toString(arr));
        }



        //第一轮{101,34,119,1} => {34,101,119,1}
        //定义待插入的数
//        int insertVal = arr[1];
//        int insertIndex = 1 - 1;
//
//        //说明
//        //1.insertIndex >= 0 保证在给insertVal找插入值的时候不越界
//        //2.insertVal < arr[insertIndex] 待插入的数,还没有找到插入位置
//        //3.就需要持 arr[insertIndex] 后移
//        while (insertIndex >= 0 && insertVal < arr[insertIndex]){
//            arr[insertIndex + 1] = arr[insertIndex];
//            insertIndex--;
//        }
//        //当退出while循环时,说明插入的位置找到, insertIndex + 1
//        arr[insertIndex + 1] = insertVal;
//
//        System.out.println("第一轮排序");
//        System.out.println(Arrays.toString(arr));
//
//        //第二轮
//        insertVal = arr[2];
//        insertIndex = 2 - 1;
//
//        while (insertIndex >= 0 && insertVal < arr[insertIndex]){
//            arr[insertIndex + 1] = arr[insertIndex];
//            insertIndex--;
//        }
//        //当退出while循环时,说明插入的位置找到, insertIndex + 1
//        arr[insertIndex + 1] = insertVal;
//
//        System.out.println("第二轮排序");
//        System.out.println(Arrays.toString(arr));
//
//        //第三轮
//        insertVal = arr[3];
//        insertIndex = 3 - 1;
//
//        while (insertIndex >= 0 && insertVal < arr[insertIndex]){
//            arr[insertIndex + 1] = arr[insertIndex];
//            insertIndex--;
//        }
//        //当退出while循环时,说明插入的位置找到, insertIndex + 1
//        arr[insertIndex + 1] = insertVal;
//
//        System.out.println("第三轮排序");
//        System.out.println(Arrays.toString(arr));
    }
}

3.速度测试

package com.sort;

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

public class InsertSort {
    public static void main(String[] args) {

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

        Date data1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String date1Str = simpleDateFormat.format(data1);
        System.out.println("排序前的时间是 = " + date1Str);

        insertSort(arr);

        Date data2 = new Date();
        String date2Str = simpleDateFormat.format(data2);
        System.out.println("排序后的时间是 = " + date2Str);
    }

    //插入排序
    public static void insertSort(int[] arr){
        //使用逐步推导的方法来讲解,便于理解
        for (int i = 0; i < arr.length; i++){
            int insertVal = arr[i];
            int insertIndex = i - 1;

            while (insertIndex >= 0 && insertVal < arr[insertIndex]){
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            //当退出while循环时,说明插入的位置找到, insertIndex + 1
            if (insertIndex + 1 != i){
                arr[insertIndex + 1] = insertVal;
            }
        }
    }
}

四、希尔排序

希尔排序是希尔(DonaldShell)于 1959 年提出的一种排序算法,希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一种更高效的版本,也称为缩小增量排序

1.基本介绍

希尔是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件给分成一组,算法便终止。

在这里插入图片描述
在这里插入图片描述

2.应用实例

有一群小牛,考试成绩分别是 {8,9,1,7,2,3,5,4,6,0} 请从小到大排序,请分别使用
1)希尔排序时,对有序序列在插入时采用交换法,并测试排序速度
2)希尔排序时,对有序列表在插入时采用移动法,并测试排序速度

1)交换法

package com.sort;

import java.util.Arrays;

public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        shellSort(arr);
    }

    public static void shellSort(int[] arr){
        int temp = 0;

        //根据规律可得
        for (int gap = arr.length / 2; gap > 0; gap /= 2){
            for (int i = gap; i < arr.length; i++){
                //遍历各组中所有的元素(共arr.length / 2组)
                for (int j = i - gap; j >= 0; j -= gap){
                    //如果当前元素大于加上步长后的那个元素,说明交换
                    if (arr[j] > arr[j+gap]){
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    }
                }
            }
            System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));

        }


//        //第一轮
//        //将10个数分成五份
//        for (int i = 5; i < arr.length; i++){
//            //遍历各组中所有的元素(共五组,每组两个元素)
//            for (int j = i -5; j >= 0; j-=5){
//                //如果当前元素大于加上步长后的那个元素,说明交换
//                if (arr[j] > arr[j+5]){
//                    temp = arr[j];
//                    arr[j] = arr[j+5];
//                    arr[j+5] = temp;
//                }
//            }
//        }
//        System.out.println("希尔排序第一轮后 = " + Arrays.toString(arr));
//
//        //第2轮
//        //将10个数分成2份
//        for (int i = 2; i < arr.length; i++){
//            //遍历各组中所有的元素(共五组,每组两个元素)
//            for (int j = i -2; j >= 0; j -= 2){
//                //如果当前元素大于加上步长后的那个元素,说明交换
//                if (arr[j] > arr[j+2]){
//                    temp = arr[j];
//                    arr[j] = arr[j+2];
//                    arr[j+2] = temp;
//                }
//            }
//        }
//        System.out.println("希尔排序第二轮后 = " + Arrays.toString(arr));
//
//        //第3轮
//        //将10个数分成3份
//        for (int i = 1; i < arr.length; i++){
//            //遍历各组中所有的元素(共五组,每组两个元素)
//            for (int j = i - 1; j >= 0; j -= 1){
//                //如果当前元素大于加上步长后的那个元素,说明交换
//                if (arr[j] > arr[j+1]){
//                    temp = arr[j];
//                    arr[j] = arr[j+1];
//                    arr[j+1] = temp;
//                }
//            }
//        }
//        System.out.println("希尔排序第三轮后 = " + Arrays.toString(arr));

    }
}

2)移动法

package com.sort;

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

public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        
       // shellSort(arr);
        shellSort2(arr);
    }

    
    //对交换式的希尔排序进行优化 -> 移位法
    public static void shellSort2(int[] arr){
        //增量gap,并逐步缩小
        for (int gap = arr.length / 2; gap > 0; gap /= 2){
            //从第gap个元素,逐个对其所在的组进行直接插入排序
            for (int i = gap; i < arr.length; i++){
                int j = i;
                int temp = arr[j];
                if (arr[j] < arr[j-gap]){
                    while(j - gap >= 0 && temp < arr[j - gap]){
                        //移动
                        arr[j] = arr[j-gap];
                        j -= gap;
                    }
                    //当退出while后,就给temp找到插入的位置
                    arr[j] = temp;
                }
            }
            System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));
        }
    }
}

3.速度测试

1)交换法

package com.sort;

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

public class ShellSort {
    public static void main(String[] args) {

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

        Date data1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String date1Str = simpleDateFormat.format(data1);
        System.out.println("排序前的时间是 = " + date1Str);

        shellSort(arr);

        Date data2 = new Date();
        String date2Str = simpleDateFormat.format(data2);
        System.out.println("排序后的时间是 = " + date2Str);
    }

    public static void shellSort(int[] arr){
        int temp = 0;

        //根据规律可得
        for (int gap = arr.length / 2; gap > 0; gap /= 2){
            for (int i = gap; i < arr.length; i++){
                //遍历各组中所有的元素(共arr.length / 2组)
                for (int j = i - gap; j >= 0; j -= gap){
                    //如果当前元素大于加上步长后的那个元素,说明交换
                    if (arr[j] > arr[j+gap]){
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    }
                }
            }
        }
        
    }
}

2)移动法

package com.sort;

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

public class ShellSort {
    public static void main(String[] args) {
//        int[] arr = {8,9,1,7,2,3,5,4,6,0};

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

        Date data1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String date1Str = simpleDateFormat.format(data1);
        System.out.println("排序前的时间是 = " + date1Str);

       // shellSort(arr);
        shellSort2(arr);

        Date data2 = new Date();
        String date2Str = simpleDateFormat.format(data2);
        System.out.println("排序后的时间是 = " + date2Str);
    }

    public static void shellSort(int[] arr){
        int temp = 0;

        //根据规律可得
        for (int gap = arr.length / 2; gap > 0; gap /= 2){
            for (int i = gap; i < arr.length; i++){
                //遍历各组中所有的元素(共arr.length / 2组)
                for (int j = i - gap; j >= 0; j -= gap){
                    //如果当前元素大于加上步长后的那个元素,说明交换
                    if (arr[j] > arr[j+gap]){
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    }
                }
            }
           // System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));

        }


}

    //对交换式的希尔排序进行优化 -> 移位法
    public static void shellSort2(int[] arr){
        //增量gap,并逐步缩小
        for (int gap = arr.length / 2; gap > 0; gap /= 2){
            //从第gap个元素,逐个对其所在的组进行直接插入排序
            for (int i = gap; i < arr.length; i++){
                int j = i;
                int temp = arr[j];
                if (arr[j] < arr[j-gap]){
                    while(j - gap >= 0 && temp < arr[j - gap]){
                        //移动
                        arr[j] = arr[j-gap];
                        j -= gap;
                    }
                    //当退出while后,就给temp找到插入的位置
                    arr[j] = temp;
                }
            }
            //System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));
        }
    }
}


总结

以上就是本章要讲的内容,本文仅仅简单复述了老师讲课的文本内容,内容有误麻烦联系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值