1. 程式人生 > >選擇排序和插入排序

選擇排序和插入排序

fin 操作 有序 序列 pla 結果 臨時變量 bre 變量

選擇排序

選擇排序的思想非常簡單,很多書或技術Blog都講的很好,這裏不贅述了,直接給出代碼

 1 void selectionSort(int arr[],int n){
 2     for(int i = 0;i<n;i++){
 3         int minIdx = i;
 4         for(int j = i+1;j<n;j++){
 5             if(arr[j]<arr[minIdx])
 6                 minIdx = j;
 7         }
 8         swap(arr[i],arr[minIdx]);
9 } 10 }

如果考慮通用性,可以使用模板函數

 1 template<typename T>
 2 void selectionSort(T arr[],int n){
 3     for(int i = 0;i<n;i++){
 4         int minIdx = i;
 5         for(int j = i+1;j<n;j++)
 6             if(arr[j]<arr[minIdx])
 7                 minIdx = j;
 8         swap(arr[i],arr[minIdx]);
9 } 10 }

插入排序

插入排序的思想非常簡單,無論是經典教材《算法導論》還是不少技術文章都以撲克牌為例,手裏的牌是有序的,每拿到一張新牌會為它在排好序的牌中找出合適的位置插入。

代碼如下:

 1 void insertion_sort(int arr[],int n){
 2     for(int i =1;i<n;i++){
 3         for(int j = i+1;j<n-1;j++){
 4             if(arr[j+1]<arr[j])
 5                 swap(arr[j],arr[j+1
]); 6 else 7 break; 8 } 9 } 10 return; 11 }

對比選擇排序,雖然都是O(N^2)級別的,但是,我們發現,插入排序可以提前結束退出,所以理論上講插入排序應該比選擇排序快,這裏,可以寫個測試測試一下。測試結果,發現,比選擇排序慢,仔細觀察,我們發現,在第二層循環中,每當出現逆序(比較操作)就swap(),swap()函數的實現,我們在大學剛學習高級語言程序設計時應該就學過,它需要一個臨時變量,三句實現,需要花費三倍於比較時間。對於數組來說,還有訪問操作,那能不能改進插入排序算法,使之在第二層循環中只交換一次呢。當然,答案是可以的。

首先,我們把要考查的當前元素復制一份,接著將該元素副本與已排好序的元素比較,只要比當前元素大,就後移,最終不再移動的位置就應該是當前要考察元素的位置,等有時間了,我會把這段思考過程用圖片的形式演示出來,下面先放上代碼

 1 void insertion_sort_opti(int arr[],int n){
 2     for(int i = 0;i<n;i++){
 3         int cur = arr[i] // copy the current element
 4         int j;//define j,j is the aultimate index of the curr
 5         for(int j = i;j>0&& arr[j-1]>cur;j--){
 6             arr[j] = arr[j-1];
 7         }
 8         arr[j] = cur;
 9     }
10     return;
11 }

希爾排序

之所以把希爾排序列在這裏,是因為希爾排序也是一種插入排序,希爾排序整體的思路就是插入排序的延伸,在插入排序中,每一次都和之前的一個元素進行比較,而希爾排序是每一次都和之前的第h個元素進行比較,h從一個很大的值逐漸減小為1,一步步將一個完全無序的數組變成一個近乎有序的數組,變成有序性越來越強的數組,直到最後變成一個有序的數組,不難理解,希爾排序會更高效,因為插入排序對於有序數組的可以達到線性的時間復雜度,既然是插入排序的延伸,依然給出未優化的和優化的版本,實現如下:

V1

 1 void shell_sort(int arr[],int n){
 2     int h = 1;//make sure the last step h =1
 3     while(h*3<n) h = h*3+1;
 4     while(h>=1){
 5         // like to insertion sort,start with teh second element
 6         for(int i = 1;i<n;i++){
 7             for(int j = i;j>=h;j-=h){ //j starts with current(i-th)
 8                 if(arr[j]<arr[j-h]) //element,compare with (j-h)th
 9                     swap(arr[j],arr[j-h]); //element,if less than
10                 else                       // swap
11                     break;
12             }
13         }
14         h/=3;
15     }
16 }

優化版本

 1 void shell_sort_opti(int arr[],int n){
 2     int h = 1;
 3     while(h<n/3) h = h*3+1;
 4     while(h>=1){
 5         for(int i = 1;i<n;i++){
 6             int curr = arr[i];
 7             int j;
 8             for(j = i;j>=h;j-=h)
 9                 if(arr[j]<curr)
10                     arr[j] = arr[j-h];
11             arr[j] = curr;
12         }
13         h/=3;
14     }
15 }

選擇排序和插入排序