快速排序
快速排序采用的是分治策略: 在一个list中选择一个基准值(pivot value),将list中比基准值小的元素排在基准值的左侧,比基准值大的元素排在基准值的右侧,形成两个sub-list;然后对sub-list进行同样的操作,直至整个list排序完成。
Partition伪代码
// pseudocode of Partition
function Partition(a, left, right)
pivotIndex := (left + right) / 2;
pivotValue := a[pivotValue];
storeIndex := left;
for i from left to right-1
if a[i] < pivotValue
swap(a[i], a[storeIndex]);
storeIndex := storeIndex;
swap(a[right], a[storeIndex]);
return storeIndex;
pivotIndex有多种选择方式,这里采用list的中间index作为pivotIndex .
storeIndex是所有小于pivotValue的元素的后面一个index,每次交换就是a[storeIndex]和a[i].
Quicksort伪代码
// psedocode of Quicksort
function Quicksort(a, left, right)
if right > left
pivotIndex := Partition(a, left, right);
Quicksort(a, left, pivotIndex-1);
Quicksort(a, pivotIndex+1, right);
寻找最小的k个数
与快速排序类似,仍然采用分治策略,不同的是,不必对每个sub-list都进行partition, 只对需要的sub-list进行partition。执行结束后,最小的k个数排在数组的前k个位置,但是,这k个数可能并没有经过排序。
算法导论第9章有该算法的实现:
代码:
template<typename Type>
void my_swap(Type& a, Type& b)
{
Type tmp = a;
a = b;
b = tmp;
}
template<typename Type>
int partition(Type* a, int left, int right)
{
int pivotIndex = (left + right)/2;
int storeIndex = left;
Type pivotValue = a[pivotIndex];
my_swap(a[pivotIndex], a[right]);
for(int i = left; i < right; i++){
if(a[i] < pivotValue){
swap(a[i], a[storeIndex]);
storeIndex ++;
}
}
my_swap(a[storeIndex], a[right]);
return storeIndex;
}
template<typename Type>
void my_quick_sort(Type* a, int left, int right)
{
if(right > left){
int pivotIndex = partition(a, left, right);
my_quick_sort(a, left, pivotIndex-1);
my_quick_sort(a, pivotIndex+1, right);
}
}
template<typename Type>
void my_select(Type* a, int p, int r, int i)
{
if(p == r)
return;
int q = partition<Type>(a, p, r);
int k = q - p + 1;
if(i == k)
return;
else if(i < k)
my_select(a, p, q-1, i);
else
my_select(a, q+1, r, i-k);
}
参考:
[1] http://zh.wikipedia.org/zh-cn/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F
[2] 算法导论,第三版,第9章