【模板】快速排序及寻找区间第k大

快速排序基本思想:分治法

快速排序基本流程

选择序列的一个元素为枢轴(程序中选择第1个元素),然后设计两个指针(start和end),将所有剩余元素依次和枢轴进行比较,根据比较结果,将比枢轴大的元素都排在它的后面,比枢轴小的元素都排在它的前面,这样一趟排序以后(start==end),序列就以枢轴为界划分成了两个部分。然后,递归地对这两个部分再进行上述操作,直到每一部分都只有一个数据元素为止(递归结束条件)。

特性

(1)平均时间复杂度最快的排序算法(o(nlogn)),最好时间复杂度也是o(nlogn)

(2)当初始序列已经有序时,快速排序蜕化成了冒泡排序,时间复杂度为o(n^2)

稳定性

不稳定(如上图,交换元素时会改变相等元素的相对位置)。

有关的改进

快速排序算法的性能取决于划分的对称性。通过修改算法quickSort,可以设计出采用随机选择策略的快速排序算法。在快速排序算法的每一步中,当数组还没有被划分时,可以在a[p:r]中随机选出一个元素作为划分基准,这样可以使划分基准的选择是随机的,从而可以期望划分是较对称的。

代码1:

#include<stdio.h>
void Qsort(int arr[],int low,int high)
{
	if(low>=high) return;//结束条件 
	int start=low;
	int end=high;
	int key=arr[start];//用第1个元素作为关键值 
	while(start<end)
	{
		while(start<end && arr[end]>=key)
		{
			end--;
		}
		arr[start]=arr[end];//将比关键值小的元素放到序列低端 
		while(start<end && arr[start]<=key)
		{
			start++;
		}
		arr[end]=arr[start];//将比关键值大的元素放到序列高端 
	}
	arr[start]=key;//还原 
	Qsort(arr,low,start-1);
	Qsort(arr,start+1,high);//递归 
}
int main(void)
{
	int length;
	while(scanf("%d",&length)!=EOF)
	{
		int m[10000];
		for(int i=0;i<length;i++){
			scanf("%d",&m[i]);
		}
		Qsort(m,0,length-1);
		for(int i=0;i<length;i++){
			printf("%d ",m[i]);
		}
		printf("\n");
	}
	return 0;
}

代码2:

//快速排序
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
void swap(int a[],int elem1,int elem2)
{
	int tmp = a[elem1];
	a[elem1]=a[elem2];
	a[elem2]=tmp;
}
void quickSort(int a[],int low,int high){
	if(low>=high) return;
	int start = low;
	int end = high;//避免待会儿递归时污染数值 
	int key = a[start];//以第一个元素为枢轴 
	while(start<end)
	{
		while(start<end && a[end]>=key)
		{
			end--;
		} 
		swap(a,start,end);//交换 
		while(start<end && a[start]<=key)
		{
			start++;
		}
		swap(a,start,end);//交换 
	}
	quickSort(a,low,start-1);
	quickSort(a,start+1,high);//递归 
} 
void quickSortHelp(int a[],int n){
	quickSort(a,0,n-1);
}
 int main(void)
{
	int n = 10;
	int arr[10] = {0};
	for(int i=0;i<n;i++)
	{
		arr[i]=rand()%100;
	}
	for(int i=0;i<n;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl; 
	quickSortHelp(arr,n);
	for(int i=0;i<n;i++)
	{
		cout<<arr[i]<<" ";
	}
	return 0;
}

 

寻找区间第k大

基于以上,可以在o(n)(平均)时间复杂度内寻找第K大的元素,当然最坏的时间复杂度依然是o(n^2)

思路是与快速排序一致的,只是在查找时,根据查找的元素(下标K)与枢轴位置的关系,只查找其中的一部分。

#include<iostream>
#include<stdlib.h>
using namespace std;
int arr[1000001];
//区间习惯:左开右闭 
void partition(int arr[],int p,int q,int k)//寻找第k大
{
	if(p>=q) return; 
	int random = (rand() % (q-p))+ p;//随机选择枢轴
	int key = arr[p];
	int start = p;
	int end = q-1;
	while(start<end)
	{
		while(start<end&&arr[end]>=key)//等号
		{
			end--;
		}
		arr[start]=arr[end];
		while(start<end&&arr[start]<=key)
		{
			start++;
		}
		arr[end] = arr[start];
	}
	arr[start]=key;//还原
	//当start==end
	if(k==start) return;//此时start是枢轴元素在最终有序序列的下标,找到直接返回
	if(k>start) //比寻找的比枢轴大,只需要在比枢轴大的区间继续查找
	{
		partition(arr,start+1,q,k);
	}
	if(k<start)//反之,只需要在比枢轴小的区间继续查找
	{
		partition(arr,p,start,k);
	}
	
 } 
 int main(void)
 {
 	int n,k;
 	cin>>n>>k;
 	for(int i=0;i<n;i++)
 	{
 		scanf("%d",&arr[i]); 
	 }
	 partition(arr,0,n,n-k);
	 cout<<arr[n-k]<<endl;
	 return 0;
 }

图片来源:https://blog.csdn.net/hellozhxy/article/details/79911867

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值