优化后的快速排序(详解)

news/2024/5/19 23:58:27 标签: 数据结构, java, 快速排序

目录

快速排序

三数取中值分割法获得枢纽元

快速排序的主例程

直接插入排序代码

快速排序完整代码 


快速排序

快速排序是实践中的一种快速的排序算法,它的平均运行时间是O(N log N),该算法之所以特别快,是因为它有非常精炼和高度优化的内部循环。

可以快速排序和直接插入排序结合起来得到优化后的快速排序,当数据量较小时,如果继续利用快速排序对其进行排序操作,其效率比较低下,因为快速排序是递归的,因此当遇到很小的数组(N<=20)时,采用直接排序对其进行排序.

三数取中值分割法获得枢纽元

在选择快速排序的枢纽元时,采取三数中值分割法(即在数组第一个元素,数组最后一个元素和数组中间元素三个元素中选择值处在中间的那个数)

以上述数据为例 ,设该数组为arr,分别将找到其left,mid,right

之后对这三个数据进行比较,将其进行交换,比较方式如下:

1、比较left下标的值和mid下标的值,如果arr[left] > arr[mid],将left下标的值和mid下标的值交换;

2、比较left下标和right下标的值,如果arr[left] > arr[right],将left下标的值与right下标的值进行交换;

3、比较right下标的值和mid下标的值,如果arr[right] < arr[mid],将right下标的值和mid下标的值交换;

4、在完成上述比较后,再将right-1下标的值和mid下标的值进行交换;

5、返回arr[right-1].

 进行完上述步骤后,arr变为

具体代码实现

    public static int median3(int[] arr, int left, int right) {
        int mid = (left + right) / 2;
        if(arr[left] > arr[mid]) {
            swap(arr,left,mid);
        }
        if(arr[left] > arr[right]) {
            swap(arr,left,right);
        }
        if(arr[mid] > arr[right]) {
            swap(arr,mid,right);
        }
        //找到中间元素后将其放在arr.length-1的位置.
        swap(arr,mid,right-1);
        return arr[right-1];
    }

快速排序的主例程

 1、首先判断目前分治后需要排序的数据数量,设定CUTOFF = 10,若数据量小于等于CUTOFF,直接进行插入排序,反之进行快速排序

2、令i = left,j = right - 1,利用i++寻找到左边第一个大于pivot的值,利用j--在右边寻找到第一个小于pivot的值,并对其进行交换;

3、 交换之后依次递归以枢纽元分割好的两个部分,分别对其进行快速排序.

 当i和j指向这两个位置时,对其进行交换

 交换完成后继续进行寻找,直至i > j为止,对于arr数组来说,下图所示状态为其截止状态

之后再将arr[i] 和arr[pivot]进行交换,得到如下结果

 

之后以i下标作为分割线,分别对i左边和右边的数据进行快速排序

具体代码实现

    public static final int CUTOFF = 10;
    public static void quickSort(int[] arr, int left, int right) {
        if(left + CUTOFF <= right) {
            int pivot = median3(arr,left,right);
            int i = left;
            int j = right-1;
            for(; ;) {
                while(arr[++i] < pivot) {}
                while(arr[--j] > pivot) {}
                if(i < j) {
                    swap(arr,i,j);
                }else {
                    break;
                }
            }
            swap(arr,i,right-1);
            quickSort(arr,left,i-1);
            quickSort(arr,i+1,right);
        }else {
            insertSort1(arr,left,right);
        }
    }

直接插入排序代码

    public static void insertSort1(int[] arr,int left,int right) {
        for (int i = left+1; i <= right; i++) {
            int tmp = arr[i];
            int j = i-1;
            for(; j >= left; j--) {
                if(arr[j] > tmp) {
                    arr[j+1] = arr[j];
                }else {
                    break;
                }
            }
            arr[j+1] = tmp;
        }
    }

快速排序完整代码 

