排序算法(2)快排

交换排序

思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

一、冒泡排序

java 复制代码
 public static void BubbleSort(int[] array){
        boolean flg = false;
        for(int i = 0;i<array.length-1;i++){
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    swap(array,j,j+1);
                    flg = true;
                }
            }
            if(!flg){
                break;
            }
        }
    }

总结

  1. 冒泡排序是一种非常容易理解的排序

  2. 时间复杂度:O(N^2)

  3. 空间复杂度:O(1)

  4. 稳定性:稳定

二、快速排序

基本思想:基于分治法的算法。任取待排序元素序列中的某元 素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

1、Hoare法
java 复制代码
//快排,递归,Hoare法
    //时间复杂度最坏下O(N^2)
    //快排一般说均匀分割下复杂度优化后趋于n*logn
    public static void quickSort(int[] array){
        quick(array,0,array.length-1);
    }
    private static void quick(int[] array,int start,int end) {
        if(start>=end){
            return;
        }
        int par = partition(array,start,end);
        quick(array,start,par-1);
        quick(array,par+1,end);
    }
    private static int partition(int[] array,int left,int right){
        int i = left;
        int pivot = array[left];
        while(left<right){
            while(left<right && array[right]>=pivot){
                right--;
            }
            while(left<right && array[left]<=pivot){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,left,i);

        return left;
    }

时间复杂度:最坏情况下O(N^2),如果是均匀分割下复杂度优化后趋于n*logn,快排一般用于乱序

问题:

1、堆和快排都是n*logn,那么那个更快呢?

快排还是更快一些,因为时间复杂度是粗略估计的,实际上堆排是kn*logn,最后都把k给去掉了,快排有可能是2logn,堆排是3logn。

2、与基准值比较的时候可以不写'='吗?

不可以!!!

3、为什么从右边开始?

如果先走左边导致最后相遇的地方是比基准大的数据,交换完后,会把大的放到了前面,不满足快排思想。

注意:因为快排是递归,数据太多的情况下会导致溢出

2、挖坑法
java 复制代码
 private static int partition2(int[] array,int left,int right){
       int tmp = array[left];
       while(left<right){
           while(left<right&&array[right]>=tmp){
               right--;
           }
           array[left] = array[right];
           while(left<right&&array[left]<=tmp){
               left++;
           }
           array[right] = array[left];
       }
       array[left] = tmp;
       return left;
    }
3、双指针法(了解)
java 复制代码
 private static int partition3(int[] array, int left, int right) {
        int prev = left ;
        int cur = left+1;
        while (cur <= right) {
            if(array[cur] < array[left] && array[++prev] != array[cur]) {
                 swap(array,cur,prev);
            }
                cur++;
        }
        swap(array,prev,left);
        return prev;
    }
4、快速排序优化(减小递归次数)
  1. 三数取中法选key

  2. 递归到小的子区间时,可以考虑使用插入排序

趋于有序的情况下,插入排序效率最高,并且可以减少递归次数

java 复制代码
   private static void quick(int[] array,int start,int end) {
        if(start>=end){
            return;
        }
        if(end-start+1<=5){
            insertSortRange(array,start,end);
            return;
        }
        
        int index = midTreeNum(array,start,end);
        swap(array,index,start);
        
        int par = partition(array,start,end);
        quick(array,start,par-1);
        quick(array,par+1,end);
    }
    public static void insertSortRange(int[] array,int start,int end){
        for(int i = start+1;i<=end;i++){
            int tmp = array[i];
            int j=i-1;
            for(;j>=start;j--){
                if(array[j]>tmp){
                    array[j+1] = array[j];
                }else{
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }
    private static int partition(int[] array,int left,int right){
        int i = left;
        int tmp = array[left];
        while(left<right){
            while(left<right && array[right]>=tmp){
                right--;
            }
            while(left<right && array[left]<=tmp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,left,i);

        return left;
    }
    private static int midTreeNum(int[] array,int left,int right){
        int mid = (left+right)/2;
        //返回的是中位数的下标
        if(array[left]<array[right]){
            if (array[mid]<array[left]){
                return left;
            }else if(array[mid]>array[right]){
                return right;
            }else{
                return mid;
            }
        }else{
            if (array[mid]>array[left]){
                return left;
            }else if(array[mid]<array[right]){
                return right;
            }else{
                return mid;
            }
        }
    }
5、快排非递归

使用栈

java 复制代码
    void quickSortNonR(int[] array) {
        Stack<Integer> stack = new Stack<>();
        int left = 0;
        int right = array.length-1;
        int par = partition(array,left,right);
        if(par>left+1){
            //如果左数只有一个值则不需要排序
            //先放左再放右
            stack.push(left);
            stack.push(par-1);
        }
        if(par<right-1){
            //先放左再放右
            stack.push(par+1);
            stack.push(right);
        }
        while(!stack.isEmpty()){
            //先取出来的是右之后是左
            right = stack.pop();
            left = stack.pop();
            par = partition(array,left,right);
            //重复最初的操作
            if(par>left+1){
                //如果左数只有一个值则不需要排序
                stack.push(left);
                stack.push(par-1);
            }
            if(par<right-1){
                stack.push(par+1);
                stack.push(right);
            }
        }
    }

总结:

  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2、时间复杂度:O(N*logN)

3、空间复杂度:O(logN)(递归开空间)

4、不稳定

例题:设一组初始记录关键字序列为(65,56,72,99,86,25,34,66),则以第一个关键字65为基准而得到的一趟快速排序结果是()

A: 34,56,25,65,86,99,72,66 B: 25,34,56,65,99,86,72,66

C: 34,56,25,65,66,99,86,72 D: 34,56,25,65,99,86,72,66

优先尝试挖坑法,之后是Hoare法,最后双指针(很少用)

相关推荐
苹果醋3几秒前
2020重新出发,MySql基础,MySql表数据操作
java·运维·spring boot·mysql·nginx
小蜗牛慢慢爬行2 分钟前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
azhou的代码园5 分钟前
基于JAVA+SpringBoot+Vue的制造装备物联及生产管理ERP系统
java·spring boot·制造
dundunmm11 分钟前
机器学习之scikit-learn(简称 sklearn)
python·算法·机器学习·scikit-learn·sklearn·分类算法
古希腊掌管学习的神12 分钟前
[机器学习]sklearn入门指南(1)
人工智能·python·算法·机器学习·sklearn
波音彬要多做13 分钟前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
wm10431 小时前
java web springboot
java·spring boot·后端
smile-yan1 小时前
Provides transitive vulnerable dependency maven 提示依赖存在漏洞问题的解决方法
java·maven
老马啸西风1 小时前
NLP 中文拼写检测纠正论文-01-介绍了SIGHAN 2015 包括任务描述,数据准备, 绩效指标和评估结果
java
Earnest~1 小时前
Maven极简安装&配置-241223
java·maven