八大排序———快速排序
快速排序(Quicksort)是對氣泡排序的一種改進。
快速排序由C.A.R.Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,將整個排序過程可以遞迴進行,依次達到整個資料變成有序序列。
一:演算法思想
假設要排序的陣列是A[0]......A[N-1],首先任意選取一個數據(通常情況下都是選擇陣列的第一個元素)作為關鍵資料,然後將所有比它小的數都放在它前面,所有比他大的數都放在後面,這個過程稱為一趟快速排序。它是一種不穩定的演算法。
一趟快速排序的思想是:
①:設定兩個遍歷變數,i和j。排序開始時 i=0;j=N-1
②:以第一個資料元素作為關鍵資料,賦值給key,即:key = A【0】;
③:從j開始向前搜尋,j--,找到第一個小於key的值A【j】,將A【j】和A【i】互換;
④:此時,再從i開始向後搜尋,i++,找到第一個大於key的A【i】,將A【i】和A【j】互換;
⑤:重複第3和4步,知道i=j;
二:過程演示
然後此時i=j那個位置的元素置為key 15,他的位置已經確定了。
然後在對這個位置之前的元素和之後的重複該過程。
三:程式碼分析
#include<stack> #include<iostream> using namespace std; template<typename T> int QSF(T arr[],int left,int right) { T key = arr[left]; while(left < right) { while(arr[right] >= key && left < right)//當我們的left和right元素相同時可能匯出先死迴圈問題 { --right; } arr[left] = arr[right]; while(arr[left] <= key && left < right) { ++left; } arr[right] = arr[left]; } if(left == right) { arr[left] = key; return left; } else return -1; } template<typename T> void QuickSortfun(T arr[],int left,int right) { if(left>=right) return; int index = QSF(arr,left,right); if(index == -1) { cout<<"the index is error:!"<<endl; return ; } QuickSortfun(arr,left,index-1); QuickSortfun(arr,index+1,right); } template<typename T> void QuickSort(T arr[],int len) { QuickSortfun(arr,0,len-1);//遞迴實現 } int main() { int arr[]={12,16,46,89,9,99,49,16,67,34,13,16}; int len = sizeof(arr)/sizeof(arr[0]); QuickSort(arr,len); for(int i=0;i<len;++i) { cout<<arr[i]<<" "; } cout<<endl; return 0; }
三:時間複雜度和空間複雜度
快速排序的平均時間複雜度為O(n*log n),最壞的時間複雜度為O(2^n)。
分析:
1.最優情況:在最優的情況下,Partion每次都劃分的很均勻,如果排序n個關鍵字,那麼遞迴樹的深度就是[log2 n] +1,(每次都是除以2的關係。2^n = x => x =log2 n),每次Partion的迴圈次數(查詢index)為O(n),所以總的時間複雜度為O(n*log2 n)。空間複雜度為O(log2 n)。
2.最壞情況:當資料是正序或者逆序的時間,每次劃分只得到比上一次換分少一個記錄的的子序列,所以要劃分n-1,也就是要遞迴n-1次,同時第i此劃分,需要經過n-i次的比較才能得到index的位置,所以此時的時間複雜度為O(n^2)。
四:演算法穩定性
是一種不穩定的排序演算法。
五:非遞迴實現——迴圈實現
#include<stack>
#include<iostream>
using namespace std;
template<typename T>
int QSF(T arr[],int left,int right)
{
T key = arr[left];
while(left < right)
{
while(arr[right] >= key && left < right)//當我們的left和right元素相同時可能匯出先死迴圈問題
{
--right;
}
arr[left] = arr[right];
while(arr[left] <= key && left < right)
{
++left;
}
arr[right] = arr[left];
}
if(left == right)
{
arr[left] = key;
return left;
}
else
return -1;
}
template<typename T>
void QuickSortfunnotR(T arr[],int left,int right)
{
if(left >= right )return;
stack<int> s;
s.push(right);//入棧,先入right
s.push(left);
int i = 0;
int j = 0;
while(!s.empty())
{
i = s.top();//出棧先出left
s.pop();
j = s.top();
s.pop();
int index = QSF(arr,i,j);
if(j - index > 1)
{
s.push(j);
s.push(index+1);
}
if(index - i > 1)
{
s.push(index-1);
s.push(i);
}
}
}
template<typename T>
void QuickSort(T arr[],int len)
{
QuickSortfunnotR(arr,0,len-1);//迴圈實現
// QuickSortfun(arr,0,len-1);//遞迴實現
}
int main()
{
int arr[]={12,16,46,89,9,99,49,16,67,34,13,16};
int len = sizeof(arr)/sizeof(arr[0]);
QuickSort(arr,len);
for(int i=0;i<len;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
return 0;
}
六:快排的優化
待更新。