快速分类分区:如何使“右枢轴”,“右优先”和其他变体有效

时间:2019-04-09 16:01:24

标签: java sorting quicksort

我是高中四年级APCS班的学生,正在为期中学习。 我的老师说下面是编码的最佳方法 “升序排序-选择右枢轴,然后在分区时先看左边/降序排序-选择左枢轴,当分区时,先看看右手”

起初我不明白为什么,所以我尝试了所有情况 我已经尝试了升序排序

(1)选择右枢轴/首先看向左

(2)选择右枢轴/首先看向右

(3)选择左枢轴/首先看向左

(4)选择左枢轴/首先看向右

但是我只有(1)类型可以工作。其余3个版本中存在一些逻辑错误。根据经验,我知道(2)〜(4)很难编码 通过经验并在纸上写下来,我知道如果我使用正确的轴心并首先看正确的东西,那么使用QuickSort的常规方法会出现问题。

总结:问题 [1](2)〜(4)比(1)难编码的确切原因是什么? [2]你们中任何一位出色的编码员都能帮助我完成(2)〜(4)

以下是适用于Java的版本(1)的代码

///* MOST SIMPLE VERSION OF QUICKSORT. ASCENDING, END PIVOT, LEFT FIRST 
SWEEP, LEFT & RIGHT COMPARISON
    public static void endPivSortV1(int[] a, int start, int end) {
        if(start < end) {
            int pVal = a[end];
            int left = start;
            int right = end; 
            //QUESTION: right = end - 1 

            while(true) {
                while(a[left] <= pVal && left < right) //left, 
                    left++;

                while(a[right] >= pVal && left < right)
                    right--;

                if(left == right)
                    break;

                swap(a, left, right);
            }
            swap(a, left, end);

            endPivSortV1(a, start, left - 1);
            endPivSortV1(a, left + 1, end);
        }   
    } //*/

我已经复制并粘贴了此代码,并对其进行了部分更改以创建版本(2)〜(4),但它们无法正常工作。

public static void endPivSortV2(int[] a, int start, int end) {
        if(start < end) {
            int pVal = a[end];
            int left = start - 1;
            int right = end + 1;

            while(true) {
                while(a[right--] >= pVal && left < right);

                while(a[left++] <= pVal && left < right);

                if(left == right)
                    break;

                swap(a, left, right);
            }
            swap(a, left, end);

            endPivSortV2(a, start, left - 1);
            endPivSortV2(a, left + 1, end);
        }   
    }

这是我尝试首先看右边而不是看左边的那个。 (而右移的那句话位于左移的那句的前面)我知道代码超级草率,充满了错误,但由于我在高中只写了一年的兼职书,所以让我有些懈怠...

谢谢。这是我在这里的第一篇文章,所以不要对我太刻苦:D

1 个答案:

答案 0 :(得分:0)

(1)和(4)本质上是相同的,您可以依靠扫描进入枢轴值作为停止循环的一种方式,而不必进行边界检查。对于(1),... <枢轴到达右侧的枢轴时将停止。对于(4),...>枢轴如果到达左侧的枢轴,则会停止。

(2)和(3)需要检查,以使扫描索引不会超出数组的范围,或者您可以通过将枢轴交换到数组的另一端并使用逻辑来“作弊”来自(1)或(4)。

注意-所有这些都是Lomuto分区方案的变体。还有Hoare分区方案,该方案通常选择中间值作为枢轴,并从左右扫描(两次扫描使用单独的索引)。当索引彼此交叉时,扫描停止。