下面為一段普通的快速排序代碼
(1)隨機性
快速排序算法有較壞的情況,例如9、8、7、6、5、4、3、2、1這樣一個序列,此時用快速排序則效率很低。
因此,可以編寫shuffle函數打亂數組。
shuffle函數
(2)采用三向切分
在實際應用中,數組中可能存在著大量的重復元素,對重復元素進行排序沒有任何意義。Dijkstra的三向切分解法思想如下圖所示。他使用了lt和gt指針,令[lo,...,lt-1]的元素都下于v,[gt+1,...,hi]的元素都大于v。
1、a[i]<v , swap(a[lt],a[i]) , lt++ , i++
2、a[i]>v , swap(a[gt],a[i]) , gt--
3、a[i]==v , i++
三項切分思想
下圖為三向切分處理數組的過程:
(3)小規模數組采用直接插入排序
在快速排序遞歸的過程中,處理小規模數組時,需要多次的遞歸,執行更小的數組,導致此時快速排序沒有直接插入排序的效率高。因此將sort()中語句
if (hi <= lo) return;
替換成下面這條語句:
if ( hi <= lo + M) { Insertion.sort(a, lo, hi); return;}
其中M的最佳取值需要根據具體環境而定。
(4)設置哨兵
在插入排序時,在數組0號元素存放哨兵,可以去除判斷指針是否小于數組的最低位的判斷。
(5)個人想法
在之前的學習中,學過歸并排序,它的復雜度為O(nlogn),但是快速排序優化不采用歸并排序而采用三向切分,個人有以下兩點想法:
1、歸并排序對重復數據的處理性能不穩定。通過測試,隨機數組長度為100000000,數字范圍為[0,200),自頂向下的歸并排序消耗時間為14427ms,三向切分消耗時間為13000ms。
2、小數組采用直接插入排序時,M的取值在5~15之間性能較好,此時若對直接插入排序采用歸并,意義不大,可能還會因為遞歸導致效率降低。