前端css基礎知識點
阿新 • • 發佈:2020-11-26
1. 快排基礎
快速排序的要點是先找到第一個元素的最終的位置,如何尋找就如下圖所示,找到比4小的數,在找到比4大的數。核心就是如何把4這個數挪到正確的位置上。
下圖中,l記錄的是當前的元素,j記錄<v和>v的分界點(對於j這個點上值多少不用去管),i是當前訪問的元素。如果當e>v就直接放在後面。
如果當e<v這種情況,就需要把e放在前面橙色的部分。方法很簡單,e和j位置上的元素互換(直接將e放到j的位置),而j++就好。
最後都結束了之後再把v這個元素放在j上。
初版程式碼如下:
// 對arr[l,,r]部分進行partition操作 //返回是一個索引 p 使得arr[l...p-1] < arr[p] arr[p+1....r] > arr[p] template <typename T> int __partition(T arr[],int l,int r){ // 先把數儲存下來 T v = arr[l]; // arr[l+1...j] < v arr[j+1....r) > arr[j] int j = l; for (int i = l+1; i <= r; ++i) { if (arr[i] < v){ swap(arr[j+1],arr[i]); j++; } } swap(arr[l],arr[j]); return j; } // 內部快排介面 對arr[l...r]進行快速排序 template <typename T> void __quickSort(T arr[],int l,int r){ // 出現異常 if (l>=r){ return; } int p = __partition(arr,l,r); __quickSort(arr,l,p-1); __quickSort(arr,p+1,r); } // 快速排序 template <typename T> void quickSort(T arr[],int n){ __quickSort(arr,0,n-1); }
和直接插入排序相比
結果如下:
quick order:0.01s
insertSort:2.941s
Process finished with exit code 0
2. 快排進階
當遇到近乎有序的陣列時,快速排序會慢很多倍。
結果如下:
quick order:0.028s
insertSort:0s
原因如下圖,他和歸併排序不一樣的地方是歸併排序始終是對陣列一分為二。但是在快速排序中左右子樹是不一定對稱的。當遇到最差情況就是有序的陣列左側(或者右側)子樹是沒有的,那麼他會退化成o(n^2)。
解決方法也是很簡單,即設定隨機種子。隨機選擇一個元素把這個元素與第一個元素進行互換,這樣可以降低退化成o(n^2)的可能性。
// 對arr[l,,r]部分進行partition操作 //返回是一個索引 p 使得arr[l...p-1] < arr[p] arr[p+1....r] > arr[p] template <typename T> int __partition(T arr[],int l,int r){ // 先把數儲存下來 swap(arr[l],arr[rand()%(r-l+1)+l]); T v = arr[l]; // arr[l+1...j] < v arr[j+1....r) > arr[j] int j = l; for (int i = l+1; i <= r; ++i) { if (arr[i] < v){ swap(arr[j+1],arr[i]); j++; } } swap(arr[l],arr[j]); return j; } // 內部快排介面 對arr[l...r]進行快速排序 template <typename T> void __quickSort(T arr[],int l,int r){ // 出現異常 if (r<l){ // insertSort(arr,r-l+1); return; } int p = __partition(arr,l,r); __quickSort(arr,l,p-1); __quickSort(arr,p+1,r); } // 快速排序 template <typename T> void quickSort(T arr[],int n){ srand(time(NULL)); __quickSort(arr,0,n-1); }
3. 快速排序高階
3.1 雙指標
通過使用雙指標的方式進行排序入,下圖所示:
程式碼如下:
template <typename T>
int __partition2(T arr[], int l, int r){
swap( arr[l] , arr[rand()%(r-l+1)+l] );
T v = arr[l];
// arr[l+1...i) <= v; arr(j...r] >= v
int i = l+1, j = r;
while( true ){
while( i <= r && arr[i] < v )
i ++;
while( j >= l+1 && arr[j] > v )
j --;
if( i > j )
break;
swap( arr[i] , arr[j] );
i ++;
j --;
}
swap( arr[l] , arr[j]);
return j;
}
template <typename T>
void __quickSort2(T arr[],int l,int r){
// 出現異常
if (r<l){
insertSort(arr,r,l);
return;
}
int p = __partition2(arr,l,r);
__quickSort2(arr,l,p-1);
__quickSort2(arr,p+1,r);
}
// 快速排序
template <typename T>
void quickSort2(T arr[],int n){
srand(time(NULL));
__quickSort2(arr,0,n-1);
}
template <typename T>
void insertSort(T arr,int l,int r){
for (int i = l+1; i < r; ++i) {
T e = arr[i];
int j;
for (j = i; j > 0 && arr[j-1]>e; j--) {
arr[j] = arr[j-1];
}
arr[j] = e;
}
}
3.2 三路快速排序
如果 e<v,那麼就和 lt+1位置上的元素進行互換。如果e>v,就和gt-1上的元素進行互換,同樣的兩邊的索引,左邊的++,右邊的--。最後把第一個v的元素和lt上的元素進行互換。
程式碼如下:
template <typename T>
void __quickSort3(T arr[], int l, int r){
if (r<l){
// insertSort(arr,l,r);
return;
}
swap(arr[l],arr[rand()%(r-l+1)+l]);
T v = arr[l];
int lt = l;
int gt = r+1;
int i = l+1;
while (i<gt){
if (arr[i]>v){
swap(arr[i],arr[--gt]);
}else if (arr[i]<v){
swap(arr[i++],arr[++lt]);
}else{
i++;
}
}
swap(arr[l],arr[lt]);
__quickSort3(arr,l,lt-1);
__quickSort3(arr,gt,r);
}
template <typename T>
void quickSort3(T arr[],int n){
srand(time(NULL));
__quickSort3(arr,0,n-1);
}
參考文獻
[1]維基百科.快速排序[EB/OL].https://zh.wikipedia.org/wiki/快速排序,2020-10-10.