快速排序:Hoare法、挖坑法、前后指针法

1.1 原理
  1. 从待排序区间选择一个数,作为基准值(pivot);
  2. Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
  3. 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度等于1,代表已经有序,或者小区间的长度等于0,代表没有数据
1.2 快速排序图示

在这里插入图片描述

1.3 代码示例(原理-partition)
1.3.1 Hoare法
 //hoare版本

    public int partitionHoare(int[] array,int lowIndex,int highIndex){
        int leftIndex = lowIndex;
        int rightIndex = highIndex;
        int key = array[lowIndex];
        //基准值选取 左边值
        while(leftIndex<rightIndex){
            while(leftIndex<rightIndex && array[rightIndex]>=key){
                rightIndex--;
            }
            //出循环说明rightIndex 遇到比key小的值了
            while(leftIndex<rightIndex && array[leftIndex]<=key){
                leftIndex++;
            }
            //出循环说明leftIndex 遇到比key大的值了

            //交换这两个位置的值
            swap(array,leftIndex,rightIndex);

        }
        swap(array,lowIndex,leftIndex);
        return leftIndex;
    }

    public void quickSortInternal_Hoare(int[] array,int lowIndex,int highIndex){
        int size = highIndex-lowIndex+1;
        if(size<=1){
            return;
        }
        //选取一个基准值:选取最左边的数
        //执行partition,小的放左,大的放右
        //经过partition之后选出来的最终值
        int keyIndex = partitionHoare(array,lowIndex,highIndex);

        //分别对左右区间进行相同的处理方法
        quickSortInternal_Hoare(array,lowIndex,keyIndex-1);
        quickSortInternal_Hoare(array,keyIndex+1,highIndex);
    }
     public void swap(int[] array,int index1,int index2){
        int tmp = array[index1];
        array[index1] = array[index2];
        array[index2] = tmp;
    }
    public void quickSort_Hoare(int[] array){
        quickSortInternal_Hoare(array,0,array.length-1);
    }
1.3.2 挖坑法

基本思路和Hoare法一致,只是不再进行交换,而是进行赋值(填坑+挖坑)

 //挖坑法
    public void quickSortInternal_Dig(int[] array,int lowIndex,int highIndex) {
        //由于是闭区间,所以区间个数需要加一
        int size = highIndex-lowIndex+1;
        if(size<=1) {
            return;
        }
        //选取其中一个数(选最左边的)
        //执行partition,小的放左,大的放右
        //经过partiton之后选出来的最终值
        int keyIndex = partitionDig(array,lowIndex,highIndex);
        //分别对左右区间进行相同的处理方法——递归方法
        quickSortInternal_Dig(array,lowIndex,keyIndex-1);
        quickSortInternal_Dig(array, keyIndex+1, highIndex);
    }

    public int partitionDig(int[] array,int lowIndex,int highIndex) {
        int leftIndex = lowIndex;
        int rightIndex = highIndex;
        int key = array[lowIndex];
        //选择了最左边,从右边先走
        while(leftIndex<rightIndex) {
            while(leftIndex<rightIndex&&array[rightIndex]>=key) {
                rightIndex--;
            }
            //说明rightIndex遇到比key小的值了

            array[leftIndex] = array[rightIndex];
            while(leftIndex<rightIndex&&array[leftIndex]<=key) {
                leftIndex++;
            }
            //说明leftIndex遇到比key大的值了

            array[rightIndex] = array[leftIndex];
        }
        //填坑
        array[leftIndex] = key;
        //到这
        return leftIndex;
    }

    public void quickSort_Dig(int[] array) {
        quickSortInternal_Dig(array,0,array.length-1);
    }
1.3.3 前后指针法
    //前后指针法
    public int partitionPoint(int[] array,int lowIndex,int highIndex) {
//        int front,rear;
//        front = rear = lowIndex+1;
//        //选择了最左边,从右边先走
//        while(rear<=highIndex) {
//            if(array[rear]<array[lowIndex]) {
//                swap(array,rear,front);
//                front++;
//            }
//            rear++;
//        }
//        swap(array,lowIndex,front-1);
//        //到这
//        return front-1;
		
		int front = lowIndex+1;
		for(int rear = lowIndex+1;rear<=highIndex;rear++) {
			if(array[rear]<array[lowIndex]) {
				swap(array,rear,front);
				front++;
			}
		}
		swap(array,lowIndex,front-1);
		return front-1;
    }


    //前后指针
    public void quickSortInternal_Point(int[] array,int lowIndex,int highIndex) {
        //由于是闭区间,所以区间个数需要加一
        int size = highIndex-lowIndex+1;
        if(size<=1) {
            return;
        }
        //选取其中一个数(选最左边的)
        //执行partition,小的放左,大的放右
        //经过partiton之后选出来的最终值
        int keyIndex = partitionPoint(array,lowIndex,highIndex);
        //分别对左右区间进行相同的处理方法——递归方法
        quickSortInternal_Point(array,lowIndex,keyIndex-1);
        quickSortInternal_Point(array, keyIndex+1, highIndex);
    }

    public void quickSort_Point(int[] array) {
        quickSortInternal_Point(array,0,array.length-1);
    }
1.4 性能分析
  • 时间复杂度:

    • 最好:O(n*log(n))
    • 平均:O(n*log(n))
    • 最坏:O(n^2)
  • 空间复杂度:

    • 最好:O(log(n))
    • 平均:O(log(n))
    • 最坏:O(n)
1.5 基准值的选择及优化
  • 在待排序区间选择一个基准值

    • 选择边上(左或者右)
    • 随机选择
    • 几数取中(三数取中)
  • 做partition,使得小的数在左,大的数在右(小细节优化)

  • 数量比较少,不是最快(当区间的个数低于某个阈值时(16),使用插排)

  • 相等的值做特殊处理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值