Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 排序数组的快速排序堆栈溢出(适用于其他数据集)_Java_Algorithm_Data Structures_Stack Overflow_Quicksort - Fatal编程技术网

Java 排序数组的快速排序堆栈溢出(适用于其他数据集)

Java 排序数组的快速排序堆栈溢出(适用于其他数据集),java,algorithm,data-structures,stack-overflow,quicksort,Java,Algorithm,Data Structures,Stack Overflow,Quicksort,因此,我尽最大努力优化我的快速排序算法,使其尽可能高效地运行,即使是对于已排序或接近排序的数组,也可以使用三个值的中位数作为轴心,并对较小的分区大小使用插入排序。我已经对随机值的大数组测试了我的代码,它可以工作,但是当我传递一个已经排序的数组时,我得到了一个堆栈溢出错误(讽刺的是,它让我找到了这个网站)。我认为这是我的递归调用的一个问题(我知道分区至少适用于其他数据集),但我不太明白要更改什么 这是我第一学期数据结构课程的一部分,所以任何代码审查都会有所帮助。谢谢 public void qui

因此,我尽最大努力优化我的快速排序算法,使其尽可能高效地运行,即使是对于已排序或接近排序的数组,也可以使用三个值的中位数作为轴心,并对较小的分区大小使用插入排序。我已经对随机值的大数组测试了我的代码,它可以工作,但是当我传递一个已经排序的数组时,我得到了一个堆栈溢出错误(讽刺的是,它让我找到了这个网站)。我认为这是我的递归调用的一个问题(我知道分区至少适用于其他数据集),但我不太明白要更改什么

这是我第一学期数据结构课程的一部分,所以任何代码审查都会有所帮助。谢谢

public void quickSort(ArrayList<String> data, int firstIndex, int numberToSort) {
    if (firstIndex < (firstIndex + numberToSort - 1))
        if (numberToSort < 16) {
            insertionSort(data, firstIndex, numberToSort);
        } else {
            int pivot = partition(data, firstIndex, numberToSort);
            int leftSegmentSize = pivot - firstIndex;
            int rightSegmentSize = numberToSort - leftSegmentSize - 1;
            quickSort(data, firstIndex, leftSegmentSize);
            quickSort(data, pivot + 1, rightSegmentSize);
        }
}



public int partition(ArrayList<String> data, int firstIndex, int numberToPartition) {
    int tooBigNdx = firstIndex + 1;
    int tooSmallNdx = firstIndex + numberToPartition - 1;

    String string1 = data.get(firstIndex);
    String string2 = data.get((firstIndex + (numberToPartition - 1)) / 2);
    String string3 = data.get(firstIndex + numberToPartition - 1);
    ArrayList<String> randomStrings = new ArrayList<String>();
    randomStrings.add(string1);
    randomStrings.add(string2);
    randomStrings.add(string3);
    Collections.sort(randomStrings);
    String pivot = randomStrings.get(1);
    if (pivot == string2) {
        Collections.swap(data, firstIndex, (firstIndex + (numberToPartition - 1)) / 2);
    }
    if (pivot == string3) {
        Collections.swap(data, firstIndex, firstIndex + numberToPartition - 1);
    }
    while (tooBigNdx < tooSmallNdx) {
        while ((tooBigNdx < tooSmallNdx) && (data.get(tooBigNdx).compareTo(pivot) <= 0)) {
            tooBigNdx++;
        }
        while ((tooSmallNdx > firstIndex) && (data.get(tooSmallNdx).compareTo(pivot) > 0)) {
            tooSmallNdx--;
        }
        if (tooBigNdx < tooSmallNdx) {// swap
            Collections.swap(data, tooSmallNdx, tooBigNdx);
        }
    }
    if (pivot.compareTo(data.get(tooSmallNdx)) >= 0) {
        Collections.swap(data, firstIndex, tooSmallNdx);
        return tooSmallNdx;
    } else {
        return firstIndex;
    }
}
public void快速排序(ArrayList数据、int firstIndex、int numberToSort){
if(第一索引<(第一索引+数字排序-1))
if(numberToSort<16){
insertionSort(数据、第一个索引、numberToSort);
}否则{
int pivot=分区(数据、第一个索引、numberToSort);
int leftSegmentSize=pivot-firstIndex;
int rightSegmentSize=numberToSort-leftSegmentSize-1;
快速排序(数据、firstIndex、leftSegmentSize);
快速排序(数据,透视+1,右段大小);
}
}
公共int分区(ArrayList数据、int firstIndex、int numberToPartition){
int Toobingndx=firstIndex+1;
int Toosmalndx=firstIndex+numberToPartition-1;
字符串string1=data.get(firstIndex);
字符串string2=data.get((firstIndex+(numberToPartition-1))/2);
string3=data.get(firstIndex+numberToPartition-1);
ArrayList RandomString=新的ArrayList();
randomStrings.add(string1);
randomStrings.add(string2);
randomStrings.add(string3);
Collections.sort(随机字符串);
字符串轴=randomStrings.get(1);
if(pivot==string2){
swap(数据,firstIndex,(firstIndex+(numberToPartition-1))/2);
}
if(pivot==string3){
交换(数据,firstIndex,firstIndex+numberToPartition-1);
}
while(tooBigNdx0)){
Toosmalndx--;
}
if(tooBigNdx=0){
集合.swap(数据、firstIndex、tooSmallNdx);
返回smallndx;
}否则{
返回第一个索引;
}
}

