快速排序的实现方法

快速排序法一般来说可以分为三种,分别是:

①基础快速排序法

②双路快速排序法

③三路快速排序法

下面分别对以上三种快排进行梳理。

基础快速排序法
排序思路:首先传入待排序数组,使用变量l表示数组下标起点,使用变量r表示数组下标终点,然后取数组第一个元素e做中介,使用循环逐步将数组元素分为比e小和不比e小的两部分;使用变量j记录左侧比e小的元素个数下标(初始值为l),循环内部使用变量i从l+1开始遍历到r,如果array[i]小于e,那么array[j+1]与array[i]进行互换然后j++,否则直接i++;循环结束后,变量j位于比e小的那部分的最尾部下标处,将数组待排序最左侧元素与array[j]交换,最后得到lj-1为比e小的部分,j+1r为不比e小的部分。接着对lj-1和j+1r这两部分继续上述的排序操作,直到l>=r,排序结束。

代码实现:

//基础版快速排序法
public static void quickSortBase(int[] array){
	__quickSortBase(array,0,array.length-1);
}


public static void __quickSortBase(int[] array,int l,int r){
	int temp;
	if(l>=r){
		return ;
	}

	int e = array[l];
	int j = l;//保存<e部分尾部的下标
	for(int i=l+1;i<=r;i++){//将数组分为<e和>=e两部分
		if(array[i]<e){
			temp = array[j+1];
			array[j+1] = array[i];
			array[i] = temp;
			j++;
		}
	}
	//排序完成后,将array[j]与array[l]进行交换,此时l~j-1为<e部分,j+1~r为>=e部分
	temp = array[j];
	array[j] = array[l];
	array[l] = temp;
	//继续进行排序
	__quickSortBase(array,l,j-1);
	__quickSortBase(array,j+1,r);		
}

生成20个0~66的数,进行测试:

此版本可以进行的优化:

①每次排序前,先将数组最左边的数和数组中的元素随机互换一下,然后再取数组最左边的元素e做中介。

作用:解决对几乎整体有序的数组进行排序时,会导致效率低下的问题。

public static void __quickSortBase(int[] array,int l,int r){
	int temp;
	if(l>=r){
		return ;
	}
	//优化1:先随机取下标,然后与最左元素交换下
	int index = (int) (Math.random()*(r-l)+l);
	temp = array[l];
	array[l] = array[index];
	array[index] = temp;

	int e = array[l];
	int j = l;//保存<e部分尾部的下标
	for(int i=l+1;i<=r;i++){//将数组分为<e和>=e两部分
		if(array[i]<e){
			temp = array[j+1];
			array[j+1] = array[i];
			array[i] = temp;
			j++;
		}
	}
	//排序完成后,将array[j]与array[l]进行交换,此时l~j-1为<e部分,j+1~r为>=e部分
	temp = array[j];
	array[j] = array[l];
	array[l] = temp;
	//继续进行排序
	__quickSortBase(array,l,j-1);
	__quickSortBase(array,j+1,r);		
}

②当待排序部分元素个数小的时候,进行优化版的插入排序,提高效率

public static void __quickSortBase(int[] array,int l,int r){
	int temp;

// if(l>=r){
// return ;
// }
//优化2:使用优化版的插入排序改进效率
if(r-l<=15){
insertionSortBetter(array, l, r);
return ;
}

	//优化1:先随机取下标,然后与最左元素交换下
	int index = (int) (Math.random()*(r-l)+l);
	temp = array[l];
	array[l] = array[index];
	array[index] = temp;

	int e = array[l];
	int j = l;//保存<e部分尾部的下标
	for(int i=l+1;i<=r;i++){//将数组分为<e和>=e两部分
		if(array[i]<e){
			temp = array[j+1];
			array[j+1] = array[i];
			array[i] = temp;
			j++;
		}
	}
	//排序完成后,将array[j]与array[l]进行交换,此时l~j-1为<e部分,j+1~r为>=e部分
	temp = array[j];
	array[j] = array[l];
	array[l] = temp;
	//继续进行排序
	__quickSortBase(array,l,j-1);
	__quickSortBase(array,j+1,r);		
}

双路快速排序法
排序思路:首先传入待排序数组,使用变量l表示数组下标起点,使用变量r表示数组下标终点,然后取数组左侧第一个元素v做中介,声明变量i初始值为l+1,声明变量j初始值为r,如果i<=r&&array[i]比v小,i++,直到array[i]>=v;如果j>=l+1&&array[j]比v大,j–,直到array[j]<=v;交换array[i]和array[j],确保下标从li的数组元素均小于等于v,下标从jr的数组元素均大于等于v,接着i++,j–;循环完成后,j的位置是数组中<=v的最后一个元素位置,将其与array[l]互换,接着继续对lj-1和j+1r的两部分进行双路快排。

