快排的基础概念和优化

快排的基础概念和优化

快排的基础概念:
  1. 选用一个基本值key,将比key小的放入左边,比key大的放入右边,不断重复,最终得到有序数列。
  2. 快排是一个比较高效的排序方法,时间复杂度是 n*log2n 。
  3. 快排是有一定的不稳定性,当数列倒序、相同元素较多时,快排比较其它排序方法没有更优越性
快排的实现过程(如图所示):

在这里插入图片描述

基本快排的实现:

代码如下:

void quickSort(int *a,int left,int right){
	if(left >= right) return;
	int pos=a[left];
	int low=left,row=right;
	while(low<row){
		while(a[row]>=pos && low<row) 
			row--;
		a[low]=a[row];
		while(a[low]<=pos && low<row) 
			low++;
		a[row]=a[low];
	}
	a[low]=pos;
	quickSort(a,left,low-1);
	quickSort(a,low+1,right);
}
快排的优化:
  1. 基础的快排是默认区间的左边第一个元素为key值,但数列倒序时,并没有起到优化排序的作用,所以要随机取key值;
  2. 当区间长度小于10时,可以用插排,插排和快排此时时间复杂度差不多,但是栈是有限的,使用插排可以减少栈深;
  3. 提高相等元素的聚集度也是可以减少算法的时间复杂度的。
三数取中法(代码如下):
//三数取中法 (选取轴值)
void selectQSort(int *a,int left,int right){
	int mid=left + ((right-left)>>1);	//选取中间值 
	
	if(a[mid]<a[left]) swap(a[mid],a[left]);
	
	if(a[left]>a[right]) swap(a[left],a[right]);
	
	if(a[right]<a[mid]) swap(a[right],a[mid]);
	
	Qswap(a[mid],a[left]);	//返回第二大的值 
}
插排(代码如下):
//插排 (折半插入法)
void InsertSort(int *a,int left,int right){
	int i,j,temp,low,row,mid;
	
	for(i=left+1;i<=right;i++){
		temp=a[i];
		low=left,row=i-1;
		
		while(low<=row){
			mid=low+((row-low)>>1);
			if(a[mid] <= temp){
				low=mid+1;
			}else{
				row=mid-1;
			}
		}
		
		for(j=i-1;j > row;j--) a[j+1]=a[j];
		a[row+1]=temp;
	}
}
相等元素聚集(代码如下):
void quickSort(int *a,int left,int right){
	if(left>=right) return;
	
	//当 right-left < 10 时,快排和插排相当(减少调用栈数) 
	if(right-left < 10) {
		InsertSort(a,left,right);
		return;
	}
	
	if(left<right){
		
		selectQSort(a,left,right);
		int tpr=right,tpl=left;
		int pos=a[left];
		int low=left,row=right;
		
		while(low<row){
			while(a[row]>=pos && low<row) {
				if(a[row]==pos){	//将相等元素聚集数轴的右方 
					swap(a[row],a[tpr]);
					tpr--;
				}
				row--;	
			}
			a[low]=a[row];
			
			while(a[low]<=pos && low<row) {
				//由于是以a[left]为轴值,所以要有 low!=left ,确保元素的唯一性 
				if(a[low]==pos && low!=left){	//将相等元素聚集在数轴的左方 
					swap(a[low],a[tpl]);
					tpl++;
				}	
				low++;
			}
			a[row]=a[low];
		}
		a[low]=pos;
		
		//分别将右方、左方的相等元素聚集在 pos 旁边 
		if(tpr==tpl) return;//表示该区间的所有元素相等 
		if(tpr<right){
			while(tpr<=right && row<tpr){
				tpr++;
				row++;
				if(tpr<=right) swap(a[row],a[tpr]);
			}
			row--;
		}
		
		if(tpl>left){
			while(tpl>=left && low>tpl){
				tpl--;
				low--;
				if(tpl>=left) swap(a[low],a[tpl]);	
			}
			low++;
		}
		
		quickSort(a,left,low-1);
		quickSort(a,row+1,right);
	}
}
这是完整的代码:
#include<iostream>
using namespace std;
int n;
//交换函数 
void Qswap(int &a,int &b){
	int tp=a;
	a=b;b=tp;
}

//三数取中法 (选取轴值)
void selectQSort(int *a,int left,int right){
	int mid=left + ((right-left)>>1);	//选取中间值 
	if(a[mid]<a[left]) Qswap(a[mid],a[left]);
	if(a[left]>a[right]) Qswap(a[left],a[right]);
	if(a[right]<a[mid]) Qswap(a[right],a[mid]);
	Qswap(a[mid],a[left]);	//返回第二大的值 
}

//插排 (折半插入法)
void InsertSort(int *a,int left,int right){
	int i,j,temp,low,row,mid;
	
	for(i=left+1;i<=right;i++){
		temp=a[i];
		low=left,row=i-1;
		
		while(low<=row){
			mid=low+((row-low)>>1);
			if(a[mid] <= temp){
				low=mid+1;
			}else{
				row=mid-1;
			}
		}
		
		for(j=i-1;j > row;j--) a[j+1]=a[j];
		a[row+1]=temp;
	}
}

//快排
void quickSort(int *a,int left,int right){
	if(left>=right) return;
	
	//当 right-left < 10 时,快排和插排相当(减少调用栈数) 
	if(right-left < 10) {
		InsertSort(a,left,right);
		return;
	}
	
	if(left<right){
		
		selectQSort(a,left,right);
		int tpr=right,tpl=left;
		int pos=a[left];
		int low=left,row=right;
		
		while(low<row){
			while(a[row]>=pos && low<row) {
				if(a[row]==pos){	//将相等元素聚集数轴的右方 
					Qswap(a[row],a[tpr]);
					tpr--;
				}
				row--;	
			}
			a[low]=a[row];
			
			while(a[low]<=pos && low<row) {
				//由于是以a[left]为轴值,所以要有 low!=left ,确保元素的唯一性 
				if(a[low]==pos && low!=left){	//将相等元素聚集在数轴的左方 
					Qswap(a[low],a[tpl]);
					tpl++;
				}	
				low++;
			}
			a[row]=a[low];
		}
		a[low]=pos;
		
		//分别将右方、左方的相等元素聚集在 pos 旁边 
		if(tpr==tpl) return;//表示该区间的所有元素相等 
		if(tpr<right){
			while(tpr<=right && row<tpr){
				tpr++;
				row++;
				if(tpr<=right) Qswap(a[row],a[tpr]);
			}
			row--;
		}
		
		if(tpl>left){
			while(tpl>=left && low>tpl){
				tpl--;
				low--;
				if(tpl>=left) Qswap(a[low],a[tpl]);	
			}
			low++;
		}
		
		quickSort(a,left,low-1);
		quickSort(a,row+1,right);
	}
}
/*
样例:
 
	8
	2 4 3 6 1 7 5 8
	
	10
	4 2 4 3 6 5 6 6 8 9
*/
int main(){
	int i;
	cin>>n;
	int a[n];
	for(i=0;i<n;i++) cin>>a[i];
	quickSort(a,0,n-1);
	for(i=0;i<n-1;i++) cout<<a[i]<<" ";
	cout<<a[n-1]<<endl;
}

最后,总结一下,快排的优化是:三数取中+插排+聚集相等元素,其实还有尾插等,另外本贴如果有什么错误之处,望贴友指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值