专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

挖坑法实现快速排序(Java,Scala)

了解快速排序

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。快速排序是一种不稳定的排序法。

快速排序的操作步骤

1、 取出一个数作为基准。(下文将该基准命名为temp)
2、 所有小数在其前,所有大数在其后,因此temp左右两边共产生了两个子区间。
3、 两个子区间内部未必是有序的。因此分别在每个区间内重复1,2操作,直到各个区间只有一个数。禁止套娃?

由于每个区间内的处理方法是重复的,因此我们可以用递归函数来实现它(递归函数占用栈空间),也可以采取while循环来解决。

快速排序可以轻松应付庞大且无序的数组,但是若用于高度有序(甚至完全升序,降序排列好的,元素内容完全重复的)的数组,表现反而会很糟糕。

挖坑法提供的解决思路

上段中提到的操作步骤2有很多种方法实现,思路大同小异。在这里使用挖坑法来实现。 我们首先准备:

  • 两个”指针” (虽然它们实际上只是数组下标号,但为了方便理解,下文仍统称为指针) lowhigh,分别指向数组的首和尾,且high只向移动,low只向移动。
  • 默认将数组首元素保存到temp当中。

换个说法,在程序开始前,在arr[low]的位置挖了坑,该位置上的数被移到了temp中。

有一个大前提:在调用该函数时low < high必须成立,否则不再继续递归。因为low==high意味着这个数组只有1个元素,那就没有必须再进行排序了。

104_1.png

程序运行,low指针不动,而high指针判断它所目前指向的值是否大于temp。满足条件则左移,否则high指针会停下来,将当前指向的值覆盖到arr[low]位置上。(演示图里第一次判断就中了奖 =D)

104_2.png

或者说,high位置上的数被挖出来填到了low位置上的坑。

104_3.png此刻, high指针不动, low指针判断它所目前指向的值是否小于 temp。满足条件则右移,否则 low指针会停下来,将当前指向的值覆盖到 arr[high]位置上。(这一段叙述和上一段叙述互为反过程。)

或者说,low位置上的数又被挖出来填了上一步high指针位置留下来的坑。

high指针再次开始左移,直到发现大于等于temp的数,则将其挖出来填到low指针的地方并暂停,随后low指针又不断右移,直到发现小于temp的数,再将它挖出填到high指针处……highlow指针一直处于交替相向移动的状态。

如此下去,总有一刻high指针和low指针会指向同一位置。此刻无需再移动highlow指针,只需要把最初挖出来的temp值,放到这个坑内即可。

104_4.png

我们此时可以发现,原先的数组已经被分为了三部分:比temp小的数,temp,比temp大(或等)的数组。

104_5.png

只需要再对Smaller和Greater区间进行递归操作,重复之前所述的步骤就可以了。

基于挖坑法的Java快速排序

 static void quickSortJ(Integer[] arr, int start, int end) {
        if (start < end) {
            Integer low = start;
            Integer high = end;
            Integer temp = arr[low];

            while (low < high) {

                while (high > low && arr[high] >= temp) high--;
                if (high > low) arr[low] = arr[high];
                while (high > low && arr[low] < temp) low++;
                if (high > low) arr[high] = arr[low];

            }

            arr[high] = temp;
            quickSortJ(arr, start, low - 1);
            quickSortJ(arr, high + 1, end);
        }
    }

我只要[Smaller[], Temp, Greater[]]!

我们在进行一轮排序后(左右指针法,挖坑法,etc.)必定能将数组分割成以下形式:[Smaller[], temp, Greater[]]。那能不能用更简单偷懒的方法来得到Smaller区间和Greater区间呢? 在Scala中,可以直接利用过滤器filter来过滤出比temp小(或大)的数。如:

arr.filter(x => x > temp) //filter处理之后得到的仍是Array[],放心食用。

而后再对过滤出来的Smaller[],和Greater[]继续进行递归即可。用Java的流处理同样可以实现类似逻辑,但是比较麻烦。

用Scala实现快速排序


def quickSortScl(arr: Array[Int]): Array[Int] = { if (arr.length <= 1) arr else { //这里的temp没有选取首元素,而是取中间元素. val temp =arr(arr.length/2) //返回一个[SmallerThanTemp[],temp,GreaterThanTemp[]]. Array.concat( quickSortScl(arr.filter(x => x<temp)), //如果有多个相等的元素,则该数组内的元素个数大于1. arr.filter(x => x==temp), quickSortScl(arr.filter(x => x>temp)) ) } }

传送门链接

文章永久链接:https://tech.souyunku.com/42006

未经允许不得转载:搜云库技术团队 » 挖坑法实现快速排序(Java,Scala)

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们