Java 实现快速排序以对其内容具有受限/无访问权限的列表进行排序

Java 实现快速排序以对其内容具有受限/无访问权限的列表进行排序,java,algorithm,sorting,data-structures,quicksort,Java,Algorithm,Sorting,Data Structures,Quicksort,我试图实现快速排序算法,对不允许直接访问其元素的列表进行排序。我应该只使用两种方法对列表进行排序:swap和compare,而不使用仅用于调试目的的toString方法。我选择了子数组的中间元素作为轴心。使用函数调用期间传递的比较器对象进行比较 我使用随机生成的列表运行了一些JUnit测试,其中几乎所有列表都得到了排序(更新:在运行了更多的测试之后,我发现了更多算法失败的情况)。然而,(其中一种情况)当我尝试分区一个4元素子数组时,我的算法失败了,其中键按如下顺序排列:[最小、最大、大、小] 下

我试图实现快速排序算法,对不允许直接访问其元素的列表进行排序。我应该只使用两种方法对
列表进行排序:
swap
compare
,而不使用仅用于调试目的的
toString
方法。我选择了子数组的中间元素作为轴心。使用函数调用期间传递的
比较器
对象进行比较

我使用随机生成的列表运行了一些JUnit测试,其中几乎所有列表都得到了排序(更新:在运行了更多的测试之后,我发现了更多算法失败的情况)。然而,(其中一种情况)当我尝试
分区
一个4元素子数组时,我的算法失败了,其中键按如下顺序排列:[最小、最大、大、小]

下面是传递列表的JUnitTest-[0,3,2,1]:

private static final Comparator<Integer> INTEGER_COMPARATOR = new IntegerComparator();
@Test
public void customTest() {
    SwapList<Integer> customList;
    AbstractSorter<Integer> customSorter;
    customList = new ArrayBasedSwapList<Integer>(new Integer[] { 0, 3, 2, 1 });
    customSorter = new QuickSorter<Integer>(customList,
            INTEGER_COMPARATOR);
    SwapList<Integer> result = customSorter.sort();
    System.out.println("Result: " + result.toString());
    assertTrue(result.isSorted(INTEGER_COMPARATOR));
}
我放了一些println语句,并在代码中添加了一个
indent
变量以进行调试。以下是运行测试后的输出:

quicksort(0, 3)  
  Inside partition(0, 3)  
  pivotIndex = 1  
  Initially: [0, 3, 2, 1]  
  i = 1, pivotIndex = 1, j = 3  
  After 1st swap: [0, 1, 2, 3]  
  Pivot was swapped  
  i = 2, pivotIndex = 3, j = 2  
  After 2nd swap: [0, 1, 3, 2]  
  i = 2, pivotIndex = 3, j = 2  
  p = 2  
  quicksort(0, 1)  
    Inside partition(0, 1)  
    pivotIndex = 0  
    Initially: [0, 1, 3, 2]  
    i = 0, pivotIndex = 0, j = 0  
    After 2nd swap: [0, 1, 3, 2]  
    i = 0, pivotIndex = 0, j = 0  
    p = 0  
    quicksort(0, -1)  
    quicksort(1, 1)  
  quicksort(3, 3)  
结果:[0,1,3,2]

问题出在
分区(0,3)
中,其中第二个swap语句逆转了第一个swap的效果。有人能帮我修改一下快速排序算法吗?我可能应该添加一个
if
语句,这样第二次交换只在
pivotIndex
处的元素
I
>时发生

代码如下:

