【初賽】各種排序演算法總結
阿新 • • 發佈:2018-11-14
一、演算法評價
排序方法 | 平均時間 | 最好時間 | 最壞時間 |
---|---|---|---|
氣泡排序(穩定) | O(n^2) | O(n) | O(n^2) |
選擇排序(不穩定) | O(n^2) | O(n^2) | O(n^2) |
插入排序(穩定) | O(n^2) | O(n) | O(n^2) |
快速排序(不穩定) | O(nlogn) | O(nlogn) | O(n^2) |
歸併排序(穩定) | O(nlogn) | O(nlogn) | O(nlogn) |
堆排序(不穩定) | O(nlogn) | O(nlogn) | O(nlogn) |
基數排序(穩定) | O(n) | O(n) | O(n) |
桶排序(不穩定) | O(n) | O(n) | O(n) |
希爾排序(不穩定) | O(nlogn) | O(n^1.2) | O(n^2) |
其中,冒泡和插入在資料有序時複雜度為只需要O(n),快速排序在資料有序時退化到O(n^2).
二、程式碼實現
1、氣泡排序
- 迴圈n次,每次相鄰的資料兩兩比較,小數放前面,大數放後面
- 這樣每一次操作過後最小的數就被排在了最前面
void BubbleSort(int a[], int n){
for(int i = 1; i < n; i++){ //迴圈有序陣列,每次迴圈後保證到i位置的值是有序的。
for(int j = n; j > i; j--) //迴圈無序陣列兩兩比較
if (a[j] < a[j-1])swap(a[j],a[j-1]); //如果是逆序對就交換(保證每次把最小的值往前交換)
//Print(a,n);
}
}
2、選擇排序
- 在未排序序列中找到最小的元素,記錄位置
- 將它放到已排序序列的末尾(和第一個無序元素交換即可)
void SelecSort(int a[], int n){
for(int i = 1; i <= n; i++){ //對於每一個位置的值(實質是未排序序列的第一個元素)
int index = i; //index:記錄未排序序列中最小元素的位置
for(int j = i+1; j <= n; j++) //遍歷剩餘未排序序列
if(a[j] < a[index])index = j; //保證index是最小元素的位置
swap(a[i],a[index]);//將最小的值放到未排序序列的第一個,完成排序
//for(int i = 1; i <= n; i++)cout<<a[i]<<" "; cout<<"\n";
}
}
3、插入排序
- 資料分為兩部分,一開始有序部分包含1個元素
- 依次將無序部分的元素插入到有序部分當中
void InsertSort(int a[], int n){ //直接插入排序
for(int i = 2; i <= n; i++){ //遍歷無序部分,每次取出第一個元素
int j = i-1, k = a[i]; //j為當前下標, k為無序部分第一個元素
while(j>=1 && k<a[j]){ //找到k元素在有序部分的位置
a[j+1] = a[j]; //迴圈的時候直接右移有序陣列,為k騰出位置
j--; //不是k正確的位置,繼續往前迴圈
}
a[j+1] = k; //出來的時候j多減了1,要加回去
//for(int i = 1; i <= n; i++)cout<<a[i]<<" "; cout<<"\n";
}
}
4、快速排序
- 每次選擇一個基準數,把比之小的都放到其左邊,大的都放到其右邊
- 排放時候的細節
void QuickSort(int a[], int n, int l, int r){
if(l > r)return ; //遞迴出口,越界返回
int k = a[l];//k就是基準數(k的選取與內迴圈的找數順序有關)
int i = l, j = r;//區間
while(i < j){ //i==j時,兩數相遇,
//順序有影響,先從右往左找,找到第一個比基準數小的位置
while(i<j && a[j]>=k)j--;//切記‘>=’(可以忽略掉與k相等的值,不然i永遠不會大於j,則死迴圈)
//然後從左往右找到第一個比基準數大的位置
while(i<j && a[i]<=k)i++;
//如果他們沒有相遇,就交換這兩個數的位置,並繼續尋找
if(i < j)swap(a[i],a[j]);
}
//將基準數歸位
a[l] = a[i]; //相遇的位置
a[i] = k; //
QuickSort(a,n,l,i-1);//遞迴後不用考慮基準數
QuickSort(a,n,i+1,r);
}
5、歸併排序
- 先使每個子序列有序,再使子序列段間有序。
- 遞迴到底層子序列自然有序,段間有序要求每次去合併
void MergeSort(int a[], int n, int l, int r){
if(l == r)return ;
int mid = l+r>>1;
MergeSort(a,n,1,mid);
MergeSort(a,n,mid+1,r);
int i = 1, j = mid+1;
int c[r-l+1], k = 1;
while(i <= mid && j <= r){
if(a[i]<a[j])c[k++] = a[i++];
else c[k++] = a[j++];
}
while(i <= mid)c[k++] = a[i++];
while(j <= r)c[k++] = a[j++];
for(int i = l; i <= r; i++)
a[i] = c[i];
}
6、堆排序