快速排序--Java

快速排序是在实践中运行比较快速的一种排序算法。它的平均时间性能为O(NlogN),但它的最坏的时间性能也是O(N^{2})。像归并排序一样,快速排序是也是一种分治的递归算法。快速排序的算法思想是选取一个枢纽,根据这个枢纽可以将数组分为三个部分,小于的一组,等于的一组,大于的一组。然后对小于和大于的进行排序,排序好后和等于的三者进行连接得到最后排序好的数组。快速排序的经典实现算法为:

  1. 如果数组是0或者1个元素的时候直接返回
  2. 在数组中任意选取一个元素V作为枢纽
  3. 将剩余的元素分为两个集合小于等于的和大于等于的。
  4. 然后返回小于等于的后接上V在接上返回大的大于的。

在这里有两个问题需要注意:

  1. 枢纽的选择问题,如果选取第一个元素的话,那么如果预先输入的数组是将近有序的,那么第一个元素很可能就是相对较小的元素,那么整个排序将会出现一边倾斜的现象,将会是O(N^{2})的时间复杂度。我们可以选择随机选择一个位置作为枢纽,这样是可行的,但是随机数的产生也会浪费时间。所以我们一般是选择left,center,right位置的元素进行一个排序,使这三个位置的元素是有序的,这个时候就选择center的位置作为枢纽,然后把这个center位置的元素和right-1位置的元素进行交换,然后递归的开始位置选择left+1和right-2。这样做不仅可以使选择枢纽是相对较中间的数,又可以为循环设置边界。
  2. 如果遇到了相等的元素,i和j的位置该不该停下来。设想一些如果全是是相等的元素,如果i和j都停下来,那么将会产生大量相同元素的交换,但是这个时候会产生两个平衡的数组,按照归并的思想,此时的时间复杂度是O(NlogN)。如果停止了,那么center的位置就变成了right-1或者right,也就是会产生两个极其不平衡的数组,这样的时间复杂度将会是O(N^{2})。因此我们的做法还是要选择停下来进行交换。
  3. 如果数组的长度小于20的时候,插入排序算法会比快速排序的算法快。经统计,这样会带来15%的提速。

代码:

public class quickSort {
	public void sort(int[] nums) {
		if(nums.length == 0 || nums.length == 1) {
			return ;
		}
		quickSort(nums,0,nums.length -1,10);
	}
	
	private void quickSort(int[] nums,int left,int right,int offset) {
		
		if(left + offset <=right) {
			//找到枢纽元素
			int pivot = getPivot(nums,left,right);
			
			int i = left ;
			//最后一个元素肯定比枢纽大
			int j = right -1;
			
			for(;;) {
				//左边要找到比枢纽值大的位置就停止
				while(nums[++i]<=pivot) {}
				//右边要找到比枢纽值小的位置就停止
				while(nums[--j]>=pivot) {}
				//只有i>=j的时候才进行交换
				if(i<j) {
					swap(nums,i,j);
				}
				else {
					break;
				}
			}
			
			//最后一定要对pivot的位置进行更新,因为前面可能还有比它大的元素
			swap(nums,right-1,i);
			
		
			quickSort(nums,left,i-1,10);
			
			
			quickSort(nums,i+1,right,10);
			
		}
		else {
			insertSort(nums,left,right);
		}
		
	}
	
	//插入排序
	private void insertSort(int[] nums,int left,int right) {
		int j= 0;
		for(int i = left+1;i<=right;i++) {
			int temp = nums[i];
			for( j= i;j>left&&temp<nums[j-1];j--) {
				nums[j] = nums[j-1];
			}
			nums[j] = temp;
		}
	}
	

	
	
	//对前中后三个元素进行排序并返回枢纽元素
	private int getPivot(int nums[],int left,int right) {
		int center = (left+right)/2;
		
		
		//这个过后,left的位置元素小于center位置的
		if(nums[left] > nums[center]) {
			swap(nums,left,center);
		}
		//这个过后,center位置的元素小于right位置的
		if(nums[center]>nums[right]) {
			swap(nums,center,right);
		}
		//这个过后,left位置小于center位置
		if(nums[left] > nums[center]) {
			swap(nums,left,center);
		}
		
		
		
		//交换center和right-1位置的元素
		swap(nums,center,right-1);
		
		
		//返回枢纽的值
		return nums[right-1];
	}
	
	
	//交换两个元素的值
	private void swap(int[] nums,int a,int b) {
		int temp = 0;
		temp = nums[a];
		nums[a] = nums[b];
		nums[b] = temp;
	}
	
	
	public static void main(String[] args) {
		quickSort sort = new quickSort();
		int[] nums = {5,9,7,6,88,45,62,1,7,777,4,84,12,58,64,73,29,15};
		
		sort.sort(nums);
		for(int i = 0;i<nums.length;i++) {
			System.out.print(nums[i]+",");
		}
	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值