快速排序完整代码+测试用例

    /**
     * 快速排序
     * @param arr
     */
    public static final int CUTOFF = 10;
    public static void quickSort(int[] arr, int left, int right) {
        if(left + CUTOFF <= right) {
            int pivot = median3(arr,left,right);
            int i = left;
            int j = right-1;
            for(; ;) {
                while(arr[++i] < pivot) {}
                while(arr[--j] > pivot) {}
                if(i < j) {
                    swap(arr,i,j);
                }else {
                    break;
                }
            }
            swap(arr,i,right-1);
            quickSort(arr,left,i-1);
            quickSort(arr,i+1,right);
        }else {
            insertSort1(arr,left,right);
        }
    }
    //三数取中分割法
    public static int median3(int[] arr, int left, int right) {
        int mid = (left + right) / 2;
        if(arr[left] > arr[mid]) {
            swap(arr,left,mid);
        }
        if(arr[left] > arr[right]) {
            swap(arr,left,right);
        }
        if(arr[mid] > arr[right]) {
            swap(arr,mid,right);
        }
        //找到中间元素后将其放在arr.length-1的位置.
        swap(arr,mid,right-1);
        return arr[right-1];
    }
    //直接插入排序
    public static void insertSort1(int[] arr,int left,int right) {
        for (int i = left+1; i <= right; i++) {
            int tmp = arr[i];
            int j = i-1;
            for(; j >= left; j--) {
                if(arr[j] > tmp) {
                    arr[j+1] = arr[j];
                }else {
                    break;
                }
            }
            arr[j+1] = tmp;
        }
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void main(String[] args) {
        int[] arr = {5,8,16,4,32,64,25,31,1,26,27,11};
        quickSort(arr,0,arr.length-1);
        System.out.println("快速排序后的数组为:");
        System.out.println(Arrays.toString(arr));
    }

 


http://www.niftyadmin.cn/n/735924.html

相关文章

Java实现二叉查找树及其相关操作

目录 二叉查找树 初始化 二叉查找树的查找 二叉查找树的插入 二叉查找树的删除 二叉查找树的中序遍历 findMax and findMin 二叉查找树完整代码 测试用例 完整代码已上传至gitee中&#xff1a;gitee代码仓库 二叉查找树 二叉查找树&#xff0c;又称二叉排序树…

如何编写更好的SQL查询:终极指南-第二部分

基于集合和程序的方法进行查询 > > > > >

你了解直接进行访问的数据结构吗?一篇文章带你了解简单的哈希表的实现

目录 哈希表 哈希表的实现 初始化 计算负载因子 哈希表的扩容 哈希表的插入 查找元素 完整代码 测试用例 哈希表实现代码已上传至gitee中&#xff1a;点击查看代码 哈希表 哈希表(也称散列表)&#xff1a;是根据关键码值而直接进行访问的数据结构。也就是说&…

伟大架构师的秘密

By Don Awalt and Rick McUmber RDA Corporation 企业架构师正受到其所面临的大量复杂性的挑战。开发一个能够自动处理企业任务的独立的部门应用程序是一回事。而设计并组成一个支持上万 IT 使用者的满是应用程序、服务器和数据库&#xff08;全都支持多种企业活动&#xff09;…

找出一堆整数中两个元素和为指定值的所有组合

问题描述 5, 5,-7, 5, 9, -1, 5, 1, 9, 4, 6 这堆数中两个数的和为10的组合有:55, 91, 46,如何快速的找出这样的组合&#xff1f; 假定 数组a[]存放元素&#xff0c;数组大小为len_a 指定和为aim 思路一 先排序&#xff0c;low0(最低位置)&#xff0c;uplen_a(最高位置) 当a[lo…

MySQL~数据库基础(常用数据类型、数据库的操作、表的操作)

目录 常用数据类型 数值型(整型、浮点型) 字符串类型 日期类型 数据库的操作 显示当前数据库 创建数据库 使用数据库 删除数据库 表的操作 创建表 查看表 删除表 重点总结 常用数据类型 数值型(整型、浮点型) BIT(M)&#xff1a;大小&#xff1a;M指定位数&am…

MySQL~数据表中的增删查改(CRUD)基础版

目录 新增数据(Create) 单行数据 全列插入 多行数据 指定列插入 查询数据(Retrieve) 全列查询 指定列查询 查询字段为表达式 别名 去重 distinct 排序 order by 条件查询 where 运算符 基本查询 AND与OR 范围查询 分页查询 LIMIT 修改(Update) 删除 D…

Android 音乐(音效)播放方式总结

一、音效的分类 音效按照作用的不同&#xff0c;可以将音效分为即时音效和背景音乐。两种音效在Android中的实现技术是不同的。 主要的实现方式为&#xff1a;SoundPool、MediaPlayer。 区别在于&#xff0c;MediaPlayer会在播放音频的时候&#xff0c;会占用大量的系统资源&am…