O(N^2)排序算法分析:選擇排序和插入排序


一。選擇排序(從小到大):

基本思想:每次遍歷數組,找到當前數組中最小的一個元素,與第一個元素調換位置。

第一次排序:遍歷8個元素,找到當前數組中最小元素2,與第一個元素調換,此時,2現在的位置就是其最終的位置

第二次排序:從第二個元素開始遍歷,找到最小的元素4,與第二個元素8對調位置

 

 第三次排序最小的元素時5,與當前位置對換,即可以理解為自己和自己對換位置,第三次排序后的結果為:2 4 5 7 6 8 9 7,按照同樣的方法,可以得到

第四次排序結果:2 4 5 6 7 8 9 7 ,第五次排序結果:2 4 5 6 7 8 9 7 ,第六次排序結果:2 4 5 6 7 7 8 9  ,第七次排序結果 :2 4 5 6 7 7 8 9 第八次排序結果:2 4 5 6 7 7 8 9。

因此對於選擇排序,可以看出,當第六次的時候已經有序,但后續步驟任然需要進行后續所有元素的遍歷,實現代碼如下:

public static void sort(Comparable[] arr){
        int n = arr.length;
        for(int i = 0; i < n ; i++){
            int minIndex = i;
            for(int j = i+1; j < n ; j++){
                //使用compareTo方法比較兩個Comparable對象的大小
                if(arr[j].compareTo(arr[minIndex]) < 0){
                    minIndex = j;
                }
            }
            SortHelper.swap(arr,i,minIndex);
        }
    }

測試:

public static void main(String[] args) {
        int n = 10000;
        Integer[] arr = SortHelper.generateRandomArray(n,0,n);
        long start = System.currentTimeMillis();
        sort(arr);
        long end = System.currentTimeMillis();
        System.out.println("執行時間"+(double)(end - start)/1000+"s");
        SortHelper.show(arr,arr.length);
    }

執行結果:(n=10000)

(n=100000)

相比兩個測試結果,執行效率差不多慢了100倍。

 二。插入排序(從小到大)

算法思想:從第二個元素開始(默認第一個元素已排序),往前依次比較,如果當前元素比被比較元素小,則和被比較元素交換位置,否則跳出循環,進行下一個元素進行比較

第一次比較過程:

第二次比較過程:

第三次比較:

實現代碼如下:

 public static void sort(Comparable[] arr){
        int n = arr.length;
        for(int i = 1 ; i < n ; i++){
//            for(int j = i ; j > 0 ; j--){
//                if(arr[j].compareTo(arr[j-1])<0){
//                    SortHelper.swap(arr,j,j-1);
//                }else {
//                    break;
//                }
//            }
            //精簡一點的寫法
            for(int j = i ; j > 0 && arr[j].compareTo(arr[j-1])<0 ; j--){
                SortHelper.swap(arr,j,j-1);
            }
        }
    }

測試用例:

 public static void main(String[] args) {
        int n = 10000;
        Integer[] arr = SortHelper.generateRandomArray(n,0,n);
        long start = System.currentTimeMillis();
        sort(arr);
        long end = System.currentTimeMillis();
        assert SortHelper.isSorted(arr);
        System.out.println("執行時間"+(double)(end - start)/1000+"s");
    }

執行結果:

當n相差10倍的時候,執行時間差不多相差了近100倍。

三。算法比較

雖然兩個算法都是O(N^2)的時間復雜度,但是對於插入排序,如果待排序序列接近有序的時候,插入排序的比較次數明顯減少,因此在待排序序列接近有序的時候,插入排序的時間復雜的會接近O(N),同時,本例中插入排序存在着不斷的調換位置的情況,需要消耗一定的時間,下面的我們將對插入排序進行優化。

 交換的次數少一些

   public static void sort2(Comparable[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++) {
            Comparable e = arr[i];
            int j = i;
            for (; j > 0 && arr[j - 1].compareTo(e)> 0; j--) {
                arr[j] = arr[j-1];
            }
            arr[j] = e;
        }
    }

測試結果:

最后,用一個接近有序的序列,再來測試一樣兩種情況

選擇排序測試結果(n=100000 和  n=10000):

 

插入排序測試結果(n=100000 和  n=10000):

 

 

附錄--代碼地址:https://github.com/yohzhangxin/MoocAlgr


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM