学习数据结构笔记====>不同的排序算法(Sort Algorithm)[冒泡,选择,插入,快速,希尔,基数,归并]

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习数据结构笔记====>不同的排序算法(Sort Algorithm)[冒泡,选择,插入,快速,希尔,基数,归并]相关的知识,希望对你有一定的参考价值。

B站学习传送门–>尚硅谷Java数据结构与java算法(Java数据结构与算法)


写在前面
数组结构可视化在线网站地址 ===>数据结构可视化在线

排序算法: 把一组数据,依指定顺序进行排列的过程.

1.时间复杂度概述

时间频度

时间频度(T(n)) 算法中语句的执行次数

案例
时间频度为 (n+1);
这里的n就是100;
加1是因为最后在循环时还要再判断一次;

public class Demo01 {
    public static void main(String[] args) {
        int total = 0;
        int end = 100;
        for (int i = 1; i <= end; i++) {
            total +=i;
        }
        System.out.println(total);//5050
    }
}

但是若直接简化写为;
时间频度就变成 1 ;因为仅执行一次

public class Demo01 {
    public static void main(String[] args) {
        int total = 0;
        int end = 100;
        total =(end +1 )* end/2;
        System.out.println(total);//5050
    }
}

实际上,常数项可以忽略

低阶的次数项也可以忽略

在同等次方的条件下,和次方项前面的系数有关系;去掉系数后;这个就接近了

时间复杂度

在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f (n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。

时间频度不同,时间复杂度可能相同
例: T(n) = n² + 6n+2 与 T(n) = 2n² + 5n+2
时间复杂度都可写为 O(n²)

Ο(1)<Ο(log₂n)<Ο(n)<Ο(nlog₂n)<Ο(n²)<Ο(n³)< Ο(n^k) <Ο(2ⁿ)
时间复杂度增大,效率变低

常数阶 Ο(1):
只要里面没有循环之类的复杂运算,代码再多也都是O(1)常数阶;
不会因为某个变量的增加而增加消耗的时间

对数阶: Ο(log₂n)
案例:比如说要计算下面这个循环次数;
在while循环内;每次都给 i *2 ;条件是i<1024;
1024 = 2^10; 即 n = 2^10; 那么对应的就是 log₂n = 10; 执行的次数为10次;
即时间复杂度为对数阶O(log₂n);
当然,这个根据实际情况会发生改变; 若 在循环中变为 i = i * 5 ;那么时间复杂度也就是O(log5n)

public class Demo02 {
    public static void main(String[] args) {
        int i = 1;
        int n =1024;
        //num:用来计数
        int num = 0;

        while (i<n){
            i = i * 2 ;
            num++;
        }
        System.out.println("执行次数->"+num); //执行次数->10
    }
}

线性阶:O(n)
单层循环的话,按照循环的规模来决定; 时间复杂度就是O(n)
案例;它的执行次数为 T(n) = n +1 ;
忽略掉常数项 ; 时间复杂度其实就是O(n);
在本案例中循环的规模n=10;那么它时间复杂度为O(10);
当n变为20时,它也就是O(20);总的来说,时间复杂度就是线性阶的O(n)

public class Demo03 {
    public static void main(String[] args) {
        int w =0;
        int num = 0;
        int n =10;
        for (int i = 0; i <= n ; i++) {
            w = num;
            num ++;
        }
        System.out.println(w);  // 10 
        System.out.println("执行次数->"+num);//执行次数->11
    }
}

线性对数阶Ο(nlog₂n)
实际上就是让时间复杂度为O(log₂n)的再循环n次
案例;这里执行次数就是 T(n) = (n+1) * (log₂n)

public class Demo04 {
    public static void main(String[] args) {
        int n =1024;
        int i ;
        //num:用来计数
        int num = 0;
        for (int m = 0; m <= n; m++) {
            i =1;
            while (i<n){
                i = i * 2 ;
                num++;
            }
        }
        System.out.println("执行次数->"+num); //执行次数->10250  (1024+1) * 10
    }
}

平方阶Ο(n²)
实际就是把时间复杂度为O(n)的再嵌套一层循环;即双层循环;也可写作O( m* n)
案例

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

        int w =0;
        int num = 0;
        int m =10;
        int n =10;
        for (int i = 1; i <= m ; i++) {
            for (int j = 1; j <= n; j++) {
                w = num;
                num ++;
            }
        }
        System.out.println(w);  // 99
        System.out.println("执行次数->"+num);//执行次数->100
    }
}

