首页 > 编程语言 >十大排序算法快速排序之Java实现

十大排序算法快速排序之Java实现

时间:2023-04-23 10:38:07浏览次数:37  
标签:begin end 轴点 元素 算法 pivot Java array 排序


快速排序

快速排序(Quick Sort)是对冒泡排序的一种改进,采用的是分治策略(一般与递归结合使用),以减少排序过程中的比较次数。

快速排序在1960年由查尔斯·安东尼·理查德·霍尔(Charles Antony Richard Hoare,缩写为C. A. R. Hoare)提出,昵称为东尼·霍尔(Tony Hoare)。

算法步骤

  1. 从数组中选择一个轴点元素(pivot),假设每次都选择索引为0的元素为轴点元素。
  2. 利用pivot将数组分割成2个子数组,将小于pivot的元素放在pivot前面(左侧),将大于pivot的元素放在pivot后面(右侧),等于pivot的元素放哪边都可以。
  3. 递归对子序列进行前面两步操作,直到不能再分割(子序列中只剩下1个元素)。

快速排序的本质:逐渐将每一个元素都转换成轴点元素。

十大排序算法快速排序之Java实现_java

动图演示

十大排序算法快速排序之Java实现_快速排序_02

代码实现

package com.morris.data.struct.sort.cmp;

import com.morris.data.struct.sort.AbstractSort;

/**
 * 快速排序
 */
public class QuickSort<E extends Comparable> extends AbstractSort<E> {

    @Override
    protected void sort() {
        sort(0, array.length);
    }

    private void sort(int begin, int end) {

        if(end - begin < 2) {
            return;
        }

        int pivotIndex = pivotIndex(begin, end);

        sort(begin, pivotIndex);
        sort(pivotIndex + 1, end);

    }

    /**
     * 返回轴点元素的真正索引
     * @param begin
     * @param end
     * @return
     */
    private int pivotIndex(int begin, int end) {

        // 随机选择一个元素跟begin位置进行交换,为了降低最好时间复杂度
        swap(begin, begin + (int)(Math.random() * (end - begin)));

        E pivot = array[begin];
        end--;

        while (begin < end) {

            while (begin < end) {
                // 从右向左扫描
                if(cmp(array[end], pivot) < 0) {
                    array[begin++] = array[end];
                    break;
                } else {
                    end--;
                }
            }

            while (begin < end) {
                // 从左向右扫描
                if(cmp(array[begin], pivot) > 0) {
                    array[end--] = array[begin];
                    break;
                } else {
                    begin++;
                }
            }
        }

        array[begin] = pivot; // begin==end

        return begin;
    }
}

在轴点左右元素数量比较均匀的情况下,同时也是最好的情况,所以最好时间复杂度和平均时间复杂度均为O(nlogn)。

如果轴点左右元素数量极度不均匀就会出现最坏情况,所以最坏时间复杂度为O(n^2)。

为了降低最坏情况的出现概率,一般采取的做法是:随机选择轴点元素。

由于递归调用的缘故,所以空间复杂度为O(logn)。

对相等元素的处理

当代码中下面两处的比较为<或>时,快速排序对相等元素的处理过程如下:

...
// 从右向左扫描
if(cmp(array[end], pivot) < 0) {
...
...
// 从左向右扫描
if(cmp(array[begin], pivot) > 0) {
...

十大排序算法快速排序之Java实现_java_03

如果数组中的所有元素都与轴点元素相等,利用目前的算法实现,轴点元素可以将数组分割成2个均匀的子序列。

当代码中下面两处的比较为<=或>=时,快速排序对相等元素的处理过程如下:

...
// 从右向左扫描
if(cmp(array[end], pivot) <= 0) {
...
...
// 从左向右扫描
if(cmp(array[begin], pivot) >= 0) {
...

十大排序算法快速排序之Java实现_排序算法_04


根据轴点元素分割出来的子数组极度不均匀,会导致出现最坏时间复杂度O(n^2)。更多精彩内容关注本人公众号:架构师升级之路

十大排序算法快速排序之Java实现_排序算法_05


标签:begin,end,轴点,元素,算法,pivot,Java,array,排序
From: https://blog.51cto.com/u_6784072/6216453

相关文章

  • jvm之垃圾回收算法
    垃圾回收算法哪些内存需要回收jvm的内存模型中将内存划分为程序计数器、虚拟机栈、本地方法栈、堆、方法区。其中程序计数器、虚拟机栈、本地方法栈属于线程私有的内存空间,与线程的生命周期保持一致,不需要手动回收内存。方法区中存放的是类的结构信息,对方法区的回收其实就是对类进......
  • 十大排序算法之归并排序
    归并排序归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。算法步骤不断地将当前序列平均分割成2个子序列,直......
  • 排序算法之希尔排序
    希尔排序1959年由唐纳德·希尔(DonaldShell)提出希尔排序。希尔排序的思想:把数组中的元素看作是一个矩阵,分成m列,逐列进行排序(一般采用插入排序),m从某个整数逐渐减为1,当m为1时,整个序列将完全有序。因此,希尔排序也被称为递减增量排序(DiminishingIncrementSort)。矩阵的列数取决于步长......
  • Java虚拟机之JVM工具监控调优
    我是攻城师(woshigcs)前几篇我们学习了,JVM里面的运行结构,GC算法,以及各种垃圾收集器的优劣点,那么本篇我们来看下如何使用一些虚拟机性能监控工具,来监控和快速处理故障,当JVM出现一些故障时,我们通常从如下的几个方面进行着手分析,包括运行日志,异常堆栈,GC日志,线程快照(threaddump/javacor......
  • Redis、Memcached、Guava、Ehcache中的算法
    1.LRU简单粗暴的Redis今天看 Redis3.0的发行通告里说,LRU算法大幅提升了,就翻开源码来八卦一下,结果哭笑不得,这旧版的"近似LRU"算法,实在太简单,太偷懒,太Redis了。在 Github的Redis项目里搜索lru,找到代码在redis.c的freeMemoryIfNeeded()函数里。先看 2.6版的代码:竟然就是随机找三......
  • Java_final 和 构造代码块
    书上的笔记转移:【REVIEW】:final除了不被重写、不被修改、不被继承、值不可变等等。。。还有以下几个特性: 1.如果成员变量的final修饰未进行赋值,那么是可以在构造方法和构造代码块进行赋值的,如果赋值成功,那么后面都不可能在进行赋值了。 ---2. 静态代码块我知道,就是只执......
  • 代码随想录算法训练营第四天 | 24.两两交换链表
     ......
  • m基于WDM网络的波长分配算法matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:      2.算法涉及理论知识概要       波分复用WDM(WavelengthDivisionMultiplexing)是将两种或多种不同波长的光载波信号(携带各种信息)在发送端经复用器(亦称合波器,Multiplexer)汇合在一起,并耦合到光线路的同一......
  • Java泛型
    Java泛型概念Java泛型是一种在编译时进行类型检查和类型推断的机制,它可以让我们编写更加通用、可重用的代码,提高了代码的可读性和可维护性,同时保证了类型安全。Java泛型的核心思想是类型参数化,即在类、接口或方法的定义中使用类型参数来代替具体的类型,这些类型参数在实例化时被具体......
  • Java 编程问题:四、类型推断
    本章包括21个涉及JEP286或Java局部变量类型推断(LVTI)的问题,也称为var类型。这些问题经过精心设计,以揭示最佳实践和使用var时所涉及的常见错误。到本章结束时,您将了解到将var推向生产所需的所有知识。问题使用以下问题来测试您的类型推断编程能力。我强烈建议您在使用解决方案......