包裹分拣机;
导入java.util.Comparator;
导入结构.SwapList;
公共类QuickSorter扩展了AbstractSorter{
//字符串缩进=”;
公共快速排序器(SwapList、Comparator和Comparator){
超级(列表、比较);
}
@凌驾
公共交换列表排序(){
快速排序(0,list.size()-1);
退货清单;
}
私有void快速排序(int firstIndex,int lastIndex){
//System.out.println(缩进+快速排序(“+firstIndex+”,“+lastIndex+”);
//缩进+=“”;
如果(第一个索引<最后一个索引){
int p=分区(第一个索引,最后一个索引);
//System.out.println(缩进+“p=“+p”);
快速排序(第一索引,p-1);
快速排序(p+1,最新索引);
}
//缩进=缩进子串(2);
}
私有int分区(intfirstindex,intlastindex){
//System.out.println(indent+“内部分区(“+firstIndex+”,“+lastIndex+”));
int pivotIndex=(firstIndex+lastIndex)/2;
//System.out.println(缩进+“pivotIndex=“+pivotIndex”);
int i=第一索引;
int j=最新索引;
而(i=0&&i
附加代码:

private void quicksort(int firstIndex, int lastIndex) {
            //System.out.println(indent + "quicksort(" + firstIndex + ", " + lastIndex + ")");
            //indent+="  ";
            if(firstIndex < lastIndex) {
                int p = partition(firstIndex, lastIndex);
                //System.out.println(indent + "p = " + p);
                if (firstIndex < p - 1)
                    quicksort(firstIndex, p - 1);
                if (p < lastIndex)
                    quicksort(p, lastIndex);
            }
//            indent = indent.substring(2);
        }
private int partition(int firstIndex, int lastIndex) {
            //System.out.println(indent + "Inside partition(" + firstIndex + ", " + lastIndex + ")");
            int pivotIndex = (firstIndex + lastIndex) / 2;
            //System.out.println(indent + "pivotIndex = " + pivotIndex);
            int i = firstIndex;
            int j = lastIndex;
            while (i <= j) {
                while(list.compare(i, pivotIndex, comparator) < 0) {
                    i++;
                }
                while(list.compare(j, pivotIndex, comparator) > 0) {
                    j--;
                }
                //System.out.println(indent + "Initially: " + list.toString());
                //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j);
                if(i <= j) {
                    list.swap(i, j);
                    //System.out.println(indent + "After 1st swap: " + list.toString());
                    if(i == pivotIndex) {
                        pivotIndex = j;
                        //System.out.println(indent + "Pivot was swapped");
                    }
                    else if(j == pivotIndex) {
                        pivotIndex = i;
                        //System.out.println(indent + "Pivot was swapped");
                    }
                        i++;
                        j--;
                    //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j);
                }
            }
//            list.swap(pivotIndex, i);
            //System.out.println(indent + "After 2nd swap: " + list.toString());
            //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j);
            return i;
        }
package test;

import java.util.Comparator;
import java.util.Random;

public class Test
{

    private static final Comparator<Integer> INTEGER_COMPARATOR = new IntegerComparator();

    public static void main(String args[]) {
        SwapList<Integer> customList;
        AbstractSorter<Integer> customSorter;
        do {
            Random r = new Random();
            int length = r.nextInt(10);
            Integer[] test = new Integer[length];
            for(int j = 0; j < length; j++)
                test[j] = r.nextInt(10);
            customList = new ArrayBasedSwapList<Integer>(test);
            customSorter = new QuickSorter<Integer>(customList,
                    INTEGER_COMPARATOR);
            SwapList<Integer> result = customSorter.sort();
            if(!result.isSorted(INTEGER_COMPARATOR)) {
              System.out.println("Result: " + result.toString());
              System.out.println(result.isSorted(INTEGER_COMPARATOR));
            }
        } while(true);
    }

}
按照评论部分的要求-

超类
抽象分类器


我在
分区
方法中发现了三个错误或有争议的错误:

  • 该方法是
    private
    ,这意味着您没有对其进行单元测试,即使它是您所拥有的最复杂的代码片段之一。
    • 您可以通过将其包私有化(一些API,如Guava,提供了一个特殊的
      @VisibleForTesting
      注释,您可以使用它来明确为什么要这样做),或者通过将其分解为自己的类
      QuickSorter
      委托给它来解决这个问题

  • 您的算法假设
    i除了@ruakh指出的之外,我还观察到在调用
    partition()
    之后,pivot可以留在数组的任何部分。然而,由于pivot索引中的元素是确定排序的,所以它甚至可以位于
    列表的最末端
    ;有条件地调用
    quicksort()
    应该可以解决您的问题。另外,记住@ruakh的答案中已经强调的边缘案例,下面的代码应该可以解决您的所有问题。我已经对这个例程进行了无限次的测试,没有发现任何异常情况

    快速排序方法:

    private void quicksort(int firstIndex, int lastIndex) {
                //System.out.println(indent + "quicksort(" + firstIndex + ", " + lastIndex + ")");
                //indent+="  ";
                if(firstIndex < lastIndex) {
                    int p = partition(firstIndex, lastIndex);
                    //System.out.println(indent + "p = " + p);
                    if (firstIndex < p - 1)
                        quicksort(firstIndex, p - 1);
                    if (p < lastIndex)
                        quicksort(p, lastIndex);
                }
    //            indent = indent.substring(2);
            }
    
    private int partition(int firstIndex, int lastIndex) {
                //System.out.println(indent + "Inside partition(" + firstIndex + ", " + lastIndex + ")");
                int pivotIndex = (firstIndex + lastIndex) / 2;
                //System.out.println(indent + "pivotIndex = " + pivotIndex);
                int i = firstIndex;
                int j = lastIndex;
                while (i <= j) {
                    while(list.compare(i, pivotIndex, comparator) < 0) {
                        i++;
                    }
                    while(list.compare(j, pivotIndex, comparator) > 0) {
                        j--;
                    }
                    //System.out.println(indent + "Initially: " + list.toString());
                    //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j);
                    if(i <= j) {
                        list.swap(i, j);
                        //System.out.println(indent + "After 1st swap: " + list.toString());
                        if(i == pivotIndex) {
                            pivotIndex = j;
                            //System.out.println(indent + "Pivot was swapped");
                        }
                        else if(j == pivotIndex) {
                            pivotIndex = i;
                            //System.out.println(indent + "Pivot was swapped");
                        }
                            i++;
                            j--;
                        //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j);
                    }
                }
    //            list.swap(pivotIndex, i);
                //System.out.println(indent + "After 2nd swap: " + list.toString());
                //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j);
                return i;
            }
    
    package test;
    
    import java.util.Comparator;
    import java.util.Random;
    
    public class Test
    {
    
        private static final Comparator<Integer> INTEGER_COMPARATOR = new IntegerComparator();
    
        public static void main(String args[]) {
            SwapList<Integer> customList;
            AbstractSorter<Integer> customSorter;
            do {
                Random r = new Random();
                int length = r.nextInt(10);
                Integer[] test = new Integer[length];
                for(int j = 0; j < length; j++)
                    test[j] = r.nextInt(10);
                customList = new ArrayBasedSwapList<Integer>(test);
                customSorter = new QuickSorter<Integer>(customList,
                        INTEGER_COMPARATOR);
                SwapList<Integer> result = customSorter.sort();
                if(!result.isSorted(INTEGER_COMPARATOR)) {
                  System.out.println("Result: " + result.toString());
                  System.out.println(result.isSorted(INTEGER_COMPARATOR));
                }
            } while(true);
        }
    
    }
    
    private void快速排序(int firstIndex,int lastIndex){
    //System.out.println(缩进+快速排序(“+firstIndex+”,“+lastIndex+”);
    //缩进+=“”;
    如果(第一个索引<最后一个索引){
    int p=分区(第一个索引,最后一个索引);
    //System.out.println(缩进+“p=“+p”);
    如果(第一指数
    分区方法:private int partition(int firstIndex, int lastIndex) { //System.out.println(indent + "Inside partition(" + firstIndex + ", " + lastIndex + ")"); int pivotIndex = (firstIndex + lastIndex) / 2; //System.out.println(indent + "pivotIndex = " + pivotIndex); int i = firstIndex; int j = lastIndex; while (i <= j) { while(list.compare(i, pivotIndex, comparator) < 0) { i++; } while(list.compare(j, pivotIndex, comparator) > 0) { j--; } //System.out.println(indent + "Initially: " + list.toString()); //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j); if(i <= j) { list.swap(i, j); //System.out.println(indent + "After 1st swap: " + list.toString()); if(i == pivotIndex) { pivotIndex = j; //System.out.println(indent + "Pivot was swapped"); } else if(j == pivotIndex) { pivotIndex = i; //System.out.println(indent + "Pivot was swapped"); } i++; j--; //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j); } } // list.swap(pivotIndex, i); //System.out.println(indent + "After 2nd swap: " + list.toString()); //System.out.println(indent + "i = " + i +", pivotIndex = " + pivotIndex + ", j = " + j); return i; }
    package test;
    
    import java.util.Comparator;
    import java.util.Random;
    
    public class Test
    {
    
        private static final Comparator<Integer> INTEGER_COMPARATOR = new IntegerComparator();
    
        public static void main(String args[]) {
            SwapList<Integer> customList;
            AbstractSorter<Integer> customSorter;
            do {
                Random r = new Random();
                int length = r.nextInt(10);
                Integer[] test = new Integer[length];
                for(int j = 0; j < length; j++)
                    test[j] = r.nextInt(10);
                customList = new ArrayBasedSwapList<Integer>(test);
                customSorter = new QuickSorter<Integer>(customList,
                        INTEGER_COMPARATOR);
                SwapList<Integer> result = customSorter.sort();
                if(!result.isSorted(INTEGER_COMPARATOR)) {
                  System.out.println("Result: " + result.toString());
                  System.out.println(result.isSorted(INTEGER_COMPARATOR));
                }
            } while(true);
        }
    
    }