1. 程式人生 > >選擇排序,氣泡排序,插入排序

選擇排序,氣泡排序,插入排序

1.選擇排序

2.氣泡排序/雙向氣泡排序

3.插入排序

1.選擇排序

選擇排序是一種最為直觀的排序方法。每次迴圈從陣列中選擇出一個最小或者最大的元素,按順序重新放入陣列中,直到所有的戴排序元素都排序完成。

複製程式碼

public void selectSort(int[] a){
        int temp=0;
        for(int i=0;i<a.length-1;i++){
            for(int j=i+1;j<a.length;j++){
                if(a[j]<a[i]){
                    temp = a[j];
                    a[j] = a[i];
                    a[i] = temp;
                }
            }
        }
    }

複製程式碼

從程式碼不難看出,選擇排序的過程是:第一次迴圈,遍歷陣列找出陣列中最小的數字,放入a[0],第二次迴圈,找出剩下陣列中最小的數字放入a[1]一次類推。

所以,選擇排序的時間複雜度為O(n^2),如果n較大,則效率會非常低。

2.氣泡排序

氣泡排序也是較為簡單的一種排序方法,之所以叫氣泡排序,是因為排序的手法會使數字浮到陣列頂端而得名。

氣泡排序的手法是:比較相鄰的兩個元素,如果相鄰的兩個元素的順序是錯誤的,則將他們交換;然後繼續比較下一組相鄰的元素。直到所有需要排列的元素都排序完成。

複製程式碼

public void bubbSort(int[] a){
        int temp=0;
        for(int i=0;i<a.length-1;i++){
            for(int j=a.length-1;j>i;j--){
                if(a[j]<a[j-1]){
                    temp = a[j];
                    a[j] = a[j-1];
                    a[j-1] = temp;
                }
            }
        }
    }

複製程式碼

從程式碼我們可以看出來:氣泡排序是用層迴圈,外側迴圈的意義是在於,迴圈n次,每次冒泡都冒出最小的節點依次放在陣列的最前面。第二層迴圈的意義是在於,進行冒泡操作,每次比較相鄰的兩個元素,將較小的元素,像陣列頭方向移動。

因此我們可以看出氣泡排序的時間複雜度為O(n^2),如果n較大,則效率會非常低,如果陣列是有序的,即進行一次冒泡掃描發現移動的關鍵次數為最小時,說明陣列已經有序,此時的時間複雜度為O(n)。

雙向氣泡排序:

傳統的氣泡排序要麼是從左向右進行,要麼從右向左進行,每次都只對陣列一頭的元素進行掃描排序。

而雙向氣泡排序首先從前往後把最大數移到最後,然後反過來從後往前把最小的一個數移動到陣列最前面,這一過程就是第一輪,然後重複這一過程,最終就會把整個陣列從小到大排列好。

複製程式碼

public void bubbSort2(int[] a){
        int left =1 ;
        int right = a.length -1;
        int t=0;
        while(left<=right){
            for(int i=right;i>=left;i--){
                if(a[i]<a[i-1]){
                    int temp;
                    temp = a[i];
                    a[i] = a[i-1];
                    a[i-1] = temp;
                    t = i;//記錄上一次交換的下標
                }
            }
            left = t+1; //t+1中間亂序部分的最左端
            for(int i=left;i<right+1;i++){
                if(a[i]<a[i-1]){
                    int temp;
                    temp = a[i];
                    a[i] = a[i-1];
                    a[i-1] = temp;
                    t = i;//記錄上一次交換的下標
                }
            }
            right = t-1;//t-1為中間亂序部分的最右端
        }
    }

複製程式碼

從程式碼看來,雙向氣泡排序會比普通氣泡排序減少很多次迴圈。因為雙向排序時陣列的兩頭都排序好了,我們只需要處理陣列的中間部分即可,普通氣泡排序只有一頭的元素是排好序的。

雖然雙向氣泡排序有些改進,但是不能大幅度的提升效率,這是由於氣泡排序的基本過程所確定的。

3.插入排序

插入排序的基本方法是,每步將一個待排序的紀錄,按其關鍵碼值的大小插入前面已經排序的檔案中適當位置上,直到全部插入完為止。

複製程式碼

public void insertSort(int[] a){
        for(int i=1;i<a.length;i++){
            int temp = a[i],j=i    ;
            if(a[j-1]>temp){
                while(j>=1&&a[j-1]>temp){//找到新元素合適的位置
                    a[j] = a[j-1];//前一個覆蓋後一個
                    j--;
                }
            }
            a[j]=temp; //插入元素
        }
    }

複製程式碼

直接插入排序最好的時間複雜度為O(n),平均時間複雜度為O(n^2)。同樣的,如果n過於大的時候,直接插入排序的效率會很低。

插入排序改進思路和氣泡排序一樣,我們也可以對於直接插入排序進行改進。在直接插入排序中我們每次插入元素的時候,都是挨個遍歷前面所有元素,這樣遍歷的效率並不高。

因為插入的陣列是已經排好序的有序陣列,所以我們自然而然的想到了折半插入的方法,這樣可以減少比較的次數。

不過雖然折半插入會減少元素比較的次數,但因為是插入陣列,所以,只是減少元素的比較次數,元素移動的個數依然沒有改變,時間複雜度依然是O(n^2)。