(一)對於近乎有序的陣列,演算法的計算複雜度由o(nlogn)退化到o(n2)
使用上篇部落格裡的快速排序演算法做測試,測試程式為
int
main()
測試結果
可以看出對於乙個近乎有序的5萬個元素的陣列,快速排序用了 0.545s,比歸併排序慢了很多倍快速排序演算法中,我們一般將陣列最左邊的元素作為參考元素,這樣的話,當陣列近乎有序的時候,對整個陣列進行partition後,左邊小於參考元素的個數會很少,近乎沒有,右邊大於參考元素的個數將會接近整個陣列元素個數,在遞迴過程中,每層的partition都將近乎只有一部分,如下圖所示
解決方案很簡單,就是隨機選取參考元素,具體實現如下
#include
#ifndef _sortinghelp_h_
#define _sortinghelp_h_
#include
"sortinghelp.h"
#endif
// _sortinghelp_h_
#include
"mergesorting.h"
using namespace std;
//對arr[l...r]進行partition操作
//返回p,使得arr[l...p-1] < arr[p]; arr[p+1...r] > arr[p]
template
int__partition
(t arr,
int l,
int r)
}swap
(arr[l]
, arr[j]);
return j;
}//對arr[l...r]部分進行排序
template
void
__quicksorting
(t arr,
int l,
int r)
template
void
quicksorting
(t arr,
int n)
intmain()
輸出為
隨機設定參考元素後,對於近乎有序的陣列,快速排序演算法的速度恢復正常了
(二)如果陣列中存在大量重複的元素,那麼演算法的計算複雜度也會退化到o(n2)
首先測試一下當陣列中有大量重複元素時,演算法的執行時間
int
main()
輸出為
可以看出使用上面隨機設定參考元素的方法,計算時間還是很長
由下圖可以看出,當存在大量重複元素時,還是會出現partition後左右不平衡的現象
在上篇部落格的演算法中遍歷陣列元素時是從左到右依次遍歷,遇到大於參考元素的值不操作,遇到小於參考元素的值將其與第乙個大於參考元素的值相交換,下面換一種策略
如上圖所示,同時從陣列兩邊進行遍歷,首先還是隨機設定乙個參考元素 v
vv,然後與最左邊元素進行位置交換
(1)索引為 i
ii 的元素從左向右遍歷,如果遍歷的元素小於 v
vv ,那麼就繼續遍歷,如果大於等於 v
vv ,那麼就停止
(2)此時索引為 j
jj 的元素從右向左遍歷,如果遍歷的元素大於 v
vv ,那麼就繼續遍歷,如果小於等於 v
vv ,那麼就停止
(3)將索引為 i
ii 的元素與索引為 j
jj 的元素交換位置,此時左右兩邊又都符合條件了, i
ii 和 j
jj 就繼續開始遍歷
這樣的話,即使有大量重複的元素,也會不斷交換分散到左右兩邊(i
ii 和 j
jj 交換時有三種可能,一、i
ii 和 j
jj 都等於 v
vv ;二、i
ii 等於 v
vv, j
jj 不等於 v
vv ;三、i
ii 不等於 v
vv, j
jj 等於 v
vv),不會出現左右不平衡的現象
上述改進原理也可檢視部落格
實現程式如下
#include
#ifndef _sortinghelp_h_
#define _sortinghelp_h_
#include
"sortinghelp.h"
#endif
// _sortinghelp_h_
#include
"mergesorting.h"
using namespace std;
//對arr[l...r]進行partition操作
//返回p,使得arr[l...p-1] < arr[p]; arr[p+1...r] > arr[p]
template
int__partition
(t arr,
int l,
int r)
}swap
(arr[l]
, arr[j]);
return j;
}//對arr[l...r]部分進行排序
template
void
__quicksorting
(t arr,
int l,
int r)
template
void
quicksorting
(t arr,
int n)
//下面是改進後的快速排序演算法
//對arr[l...r]進行partition操作
//返回p,使得arr[l...p-1] < arr[p]; arr[p+1...r] > arr[p]
template
int__partition2
(t arr,
int l,
int r)
swap
(arr[l]
, arr[j]);
return j;
}//對arr[l...r]部分進行排序
template
void
__quicksorting2
(t arr,
int l,
int r)
template
void
quicksorting2
(t arr,
int n)
intmain()
輸出為
可以看出使用左右兩個方向都遍歷,已經可以對有大量重複元素的陣列進行快速排序
資料結構與演算法之快速排序
1.快速排序的 實現如下 include using namespace std template void sort t data,size t head,size t tail templatesize t partition t data,size t head,size t tail tem...
資料結構與演算法之快速排序
快速排序是c.r.a.hoare於1962年提出的一種劃分交換排序。它採用了一種分治的策略,通常稱其為分治法 divide and conquermethod 該方法的基本思想是 1 先從數列中取出乙個數作為基準數。2 分割槽過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。3 ...
資料結構與演算法 排序演算法之六 快速排序
一 快速排序 排序演算法中的奧斯卡,諾貝爾獎,當屬快速排序!快速排序是20世紀十大演算法之一!1 基本思想 前面提到氣泡排序,它是一種交換排序,堪稱最慢的排序演算法。可是,物極必反,快速排序是氣泡排序的公升級加強版,同屬於交換排序類。以 空間 換時間,快速排序不是相鄰元素的交換,而是加大了比較和交換...