插入排序、希爾排序、冒泡排序、快速排序、選擇排序、歸併排序

代碼原創,引用他人模型演示

一、插入排序

直接插入插排的基本思想是:當插入第i(i >= 1)時,前面的元素已經排好序。
時間複雜度爲O(n^2)

73-插入排序——直接插入排序 - 專注於linux,網絡安全 - CSDN博客
https://blog.csdn.net/qq_35733751/article/details/81713061

(動圖做的真形象)
在這裏插入圖片描述

    public int[] insert(int[] arr) {
        int[] a = arr;
        //只有一個元素
        if (a.length <= 1)
            return null;
        //超過一個元素
        for (int i = 1; i < a.length; i++) {
            int b = a[i];
            int j = i - 1;
            //相比較和將較大的數往後放
            while (j >= 0 && b < a[j]) {
                a[j + 1] = a[j];
                j--;
            }
            //大於當前位置的最大數,固定位置
            a[j + 1] = b;
        }
        return a;
    }

二、希爾排序

算法解釋如下:

希爾排序--簡單易懂圖解 - 祥哥的說 - CSDN博客
https://blog.csdn.net/qq_39207948/article/details/80006224

(吐槽:這倆和尚除了唸經真的啥都會)

    public void shell(int[] arr){
        int N=arr.length;
        //確定增量
        for (int gap=N/2;gap>0;gap/=2){
            //分組,依次進行插入排序
            for (int i=gap;i<N;i++){
                insertI(arr,gap,i);
            }
        }
    }
    //插入排序
    public void insertI(int[] arr,int gap,int i){
        int tmp=arr[i];
        //記錄排序後的位置
        int j=i-gap;
        //對已經分組的元素進行插入排序
        while(j>=0&&tmp<arr[j]){
            arr[j+gap]=arr[j];
            j-=gap;
        }
        arr[j+gap]=tmp;
    }

三、冒泡排序

冒泡排序是一種比較簡單的排序算法(找最小值或最大值),循環所有元素,依次比較相鄰的兩個元素,如果小於(大於)就交換,直至沒有元素交換,完成排序。
時間複雜度爲O(n^2)

寫文章-CSDN博客
https://mp.csdn.net/mdeditor/103040244#
在這裏插入圖片描述

    public int[] foam(int[] arr) {
        int[] a = arr;
        if (a.length <= 1)
            return null;
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < a.length - i - 1; j++) {
                //相鄰位置互相比較,將最大值放在最後
                if (a[j] > a[j + 1]) {
                    int b = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = b;
                }
            }
        }
        return a;
    }

四、快速排序

這個解釋的很詳細且生動了

快速排序—(面試碰到過好幾次) - nrsc - CSDN博客
https://blog.csdn.net/nrsc272420199/article/details/82587933

根據個人理解寫的代碼

    /*
    * main中傳參
    * quick(arr, 0, arr.length - 1);
    * */
    public void quick(int[] arr, int low, int high) {
        if (arr.length<=1)
            return;
        int[] a = arr;
        //首
        int i = low;
        //尾
        int j = high;
        //退出條件
        if (low > high)
            return;
        //基值
        int x = a[low];
        //low!=high
        while (i < j) {
            //從右到左找到大於基值的數
            while (i < j & a[j] >= x) {
                j--;
            }
            a[i] = a[j];
            //從左到右找到小於基值的數
            while (i < j && a[i] < x) {
                i++;
            }
            a[j] = a[i];
        }
        //i=j;賦中值(很關鍵,不能忘)
        a[i] = x;
        //low=high
        quick(a, low, i - 1);
        quick(a, i + 1, high);
    }

五、選擇排序

工作原理是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到全部待排序的數據元素排完。
選擇排序是不穩定的排序方法。
原因:在一趟選擇,如果一個元素比當前元素小,而該小的元素又出現在一個和當前元素相等的元素後面,那麼交換後穩定性就被破壞了。
如:序列5 8 5 2 9,我們知道第一遍選擇第1個元素5會和2交換,那麼原序列中兩個5的相對前後順序被破壞了,所以選擇排序是一個不穩定的排序算法。

此處多寫一個遞歸的例子

    public void select(int[] arr, int k) {
        if (arr.length<=1)
            return;
        /*
        * 利用遞歸循環或者for循環
        * */
        //遞歸
        //退出條件
        if (k == arr.length - 1) return;
        int a = arr[k];
        int b = 0;
        int c = arr[k];
        //找到待排序元素的最小值,放在待排序列表的首位
        for (int i = k; i < arr.length - 1; i++) {
            if (a > arr[i + 1]) {
                a = arr[i + 1];
                b = i + 1;
            }
        }
        //避免本身就是最大值
        if (b != 0)
            arr[b] = c;
        arr[k] = a;
        k++;
        select(arr, k);
    }

for循環解決

    public void select(int[] arr, int k) {
        for (int i = 0; i < arr.length - 1; i++) {
            int tmp = i;
            //找到最大值
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[tmp] > arr[j]) {
                    tmp = j;
                }
            }
            //避免本身就是最大值
            if (tmp != i) {
                //兩兩互換位置
                int a = arr[tmp];
                arr[tmp] = arr[i];
                arr[i] = a;
            }
        }
    }

六、歸併排序

歸併排序_嗶哩嗶哩 (゜-゜)つロ 乾杯~-bilibili
https://www.bilibili.com/video/av9982752?from=search&seid=4684025026002002014

(視頻講的很細緻)

個人理解:
在這裏插入圖片描述
歸併是對分治的兩個組合元素進行比較和排序
主要實現方法是:
利用中值,將分治的左右兩個元素分別存在在左右數組Left和Right,用i,j,k表示Left,Right,arr的指針,將兩個數組的最小值放入arr數組當中(第一次分治的時候只有兩個元素,因此,當前元素合併之後,一定是排序好的),根據分治的遞歸,完成排序的工作.
附上完整代碼

    //歸併排序
    public void merge(int[] arr, int L, int M, int R) {
        //利用中值M,將兩組數分割
        int Left_arr[] = new int[M - L];
        int Right_arr[] = new int[R - M + 1];
        //Left
        for (int i = L; i < M; i++) {
            Left_arr[i - L] = arr[i];
        }
        //Right
        for (int i = M; i <= R; i++) {
            Right_arr[i - M] = arr[i];
        }
        //i代表Left,j代表Right,k代表arr
        int i = 0, j = 0, k = L;
        //歸併
        while (i < Left_arr.length && j < Right_arr.length) {
            if (Left_arr[i] <= Right_arr[j]) {
                arr[k] = Left_arr[i];
                i++;
                k++;
            } else {
                arr[k] = Right_arr[j];
                j++;
                k++;
            }
        }
        //左側存在剩餘元素
        while (i < Left_arr.length) {
            arr[k] = Left_arr[i];
            i++;
            k++;
        }
        //右側存在剩餘元素
        while (j < Right_arr.length) {
            arr[k] = Right_arr[j];
            j++;
            k++;
        }
    }

    public void merge_sort(int[] arr, int L, int R) {
        //退出條件,只有一個元素
        if (L == R)
            return;
        //求中值
        int M = (R + L) / 2;
        //左    第一次執行時,L=0,R=1,M=0
        merge_sort(arr, L, M);
        //右   第一次執行時,L=0,R=1,M=0
        merge_sort(arr, M + 1, R);
        //左右歸併
        merge(arr, L, M + 1, R);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章