算法--Java代码实现快速排序以及三路划分

本文只提供思想,仅供参考.

底部有文章的参考,在巨人的肩膀上加上了自己的一点解释和理解。有兴趣可以直接去看参考文章。

一般的快速排序

思路:
1.一般选取最右边的值为pivot
2.从左端开始扫描,直到找到大于pivot,右端开始扫描,直到小于pivot,再交换。
3.继续执行2,直到左指针不小于右指针,最后在减缓左元素和pivot
4.在左右两边重复上面过程,直至元素个数为0或者1

这里写图片描述

一般的快速排序,无法解决和pivot大量重复的情况,这里就需要用到了三路划分。


三路划分快速排序:

平均时间复杂度O(NlgN)
基本思想是将区间划分为三个部分,左部分小于划分元素,中间部分等于划分元素,右部分大于划分元素,然后再在左右两部分进行子处理,

1.选择左端元素、右端元素和中间元素的中值作为pivot,也就是三者取中划分,避免最坏。
2 从左端开始扫描,直到找到大于等于pivot的元素,同时右端开始扫描,直到找到小于等于pivot的元素,交换停止扫描的两个元素。如果左指针等于pivot,与左边元素交换。并递增左边位置(初始化为文件最左位置)。如果右指针元素等于划分元素,那么与右端元素交换,并递减右端位置(初始化为文件最右位置)。
3.继续步骤2. 直到左指针不小于右指针
4.交换最左端区间和左指针左侧区间(不包括左指针元素),这一过程会递减左端位置;交换最右端区间和左指针右侧区间(包括左指针元素),这一过程会递增右端位置。
5.在最左端和最右端区间重复以上过程,直至元素个数为0或1。
划分过程中,与划分元素相等的元素分布在最左端和最右端,

这里写图片描述

在划分完成后处理子区间前,需要对调区间。

Java代码实现:

void quick_sort(int[] a,int _first,int _last){
 	if(_first<_last-1){
 		return;
 	}
 
 	int i=_first,j=_last-1,p=i,q=j,k;
 	//1.三路划分 pivot取第一个、最后一个、中间数的中值;
 	int pivot=_median(a[0],a[a.length-1],a[(a.length-1)/2]);
 
 	while(true){
 		//2.左边开始直到找到一个大于等于pivot的数值,右边开始查找,直到找到小于等于pivot的数值,交换
 		while(a[i]<pivot){
 			i++;
 		}
 		while(a[j]>pivot){
 			j--;
		}
 
 		if(!(i<j)){
 		   break;
 		}
 
		swap(a[i],a[j]); 
 
 		//3.交换后,如果a[i]==pivot,那么a[i]和最左边元素a[p]位置交换,交换后p+1,
		if(a[i]==pivot){
 			swap(a[p++],a[i]);
 		}
 		if(a[j]==pivot){
 			swap(a[q--],a[j]);
 		}
 
 		//4.移动一位,进行继续比较
 		++i;
 		--j;
 	}
 
 	//5.第一轮比较结束,i==j, 子模块划分前,先进行区域交换。
 	j=i-1;
 	for(k=_first;k<p;--j,++k){
		swap(a[k],a[j]);
 	}
 	for(k=_last-1;k>q;++i,--k){
 		swap(a[k],a[i]);
 	}
 
 	quick_sort(_first,j+1);
 	quick_sort(i,_last);
 }

参考:[三路划分快速排序--针对重复关键字的改进](http://www.cppblog.com/qinqing1984/archive/2012/05/19/175379.html)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值