在您的
分区
方法中,您有时会使用超出范围的元素:

String string1 = data.get(firstIndex);
String string2 = data.get((firstIndex + (numberToPartition - 1)) / 2);
String string3 = data.get(firstIndex + numberToPartition - 1);
(firstIndex+(numberToPartition-1))/2
不是中间元素的索引。这将是
(firstIndex+(firstIndex+(numberToPartition-1))/2

=firstIndex+((numberToPartition-1)/2)

事实上,如果
firstIndex>n/2
(其中
n
是输入中的元素数),则使用的元素的索引小于
firstIndex
。对于排序数组,这意味着您选择
firstIndex
处的元素作为透视元素。因此,您可以在中获得递归深度

ω(n)“>


这会导致足够大的输入出现堆栈溢出。

您可以避免堆栈溢出,而无需对算法进行太多更改。诀窍是对最大分区进行尾部调用优化,只对最小分区使用递归。这通常意味着您必须将
if
更改为
while
。我无法真正测试java代码,但它应该看起来像:

public void quickSort(ArrayList<String> data, int firstIndex, int numberToSort) {
    while (firstIndex < (firstIndex + numberToSort - 1))
        if (numberToSort < 16) {
            insertionSort(data, firstIndex, numberToSort);
        } else {
            int pivot = partition(data, firstIndex, numberToSort);
            int leftSegmentSize = pivot - firstIndex;
            int rightSegmentSize = numberToSort - leftSegmentSize - 1;

            //only use recursion for the smallest partition
            if (leftSegmentSize < rightSegmentSize) {
                quickSort(data, firstIndex, leftSegmentSize);
                firstIndex = pivot + 1;
                numberToSort = rightSegmentSize;
            } else {
                quickSort(data, pivot + 1, rightSegmentSize);
                numberToSort = leftSegmentSize;
            }
        }
}
public void快速排序(ArrayList数据、int firstIndex、int numberToSort){
而(firstIndex<(firstIndex+numberToSort-1))
if(numberToSort<16){
insertionSort(数据、第一个索引、numberToSort);
}否则{
int pivot=分区(数据、第一个索引、numberToSort);
int leftSegmentSize=pivot-firstIndex;
int rightSegmentSize=numberToSort-leftSegmentSize-1;
//仅对最小分区使用递归
如果(leftSegmentSize

这将确保调用堆栈大小最多为
O(log n)
,因为每次调用时,您只能对最多为
n/2
大小的数组使用递归。

谢谢!这完全有道理。我的代码现在可以正常工作了。如果您有时间,我还有一个问题。对于我的项目,我必须使算法尽可能高效。rand.nextInt()会吗为了找到三个随机值来为未排序的数据找到更好的中位数,有助于优化我的代码以获得n的大值?或者有没有更有效的方法来找到半精确的中位数?@NateSchellink:我个人更喜欢随机版本的quicksort,因为你无法得到最坏情况的输入。(最坏的情况仍然可能发生,但这取决于生成的随机数)。也不要再重新创建3元素
ArrayList
。如果不调用
sort
,也不难找到3的中间值,这将避免调用该方法的开销。感谢您的响应,我相信您在某些情况下是对的,这将阻止堆栈溢出,但我想要一个更优雅的解决方案开启。这将在所有情况下阻止堆栈溢出。这将为máximum调用堆栈大小设置理论上限。但我理解你的观点,实现中间值也降低了算法运行时的复杂性。