快速排序及寻找最小的k个数

快速排序

快速排序采用的是分治策略在一个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章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值