快速選擇排序演算法,選擇排序演算法
快速排序是對冒泡法排序的一種改進。
1 排序思想:
通過一趟排序,將待排序記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小;再分別對這兩部分記錄進行下一趟分割排序,以達到整個序列有序,重複執行以上的劃分操作,直 到所有要進行排序的資料變為有序為止。
可能僅根據基本思想對快速排序的認識並不深,接下來以對n個無序數列A[0], A[1]…, A[n-1]採用快速排序方法進行升序排列為例進行講解。
(1)定義兩個變數low和high,將low、high分別設定為要進行排序的序列的起始元素和最後一個元素的下標。第一次,low和high的取值分別為0和n-1,接下來的每次取值由劃分得到的序列起始元素和最後一個元素的下標來決定。
(2)定義一個變數key,接下來以key的取值為基準將數組A劃分為左右兩個部分,通 常,key值為要進行排序序列的第一個元素值。第一次的取值為A[0],以後毎次取值由要劃 分序列的起始元素決定。
(3)
從high所指向的數組元素開始向左掃描,掃描的同時將下標為high的數組元素依次與劃分基準值key進行比較操作,直到high不大於low或找到第一個小於基準值key的數組元素,然後將該值賦值給low所指向的數組元素
(4)如果low依然小於high,那麼由low所指向的數組元素開始向右掃描,掃描的同時將下標為low的數組元素值依次與劃分的基準值key進行比較操作,直到low不小於high或找到第一個大於基準值key的數組元素,然後將該值賦給high所指向的數組元素。
(5)重複步驟(3) (4),直到low的植不小於high為止,這時成功劃分後得到的左右兩部分分別為A[low……pos-1]和A[pos+1……high],其中,pos下標所對應的數組元素的值就是進行劃分的基準值key,所以在劃分結束時還要將下標為pos的數組元素賦值 為 key。
(6)將劃分得到的左右兩部分A[low……pos-1]和A[pos+1……high]繼續採用以上操作步驟進行劃分,直到得到有序序列為止。
為了能夠加深讀者的理解,接下來通過一段代碼來瞭解快速排序的具體實現方法。
複製純文字新視窗
- #include <stdio.h>
- #include <stdlib.h>
- #include <iostream>
- using namespace std;
-
- int partition(int arr[], int low, int high)
- {
- int key;
- key = arr[low]; // 定義一個變數key,接下來以key的取值為基準將數組A劃分為左右兩個部分
- while(low<high)
- {
//從high所指向的數組元素開始向左掃描,掃描的同時將下標為high的數組元素依次與劃分基準值key進行比較操作; //直到high不大於low或找到第一個小於基準值key的數組元素,然後將該值賦值給low所指向的數組元素 while(low <high && arr[high]>= key ) high--; arr[low] = arr[high]; //如果low依然小於high,那麼由low所指向的數組元素開始向右掃描,掃描的同時將下標為low的數組元素值依次與劃分的基準值key進行比較操作; //直到low不小於high或找到第一個大於基準值key的數組元素,然後將該值賦給high所指向的數組元素。 while( low<high && arr[low]<=key ) low++; arr[high] = arr[low]; } //重複步驟(3) (4),直到low的植不小於high為止,這時成功劃分後得到的左右兩部分分別為A[low……pos-1]和A[pos+1……high]; //其中,pos下標所對應的數組元素的值就是進行劃分的基準值key arr[low] = key; return low; }
- void quick_sort(int arr[], int start, int end)
- {
- int pos=0;
- if (start<end)
- {
- pos = partition(arr, start, end);
- quick_sort(arr,start,pos-1);
- quick_sort(arr,pos+1,end);
- }
- return;
- }
- int main(void)
- {
- int i=0;
- int arr[]={32,12,7, 78, 23,45};
- int N=sizeof(arr)/sizeof(arr[0]);
-
- cout<<"排序前,對於數組中元素的輸出"<<endl;
- for(i=0;i<N;i++)
- cout<<arr[i]<<endl;
- quick_sort(arr,0,N-1);
- cout<<"進行輸出排序之後的數組元素"<<endl;
- for(i=0; i<N; i++)
- cout<<arr[i]<<endl;
- system("pause");
-
- return 0;
- }
#include <stdio.h>#include <stdlib.h>#define N 6int partition(int arr[], int low, int high){ int key; key = arr[low]; while(low<high){ while(low <high && arr[high]>= key ) high--; if(low<high) arr[low++] = arr[high]; while( low<high && arr[low]<=key ) low++; if(low<high) arr[high--] = arr[low]; } arr[low] = key; return low;}void quick_sort(int arr[], int start, int end){ int pos; if (start<end){ pos = partition(arr, start, end); quick_sort(arr,start,pos-1); quick_sort(arr,pos+1,end); } return;}int main(void){ int i; int arr[N]={32,12,7, 78, 23,45}; printf("排序前 \n"); for(i=0;i<N;i++) printf("%d\t",arr[i]); quick_sort(arr,0,N-1); printf("\n 排序後 \n"); for(i=0; i<N; i++) printf("%d\t", arr[i]); printf ("\n"); system("pause"); return 0;}運行結果:
排序前32 12 7 78 23 45排序後7 12 23 32 45 78
在上面的代碼中,根據前面介紹的步驟一步步實現了快速排序演算法。接下來通過來示範第一次劃分操作。
在第一次劃分操作中,先進行初始設定,key的值是進行劃分的基準,其值為要劃分數 組的第一個元素值,在上面的排序序列中為第一個元素值32,同時將low設定為要排序數組中第一個元素的下標,第一次排序操作時其值為0,將high設定為要排序序列最後一個 元素的下標,在上面的排序序列中其第一次取值為5。先將下標為high的數組元素與key進行比較,由於該元素值大於key,因此high向左移動一個位置繼續掃描。由於接下來的值為 23,小於key的值,因此將23賦值給下標為low所指向的數組元素。接下來將low右移一 個位置,將low所指向的數組元素的值與key進行比較,由幹接下來的12、7都小於key, 因此low繼續右移掃描,直至下標low所指向的數組元素的值為78即大於key為止,將78賦值給下標為high所指向的數組元素,同時將high左移一個位置。接下來由於low不再小於high,劃分結束。需要注意的是,在進行劃分的過程中,都是將掃描的值與key的值進行對比,如果小於key,那麼將該值賦值給數組中的另外一個元素,而該元素的值並沒有改變。 可以看出這一點,所以需要在劃分的最後將作為劃分基準的key值賦值給下標為 pos的數組元素,這個元素不再參與接下來的劃分操作。
第一次劃分操作
第一輪劃分結束後,得到了左右兩部分序列A[0]、A[1]、A[2]和A[4]、A[5],繼續進 行劃分,即對毎輪劃分後得到的兩部分序列繼續劃分,直至得到有序序列為止。
選擇排序演算法的思想是什?
每一次都選擇當前序列的最值:
例 1,3,6,9,5 從小到大排序!
第一步 1
第二步 1,3
第三步 1,3,5
第四步 1,3,5,6
第五步 1,3,5,6,9
//遞增選擇排序的實現!
void SelectSort(double *head, int amount)
{
double temp;
int m,n;
for (m=0; m<amount-1; m++)
{
for (n=m+1; n<amount; n++)
{
if (head[n]<head[m])
{
temp=head[n];
head[n]=head[m];
head[m]=temp;
}
}
}
}
冒泡、直插、選擇、快速、希爾、歸併排序演算法進行比較
(1)冒泡排序
冒泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,如果兩個元素相等,我想你是不會再無聊地把他們倆交換一下的;如果兩個相等的元素沒有相鄰,那麼即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前後順序並沒有改變,所以冒泡排序是一種穩定排序演算法。
(2)選擇排序
選擇排序是給每個位置選擇當前元素最小的,比如給第一個位置選擇最小的,在剩餘元素裡面給第二個元素選擇第二小的,依次類推,直到第n-1個元素,第n個元素不用選擇了,因為只剩下它一個最大的元素了。那麼,在一趟選擇,如果當前元素比一個元素小,而該小的元素又出現在一個和當前元素相等的元素後面,那麼交換後穩定性就被破壞了。比較拗口,舉個例子,序列5 8 5 2 9,我們知道第一遍選擇第1個元素5會和2交換,那麼原序列中2個5的相對前後順序就被破壞了,所以選擇排序不是一個穩定的排序演算法。
(3)插入排序
插入排序是在一個已經有序的小序列的基礎上,一次插入一個元素。當然,剛開始這個有序的小序列只有1個元素,就是第一個元素。比較是從有序序列的末尾開始,也就是想要插入的元素和已經有序的最大者開始比起,如果比它大則直接插入在其後面,否則一直往前找直到找到它該插入的位置。如果碰見一個和插入元素相等的,那麼插入元素把想插入的元素放在相等元素的後面。所以,相等元素的前後順序沒有改變,從原無序序列出去的順序就是排好序後的順序,所以插入排序是穩定的。
(4)快速排序
快速排序有兩個方向,左邊的i下標一直往右走,當a[i] <= a[center_index],其中center_index是中樞元素的數組下標,一般取為數組第0個元素。而右邊的j下標一直往左走,當a[j] > a[center_index]。如果i和j都走不動了,i <= j, 交換a[i]和a[j],重複上面的過程,直到i>j。交換a[j]和a[center_index],完成一趟快速排序。在中樞元素和a[j]交換的時候,很有可能把前面的元素的穩定性打亂,比如序列為 5 3 3 4 3 8 9 10 11,現在中樞元素5和3(第5個元素,下標從1開始計)交換就會把元素3的穩定性打亂,所以快速排序是一個不穩定的排序演算法,不穩定發生在中樞元素和a[j] 交換的時刻。
(5)歸併排序
歸併排序是把序列遞迴地分成短序列,遞迴出口是短序列只有1個元素(認為直接有序)或者2個序列(1次比較和交換),然後把各個有序的段序列合并成一個有序的長序列,不斷合并直到原序列全部排好序。可以發現,在1個或2個元素時,1個元素不會交換,2個元素如果大小相等也沒有人故意交換,這不會破壞穩定性。那麼,在短的有序序列合并的過程中,穩定是是否受到破壞?沒有,合并過程中我們可以保證如果兩個當前元素相等時,我們把處在前面的序列的元素儲存在結果序列的前面,這樣就保證了穩定性。所以,歸併排序也是穩定的排序演算法。
(6)基數排序
基數排序是按照低位先排序,然後收集;再按照高位排序,然後再收集;依次類推,直到最高位。有時候有些屬性是有優先順序順序的,先按低優先順序排序,再按高優先順序排序,最後的次序就是高優先順序高的在前,高優先順序相同的低優先順序高的在前。基數排序基於分別排序,分別收集,所以其是穩定的排序演算法。
(7)希爾排序(shell)
希爾排序是按照不同步長對元素進行插入排序,當剛開始元素很無......餘下全文>>