七大排序之快速排序

原理

  • 从待排序区间选择一个基准值
    如何选择基准值?
    1. 可以选择两端的数据(代码中选取这种方法)
    2. 随机选取
    3. 三数取中法(后续会讲)
  • 做 partition,将比基准值大的放在基准值的右边,比基准值小的放在基准值的左边
    partition 的方法?(代码讲解)
    1. hoare
    2. 挖坑法
    3. 遍历法
  • 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度为 1 ,代表有序,或者长度为 0 ,代表没有数据
    分治方法?
    1. 递归
    2. 非递归

实现

public class QuickSort{
	public static void quickSort(int[] arr){
		quickSortInter(arr,0,arr.length-1);
	}
	
	//分治思想:递归
	public static void quickSortInter(int[] a,int left,int right){
		if(left>=right){
			return;
		}
		//1. 选择基准值 a[left]
		//2. 做 partition(比基准值大的放在基准值右边,比基准值小的放在基准值左边)
		int pivotIndex = partition(a,left,right);
		//3. 对左右小区间继续处理
		//左区间[left,pivotIndex-1]
		//右区间[pivotIndex+1,right]
		quickSortInter(a,left,pivotIndex-1);
		quickSortInter(a,pivotIndex+1,right);
	}
	
	//做 partition 之 hoare 法
	
	//将第一个数作为基准值,将数组最后一个元素和基准值比较,
	//大于基准值,end--,小于基准值,再从数组第二个元素开始,
	//如果元素小于基准值,begin++,
	//如果元素大于基准值,将这个数和 end 指向的数交换,就达到了前面的数比基准值小,后面的数比基准值大,
	//重复此步骤,直到 begin 和 end 相遇,交换基准值和 begin(或 end,此时 begin 和 end 已经相等)下标对应的元素
	public static int partition(int[] a,int left,int right){
		int begin = left;
		int end = right;
		int pivot = a[left];
		while(begin < end){
			while(begin < end && a[end] >= pivot){
				end--;
			}
			while(begin < end && a[begin] <= pivot){
				begin++;
			}
			//如果是内层的第一个循环走到这里,说明 a[end] < pivot,为了保证后面的元素比基准值大,所以需要交换
			//如果是内层的第二个循环到这里,说明 a[begin] > pivot,为了保证前面的元素比基准值小,所以需要交换
			swap(a,begin,end);
		}
		//说明 begin==end ,此时需要交换 begin 和 left 的值,
		//保证基准值在中间,左边的元素比基准值小,右边的元素比基准值大
		swap(a,left,begin);
		return begin;
	}
	
	//做 partition 之挖坑法
	
	//挖坑法和 hoare 相同的,只是不再交换,而是赋值
	public static int partition(int[] a,int left,int right){
		int begin = left;
		int end = right;
		int pivot = a[left];
		
		while(begin < end){
			while(begin < end && a[begin] <= pivot){
				begin++;
			}
			a[end] = a[begin];
			while(begin < end && a[end] >= pivot){
				end--;
			}
			a[begin] = a[end];
	    }
		a[begin] = pivot;
		return begin;
	}
	
	//遍历

	//上边两种方法都是从两头比较,而这种方法是从一边比较
	//当所比较的元素小于基准值时,交换 i 和 d 的元素
	public static int partition(int[] a,int left,int right){
		int pivot = a[left];
		int d = left + 1;
		for(int i = left + 1;i<=right;i++){
			if(a[i] < pivot){
				swap(a,i,d++);
			}
		}
		swap(a,left,d-1);
		return d - 1;
	}			
//非递归实现分治思想
public static void quickSort(int[] arr){
	Stack<Integer> stack = new Stack<>();
	
	stack.push(arr.length-1);
	stack.push(0);
	
	while(!stack.isEmpty()){
		int left = stack.pop();
		int right = stack.pop();
		if(left >= right){
			continue;
		}
	}
	
	int pivotIndex = patition(arr,left,right);
	//3. 对左右小区间继续处理
	//左区间[left,pivotIndex-1]
	//右区间[pivotIndex+1,right]
	stack.push(right);
	stack.push(pivotIndex+1);
	stack.push(left);
	stack.push(pivotIndex-1);
}

基准值之三数取中法

在快排的过程中,要选取基准值,以基准值为分割点,将数据划分成小区间,在此采用三数取中法,即取前端、中间和后端三个数
在这里插入图片描述
再对左右区间进行类似操作即可得到有序序列

复杂度

在这里插入图片描述

稳定性

不稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值