代码实现:

//双路快排,解决大量重复值的数组排序
public static void quickSort2(int[] array){
_quickSort2(array,0,array.length-1);
}

public static void _quickSort2(int[] array,int l,int r){
	//数组数量小时,用优化版插入排序提高效率
	if(r-l<=15){
		insertionSortBetter(array, l, r);
		return ;
	}
	//优化:先随机取下标,然后与最左元素交换下
	int index = (int) (Math.random()*(r-l)+l);
	int temp = array[l];
	array[l] = array[index];
	array[index] = temp;
	
	int v = array[l];//最左侧元素做中介
	
	int i = l+1,j = r;
	while(true){
		while(i<=r&&array[i]<v){i++;}//如果array[i]小于v,i++;直到碰到不小于v的元素时停止
		while(j>=l+1&&array[j]>v){j--;}//如果array[j]大于v,j--;直到碰到不大于v的元素时停止
		if(i>j){break;}
		//交换array[i]和array[j],保证下标从l~i的元素值均小于等于v,下标从j~r的元素值均大于等于v
		temp = array[i];
		array[i] = array[j];
		array[j] = temp;
		i++;
		j--;
	}
	//循环结束后,j位于<=v的最后一个元素位置,交换array[j]和array[l];此时l~j均小于等于v,下标从j~r的元素值均大于等于v,array[j]==v
	temp = array[l];
	array[l] = array[j];
	array[j] = temp;
	
	_quickSort2(array,l,j-1);
	_quickSort2(array,j+1,r);
	
}

三路快速排序法
 
排序思路:首先传入待排序数组,使用变量l表示数组下标起点,使用变量r表示数组下标终点,然后取数组左侧第一个元素v做中介,声明变量i初始值为l+1,声明变量lt初始值为l,声明变量gt初始值为r+1,先将数组分为三部分,array[l+1]array[lt]的部分<v,array[gt]到array[r]的部分>v,array[lt+1]array[i]的部分==v;当i<gt时数组进入循环处理。如果array[i]<v,将其与lt+1交换,并且lt++,此时l+1lt的部分小于v,lt到i的部分等于v;如果array[i]>v,将其与gt-1交换,并且gt–,此时gtr的部分大于v;如果array[i]v,直接i++即可。循环终止时,lt位于array中<v部分的最后一位,将其与array[l]进行互换,此时array[l]~array[lt-1]的部分<v,array[lt]到array[gt-1]的部分v,array[gt]到array[r]的部分>v。接着继续对小于v和大于v的两部分进行三路快排。

代码实现:

// 三路快排,将数组分为<v,==v,>v三部分处理
public static void quickSort3(int[] array) {
	_quickSort3(array, 0, array.length - 1);
}

public static void _quickSort3(int[] array, int l, int r) {
	// 数组数量小时,用优化版插入排序提高效率
	if (r - l <= 15) {
		insertionSortBetter(array, l, r);
		return;
	}
	// 优化:先随机取下标,然后与最左元素交换下
	int index = (int) (Math.random() * (r - l) + l);
	int temp = array[l];
	array[l] = array[index];
	array[index] = temp;

	int v = array[l];// 最左侧元素做中介
	
	int i=l+1,lt=l,gt=r+1;//array[l+1...lt]<v,array[gt...r]>v,array[lt+1....i]==v
	
	while(i<gt){
		if(array[i]<v){//将其与lt+1交换,并且lt++,此时l+1~lt的部分小于v,lt到i的部分等于v
			temp = array[i];
			array[i] = array[lt+1];
			array[lt+1] = temp;
			lt++;
			i++;
		}
		else if(array[i]>v){//将其与gt-1交换,并且gt--,此时gt~r的部分大于v
			temp = array[i];
			array[i] = array[gt-1];
			array[gt-1] = temp;
			gt--;				
		}else{//直接i++
			i++;
		}
	}
	//循环结束后,lt位于小于v的部分的最后一个元素,将其与最左侧交换
	temp = array[l];
	array[l] = array[lt];
	array[lt] = temp;
	
	//继续对小于v和大于v的两部分进行三路快排
	_quickSort3(array, 0, lt-1);
	_quickSort3(array, gt, r);
	
}

作者:墨染秦月
来源:CSDN
原文:https://blog.csdn.net/A1344714150/article/details/88789649
版权声明:本文为博主原创文章,转载请附上博文链接!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值