快速排序 与 Top-k (第k小数)

快速排序

一、快速排序

  1. 基本思路:
    快速排序使用分治的思想,通过Partition的动作将原数据集以一个枢轴pivot分割为小于pivot和大于pivot的两个部分,递归地在这两个部分继续分割,直到当前数据集大小为1,这时也完成了排序。

  2. 算法

PARTITION (array, left, right):
pivot = array[left]
temp=left
while (left<right):
		while (left<right && array[right]>pivot):
			right=right-1
		while (left<right && array[left]<=pivot):
			left=left+1
		swap (left, right)
swap (left, temp)

解释:分别从右、左两边遍历当前数据集,交换数据实现以pivot为中心的分割

该算法在实现过程中有一些细节要注意:
(1)pivot应该存储实际数据而不是下标,因为下标left在后面会修改
(2)从小到大排序应该从右开始遍历:如果从左开始,那么循环中最后一次交换完执行left=left+1,然后left==right,也就是说这时的array[left]>pivot,执行最后一个交换,一个大于pivot的数会被交换到pivot前面
(3)array[left]<=pivot:至少要有这个等号

QUICKSORT (array, left, right):
if left<right
pivot = PARTITION (array, left, right)
QUICKSORT (array, left, pivot-1)
QUICKSORT (array, pivot+1, right)

  1. 复杂度:O(nlogn)

  2. 运行截图
    在这里插入图片描述

  3. 源代码
    解释:程序用了三种Partition的方法,前两个只有微小的不同,第三个来自于算法导论,不同在于它是单向遍历,而非前两个分别从首尾遍历。

int Partition1(vector<int> &list, int left, int right)
{	
	int pivot = list[left];
	int templeft = left;
	while(left<right)
	{
		while(left<right && list[right]>=pivot)
		{
			right--;
		}		
		swap(list,left,right);
		while(left<right && list[left]<=pivot)
		{
			left++;
		}
		swap(list,right,left);
	}
}
int Partition2(vector<int> &list, int left, int right)
{
	int pivot = list[left];
	int templeft = left;
	while(left<right)
	{
		while(left<right && list[right]>pivot)
		{
			right--;
		}
		while(left<right && list[left]<=pivot)
		{
			left++;
		}
		swap(list,left,right);
	}
	swap(list,left,templeft);
	return left;
}

int Partition3(vector<int> &list, int left, int right)
{
	int pivot = list[right];
	int i=left-1;
	for(int j=left;j<right;j++)
	{
		if(list[j]<=pivot)
		{
			i++;
			swap(list,i,j);
		}
	}
	swap(list,i+1,right);
	return i+1;
}
void QuickSort(vector<int> &list, int left, int right)
{
	if(left<right)
	{
		int partition = Partition(list,left,right);
		QuickSort(list,left,partition-1);
		QuickSort(list,partition+1,right);
	} 		
}
void swap(vector<int> &list, int a, int b)
{
	int temp = list[a];
	list[a] = list[b];
	list[b] = temp;
}

二、基于快速排序的第k小数

  1. 基本思路:
    递归调用Partition函数,直到枢轴的下标为k。

  2. 运行截图
    在这里插入图片描述

  3. 源代码
    解释:实际程序与快速排序非常相似,只是递归条件变化。

int Partition(int list[], int left, int right)
{
	int pivot = left;
	while(left<right)
	{
		while(list[right]>list[pivot] && left<right) right--;
		while(list[left]<=list[pivot] && left<right)	left++;
		swap(list,left,right);
	}
	swap(list,left,pivot);
	return left;
}

int QuickSortGetTopK(int list[], int left, int right, int k)
{
	int partition = -1;
	if(left<right && k)
	{
		partition = Partition(list,left,right);
		if(partition == k)
			return k;
		else if(partition < k)
			return QuickSortGetTopK(list,partition+1,right,k);
		else
			return QuickSortGetTopK(list,left,partition-1,k);
	}
}
void swap(int list[], int a, int b)
{
	int temp = list[a];
	list[a] = list[b];
	list[b] = temp;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值