平均&最差时间复杂度

2.冒泡排序

按照提前设定的规则 (由小到大 / 由大到小) ;比较前后两个相邻元素的大小;若逆序了,就发生交换;

例如需要完成由小到大冒泡排序:29,10,14,37,14,3
图示:–>

初始的理解过程

总共经过数组的(长度-1)次大的交换过程;即 5 次;
其实每次大的排序结束后就有一个最大的值固定下来了;所以循环次数会比上一次的少一次
(1)
10 -> 29 -> 14 -> 37 -> 14 -> 3
10 -> 14 -> 29 -> 37 -> 14 -> 3
10 -> 14 -> 29 -> 37 -> 14 -> 3
10 -> 14 -> 29 -> 14 -> 37 -> 3
10 -> 14 -> 29 -> 14 -> 3 -> 37
(2)
10 -> 14 -> 29 -> 14 -> 3 -> 37
10 -> 14 -> 29 -> 14 -> 3 -> 37
10 -> 14 -> 14 -> 29 -> 3 -> 37
10 -> 14 -> 14 -> 3 -> 29 -> 37
(3)
10 -> 14 -> 14 -> 3 -> 29 -> 37
10 -> 14 -> 14 -> 3 -> 29 -> 37
10 -> 14 -> 3 -> 14 -> 29 -> 37
(4)
10 -> 14 -> 3 -> 14 -> 29 -> 37
10 -> 3 -> 14 -> 14 -> 29 -> 37
(5)
3 -> 10 -> 14 -> 14 -> 29 -> 37

分步骤写法;

这里分步骤展示排序过程

public class BubbleSortTest2 {
    public static void main(String[] args) {
        //需要排序的数组
        int[] array = {29,10,14,37,14,3};

        //临时变量,用于前后交换时临时存储;
        int temp = 0;

        //1.第一次排序;
        for (int i = 0; i < array.length - 1; i++) {
            if(array[i] > array[i+1]){
                temp = array[i];
                array[i] = array[i+1];
                array[i+1] =temp;
            }
        }

        System.out.println("第一次排序后-->"+ Arrays.toString(array));
        //第一次排序后-->[10, 14, 29, 14, 3, 37]

        //2.第二次排序;
        for (int i = 0; i < array.length - 1 - 1; i++) {
            if(array[i] > array[i+1]){
                temp = array[i];
                array[i] = array[i+1];
                array[i+1] =temp;
            }
        }

        System.out.println("第二次排序后-->"+ Arrays.toString(array));
        //第二次排序后-->[10, 14, 14, 3, 29, 37]

        //3.第三次排序
        for (int i = 0; i < array.length - 1 - 1 - 1; i++) {
            if(array[i] > array[i+1]){
                temp = array[i];
                array[i] = array[i+1];
                array[i+1] =temp;
            }
        }

        System.out.println("第三次排序后-->"+ Arrays.toString(array));
        //第三次排序后-->[10, 14, 3, 14, 29, 37]

        //4.第四次排序;
        for (int i = 0; i < array.length - 1 - 1 -1; i++) {
            if(array[i] > array[i+1]){
                temp = array[i];
                array[i] = array[i+1];
                array[i+1] =temp;
            }
        }

        System.out.println("第四次排序后-->"+ Arrays.toString(array));
        //第四次排序后-->[10, 3, 14, 14, 29, 37]

        //5.第五次排序;
        for (int i = 0; i < array.length - 1 - 1 -1; i++) {
            if(array[i] > array[i+1]){
                temp = array[i];
                array[i] = array[i+1];
                array[i+1] =temp;
            }
        }

        System.out.println("第五次排序后-->"+ Arrays.toString(array));
        //第五次排序后-->[3, 10, 14, 14, 29, 37]
    }
}

