前言
你說你熟悉常用的數據結構和算法,談談快速排序算法吧。
解答
首先先給出快速排序的基本思想:
(1)先從數列中選擇一個數作爲基準數
(2)將序列分成兩個區間,小於步驟(1)基準數的放在左區間,大於基準數的放在右區間。
(3)對步驟(2)分出的左右區間重複第二步,直到各區間只有一個數。(遞歸)
代碼如下:
class QuickSort {
public:
int* quickSort(int* A, int n) {
// write code here
if(A==NULL||n<2) return A;
quickSortCore(A,0,n-1);
return A;
}
int RandomInRange(int min, int max)//隨機產生min~max之間的一個數
{
int random = rand() % (max - min + 1) + min;
return random;
}
void quickSortCore(int *A,int left,int right)
{
if(left<right){
int random=RandomInRange(left,right);
swap(A,random,right);
int mid=partition(A,left,right);
quickSortCore(A,left,mid-1);
quickSortCore(A,mid+1,right);
}
}
int partition(int *A,int left,int right){
int pivot=left-1;
int index=left;
while(index<=right){
if(A[index]<=A[right]){
swap(A,++pivot,index);
}
++index;
}
return pivot;
}
void swap(int *arr, int index1, int index2) {
int tmp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = tmp;
}
};
快速排序的平均時間複雜度爲O(N*logN),最壞的情況複雜度爲O(N*N),最壞情況出現在每次切分選的切分元素總是當前切分數組的最小值時。因其在排序過程中,會交換元素打亂數組原本的相對順序,所以快速排序是不穩定的算法。
快速排序改進:
- 因爲在對於小數組來說,快速排序是比插入排序慢的,如果我們需要將我們的排序方法做成庫函數的話,則我們面對的排序對象的特性是未知的,那麼我們可以先判斷數組的大小,如果其大小<某個值的時候,就用插入排序,大於某個值就用快速排序。
在實際應用當中,數組中可能存在着大量重複元素,如我們可能要排序一個公司的所有人員的年齡。在這種情況下,快速排序的遞歸性會使元素全部重複的子數組經常出現,我們可以將數組切分成三部分,分別爲小於,大於和等於切分元素的數組元素。思想爲從左遍歷數組依次,維護一個lt指針使得a[lo….lt-1]的元素都小於切分元素v,一個指針gt使得A[gt+1…hi]中的元素都大於v,一個指針i使得A[lt…i-1]中的元素都等於v。遍歷過程遵循的規則如下:
- A[i]小於v,將A[lt]和A[i]交換,++lt,++i
- A[i]大於v,將A[gt]和A[i]交換,gt–;
- A[i]等於v,++i;
代碼如下:
void quickSortCore3(int *A,int lo,int hi)
{
if(hi<=lo) return;
int lt=lo,i=lo+1,gt=hi;
int v=A[lo];
while(i<=gt){
if(A[i]>v){
swap(A,i,gt--);
}else if(A[i]<v){
swap(A,lt++,i++);
}else{
++i;
}
}
quickSortCore3(A,lo,lt-1);
quickSortCore3(A,gt+1,hi);
}