temp
) temp
左右两边共产生了两个子区间。 由于每个区间内的处理方法是重复的,因此我们可以用递归函数来实现它(递归函数占用栈空间),也可以采取while循环来解决。
快速排序可以轻松应付 庞大且无序的数组 ,但是若用于高度有序(甚至完全升序,降序排列好的,元素内容完全重复的)的数组,表现反而会很糟糕。
上段中提到的操作步骤2有很多种方法实现,思路大同小异。在这里使用挖坑法来实现。 我们首先准备:
low
和 high
,分别指向数组的首和尾,且 high
只向 左 移动, low
只向 右 移动。 temp
当中。 换个说法,在程序开始前,在arr[low]的位置挖了坑,该位置上的数被移到了temp中。
有一个大前提:在调用该函数时 low < high
必须成立,否则不再继续递归。因为 low
== high
意味着这个数组只有1个元素,那就没有必须再进行排序了。
程序运行, low
指针不动,而 high
指针判断它所目前指向的值是否大于 temp
。满足条件则左移,否则 high
指针会停下来,将当前指向的值覆盖到 arr[low]
位置上。(演示图里第一次判断就中了奖 =D)
或者说, high
位置上的数被挖出来填到了 low
位置上的坑。
high
指针不动,
low
指针判断它所目前指向的值是否小于
temp
。满足条件则右移,否则
low
指针会停下来,将当前指向的值覆盖到
arr[high]
位置上。(这一段叙述和上一段叙述互为反过程。)
或者说, low
位置上的数又被挖出来填了上一步 high
指针位置留下来的坑。
high
指针再次开始左移,直到发现大于等于 temp
的数,则将其挖出来填到 low
指针的地方并暂停,随后 low
指针又不断右移,直到发现小于 temp
的数,再将它挖出填到 high
指针处...... high
和 low
指针一直处于 交替相向移动 的状态。
如此下去,总有一刻 high
指针和 low
指针会指向 同一位置 。此刻无需再移动 high
和 low
指针,只需要把最初挖出来的 temp
值,放到这个坑内即可。
我们此时可以发现,原先的数组已经被分为了三部分:比 temp
小的数, temp
,比 temp
大(或等)的数组。
只需要再对Smaller和Greater区间进行递归操作,重复之前所述的步骤就可以了。
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); } } 复制代码
我们在进行一轮排序后(左右指针法,挖坑法,etc.)必定能将数组分割成以下形式: [Smaller[], temp, Greater[]] 。那能不能用更简单
偷懒
的方法来得到Smaller区间和Greater区间呢? 在Scala中,可以直接利用过滤器 filter
来过滤出比 temp
小(或大)的数。如:
arr.filter(x => x > temp) //filter处理之后得到的仍是Array[],放心食用。
而后再对过滤出来的Smaller[],和Greater[]继续进行递归即可。用Java的流处理同样可以实现类似逻辑,但是比较麻烦。
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)) ) } } 复制代码