交換排序(氣泡排序/快速排序)及其優化
阿新 • • 發佈:2018-12-13
交換排序基本思想
兩兩比較待排記錄的關鍵字,一旦發現兩個記錄的次序與排序的要求相逆,則交換這兩個記錄的位置,直到表中沒有逆序的記錄存在為止。
分類
- 氣泡排序
- 快速排序(對冒泡的改進)
<1>氣泡排序
基本思想:序列中相鄰的兩個元素進行比較,如果前一個元素大於後一個元素,則交換二者位置,接著繼續向後迴圈比較直到最後一個元素,這樣一趟下來就可以將最大的那個元素放到最後的位置。完成之後,進行第二趟排序,迴圈比較直到倒數第二個元素,就可以將第二大元素放於倒數第二個位置......迴圈以上步驟,直到迴圈比較到原陣列的最後兩個元素,排序即可完成。
程式碼體現:
void bubble_sort(int arr[],int len) { for(int i=0;i<len-1;i++) //排序的趟數,n個數就需要排序n-1趟 { bool flag=true; //一個小小的優化,在某一趟如果沒有改變就不再進行最外層迴圈了 for(int j=0;j<len-i-1;j++) //每一趟中的交換排序 { if(arr[j]>arr[j+1]) { swap(arr[j],arr[j+1]); flag=false; //進入這個判斷就證明排序沒有完成 } } if(flag) break; } }
複雜度分析:
1:空間複雜度:可以看出並沒有什麼大的額外空間,所以為O(1);
2:時間複雜度:
- 最好情況下,待排序列已經是有序的,這樣氣泡排序在第一趟排序過程就沒有交換髮生,所以一趟之後即排序結束。也即,只在第一趟中進行了n-1次比較。最壞情況是待排序列記錄按逆序排序,所以需要進行n-1趟排序,且第i趟需要進行n-i次比較。所以總的比較次數為1/2*n*(n-1);所以氣泡排序的時間複雜度為O(n²)。
3:演算法穩定性:
氣泡排序並未改變相同元素的先後次序,所以是穩定的排序演算法
<2>快速排序
基本思想:快速排序就是氣泡排序的一種改進,氣泡排序是通過每一趟冒泡將最大值(最小值)放到恰當位置,而快速排序則是每趟排序從待排序區間選一個基準值(也稱作樞紐值),將比它小的資料全放在其左邊,將比它大的值放在其右邊然後遞迴其左右子區間對其排序,一層層遞迴下去,某區直到間只剩一個數據時,停止遞迴,此子區間已經算是有序,繼而向其上層區間返回,一層層向上返回,當首次樞紐值的左右區間均已有序時,整個排序就算完成。
遞迴程式碼:
#include<iostream> using namespace std; int Partition(int *arr,int low,int high) //劃分演算法,找到元素正確位置 { int tmp=arr[low]; //從第一個元素作為基準進行劃分 while(low<high) //從序列兩端交替向中間掃描 { while(arr[high]>=tmp&&low<high) //從右向左掃描查詢第一個小於基準的 high--; if(low<high) //找到小於基準的數,將其交換到表的左邊 { arr[low]=arr[high]; low++; //因為本位low已存從右邊拿來的資料,所以low往後移 } while(arr[low]<=tmp&&low<high) //從左往右找第一個大於基準的元素 low++; if(high>low) //找到大於基準的數,將其交換到表的右邊 { arr[high]=arr[low]; high--; } } arr[low]=tmp; //最終的low/high位置即是基準在序列中的最終位置,放入即可 return low; //返回基準的最終位置下標 } void QuickSort(int *arr,int low,int high) //遞迴形式的快排 { int i; if(low<high) { i=Partition(arr,low,high); //以i為基準將序列分為兩部分 if(i-low>1) //避免一次遞迴呼叫,左邊沒有元素或者只有一個就不用排序 QuickSort(arr,low,i-1); //左半邊進行排序 if(high-i>1) QuickSort(arr,i+1,high); //右半邊進行排序 } } void Show(int *arr,int len) { for(int i=0;i<len;i++) cout<<arr[i]<<" "; cout<<endl; } int main() { int arr[]={61,33,48,82,72,11,25,48}; int len=sizeof(arr)/sizeof(arr[0]); QuickSort(arr,0,len-1); Show(arr,len); }
非遞迴程式碼(我們都知道棧與遞迴很相似,那麼我們就可以用棧來替換遞迴)
#include<iostream>
#include<stack>
#include<assert.h>
using namespace std;
void QuickSort(int *arr,int low,int high)
{
assert(arr);
if(low>=high)
throw "error";
int i=low;
int j=high;
stack<int> s;
s.push(i);
s.push(j);
while(!s.empty())
{
j=s.top();
high=j;
s.pop();
i=s.top();
low=i;
s.pop();
int tmp=arr[i];
while(i<j)
{
while(i<j&&arr[j]>=tmp)
j--;
if(i<j)
{
arr[i]=arr[j];
i++;
}
while(i<j&&arr[i]<=tmp)
i++;
if(i<j)
{
arr[j]=arr[i];
j--;
}
}
arr[i]=tmp;
if(high-j>1)
{
s.push(j+1);
s.push(high);
}
if(i-low>1)
{
s.push(low);
s.push(i-1);
}
}
}
void Show(int *arr,int len)
{
for(int i=0;i<len;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
int main()
{
int arr[]={47,47,55,1,47,47};
int len=sizeof(arr)/sizeof(arr[0]);
QuickSort(arr,0,len-1);
Show(arr,len);
}