综合写法

public class BubbleSortTest {
    public static void main(String[] args) {
        //需要排序的数组
        int[] array = {29,10,14,37,14,3};
        //调用方法; 完成由大到小排序
        int[] sortArray = BubbleSort(array);
        System.out.println("冒泡排序结果-->"+Arrays.toString(sortArray));
        //冒泡排序结果-->[3, 10, 14, 14, 29, 37]
    }

    public static int[] BubbleSort(int[] array){
        for (int i = 0; i <array.length -1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                //后一个和之前的交换;
                if(array[j] > array[j+1]){
                    int temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
            System.out.println("第"+(i+1)+"次排序后-->"+Arrays.toString(array));
        }

        return array;
    }
}

运行结果

1次排序后-->[10, 14, 29, 14, 3, 37]2次排序后-->[10, 14, 14, 3, 29, 37]3次排序后-->[10, 14, 3, 14, 29, 37]4次排序后-->[10, 3, 14, 14, 29, 37]5次排序后-->[3, 10, 14, 14, 29, 37]
冒泡排序结果-->[3, 10, 14, 14, 29, 37]

稍微优化一下

如果说,我这个数组比较特殊;
例如:3,2,14,37,14,3
看看它的执行步骤;会发现其实第三次它就排序完成了;但还进行了后面的无意义排序;

1次排序后-->[2, 3, 14, 14, 3, 37]2次排序后-->[2, 3, 14, 3, 14, 37]3次排序后-->[2, 3, 3, 14, 14, 37]4次排序后-->[2, 3, 3, 14, 14, 37]5次排序后-->[2, 3, 3, 14, 14, 37]
冒泡排序结果-->[2, 3, 3, 14, 14, 37]

那么,就对之前的冒泡排序优化一下;
在执行时加入标志位的判断;

public class BubbleSortTest3 {
    public static void main(String[] args) {
        //需要排序的数组
        int[] array = {3,2,14,37,14,3};
        //调用方法; 完成由大到小排序
        int[] sortArray = BubbleSort(array);
        System.out.println("冒泡排序结果-->"+Arrays.toString(sortArray));
    }

    public static int[] BubbleSort(int[] array){
        //定义标志位;
        boolean flag =false;
        for (int i = 0; i <array.length -1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                //后一个和之前的交换;
                if(array[j] > array[j+1]){
                    flag = true;
                    int temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
            //对标志位判断后再决定是否继续循环;
            if(flag){
                //重置标志位;
                flag = false;
            }else {
                //表示没发生交换;跳过本次循环;
                break;
            }
            System.out.println("第"+(i+1)+"次排序后-->"+Arrays.toString(array));
        }

        return array;
    }
}

看看执行过程

1次排序后-->[2, 3, 14, 14, 3, 37]2次排序后-->[2, 3, 14, 3, 14, 37]3次排序后-->[2, 3, 3, 14, 14, 37]
冒泡排序结果-->[2, 3, 3, 14, 14, 37]

3.简单选择排序

比如说要定义由小到大的排序;
首先假设数组的第一个数是最小的数;去依次和后面的数进行比较,直到找到一个比它小的,然后将那个数标记为最小的数,接着继续依次比较;直到数组遍历结束;将带有标

以上是关于学习数据结构笔记====>不同的排序算法(Sort Algorithm)[冒泡,选择,插入,快速,希尔,基数,归并]的主要内容,如果未能解决你的问题,请参考以下文章

python 学习笔记 -- 数据结构与算法 冒泡排序 Bubble sort

python 学习笔记 -- 数据结构与算法 插入排序 Insertion Sort

python 学习笔记 -- 数据结构与算法 归并排序 Merge Sort

python 学习笔记 -- 数据结构与算法 快速排序 Quick Sort

python 学习笔记 -- 数据结构与算法 选择排序 Selection Sort

Java学习笔记——排序算法之希尔排序(Shell Sort)