一、快速排序的描述
与归并排序一样,快速排序也采用了分治策略。以下是对数组A[p…r]进行快排的三步分治过程:
分解:
将数组A[p...r]分解为两个非空的子数组A[p...q-1]和A[p+1...r], 使得A[q] 大于等于A[p...q-1]中的任意一个元素,A[q]小于
等于A[q+1...r]中的任意一个元素。
解决:
通过递归调用快速排序,对子数组A[p...q-1]和A[p+1...r]进行排序。
合并:
用整个排序过程是基于原址排序的,因此不需要进行合并。
二、代码实现
递归实现(Javascript)
function QuickSort(A, p, r){
if(p < r){
q = partition(A, p, r);
QuickSort(A, p, q-1);
QuickSort(A, q+1, r);
}
}
function partition(A, p, r){
let x = A[r];
let i = p - 1;
for(let j = p; j < r; j++){
if(A[j] <= x){
i++;
//swap(A[i], A[j])
[A[i], A[j]] = [A[j], A[i]];
}
}
//swap(A[r], A[i]);
[A[i], A[r]] = [A[i], A[r]];
return i + 1;
}
非递归实现
function getRandom(a, b) {
let r = Math.floor(Math.random() * (b - a)) + a;
return r;
}
Array.prototype.quickSort = function(fn = (a, b)=>(a - b)){
const A = this;
const len = this.length;
let p = 0,
r = len - 1;
// 使用一个数组来模拟递归栈
const stack = [[p, r]];
while(stack.length > 0){
[p, r] = stack.pop();
let i = p-1,
j = p,
x = A[r];
// 随机选取比较的主元---随机化快排
let t = getRandom(p, r+1);
[A[t], A[r]] = [A[r], A[t]];
x = A[r];
// 进行一趟快速排序
// [Ap,...,Ar] --> [Ap,...,Ai,...Ar], 任意i∈[p, r], Ap < Ai < Ar
while(j < r){
if(fn(x, A[j]) >= 0){
i++;
// swap(A[i], A[j])
[A[i], A[j]] = [A[j], A[i]];
}
j++;
}
i++;
// 确定当前主元的位置
// 这也是快排的性质之一,即每一趟快排确定一个元素的位置
[A[i], A[r]] = [A[r], A[i]];
// 保证子数组元素个数至少2个
if(i-1 > p){
stack.push([p, i-1]);
}
if(i+1 < r){
stack.push([i+1, r]);
}
}
}