繁体   English   中英

Java 快速排序算法中的 StackOverFlowError

[英]Java StackOverFlowError in QuickSort Algorithm

每当我用超过 6500 个元素测试我的快速排序算法时,都会出现堆栈溢出错误。 我怎样才能优化我的算法,这样我就不会得到这个错误? 作为要求的一部分,如果分区大小小于 MIN_SIZE,我的代码必须进行插入排序。

public static <T extends Comparable<? super T>>
       void quickSort(T[] array, int first, int last)
    {
        if (last - first + 1 < MIN_SIZE)
        {
            insertionSort(array, first, last);
        }
        else {
            if (first < last)
            {
                // create the partition: Smaller | Pivot | Larger
                int pivotIndex = partition(array, first, last);
              
                // sort subarrays Smaller and Larger
                quickSort(array, first, pivotIndex-1);
                quickSort(array, pivotIndex+1, last);
            } // end if
        }
    }  // end quickSort

下面是对数组进行分区的代码:

private static <T extends Comparable<? super T>>
            int partition(T[] a, int first, int last)
        {
            int pivotIndex = last;  // simply pick pivot as rightmost element
            T pivot = a[pivotIndex];
        
            // determine subarrays Smaller = a[first..endSmaller]
            //                 and Larger  = a[endSmaller+1..last-1]
            // such that elements in Smaller are <= pivot and 
            // elements in Larger are >= pivot; initially, these subarrays are empty
        
            int indexFromLeft = first; 
            int indexFromRight = last - 1; 
        
            boolean done = false;
            while (!done)
            {
                // starting at beginning of array, leave elements that are < pivot; 
                // locate first element that is >= pivot
                while (a[indexFromLeft].compareTo(pivot) < 0)
                    indexFromLeft++;
        
                // starting at end of array, leave elements that are > pivot; 
                // locate first element that is <= pivot
        
                while (a[indexFromRight].compareTo(pivot) > 0 && indexFromRight > first)
                    indexFromRight--;
        
                // Assertion: a[indexFromLeft] >= pivot and 
                //            a[indexFromRight] <= pivot.
        
                if (indexFromLeft < indexFromRight)
                {
                    swap(a, indexFromLeft, indexFromRight);
                    indexFromLeft++;
                    indexFromRight--;
                }
                else 
                    done = true;
            } // end while
        
            // place pivot between Smaller and Larger subarrays
            swap(a, pivotIndex, indexFromLeft);
            pivotIndex = indexFromLeft;
        
            // Assertion:
            // Smaller = a[first..pivotIndex-1]
            // Pivot = a[pivotIndex]
            // Larger  = a[pivotIndex + 1..last]
        
            return pivotIndex; 
        }  // end partition

您的答案确实很缺乏,因为您应该发布所有代码(至少 MIN_SIZE、insertionSort、quickSort、swap 缺少定义)。 如果您发布错误的堆栈跟踪也会有很大帮助,即多行错误 output 告诉我们异常发生在哪个 class 以及在什么方法和行中。 请参阅https://stackoverflow.com/help/how-to-ask

但是你遇到的问题是相当基本的,所以我在这里给出一个基本的解释:

关于一般程序如何工作的简短基础知识,以及导致StackOverflowError的原因:

  • 堆栈是 CPU 的所有操作按顺序排列的地方,但您可以添加更多元素(接下来执行此操作)或删除元素(已完成此操作,不再需要它)
  • 对于您调用的每个方法,都会在堆栈顶部放置一个新的堆栈帧。 这包含跳转信息,通常返回值和参数,
    • 因此您可以将信息从调用方法传递给被调用方法
    • 所以当被调用的方法完成后,你就知道要跳回哪里,恢复之前的方法
  • 如果调用太多方法,堆栈将变得太大而无法放入 RAM(现实生活中的限制要严重得多),因此您无法调用后续方法,因此调用失败。
    • 现在这对于递归方法尤其如此,因为它们与“普通”方法的主要区别是一遍又一遍地调用自己(sort() 调用 sort() 调用 sort() 等)。
    • 还有较少直接的方法“递归”循环,其中a() 调用 b()然后b() 调用 c()c() 调用 a()a() 调用 b()

所以问题是在你的代码中,可能是 sort() 方法,调用自身(直接或通过其他方法),这最终导致错误。

当该方法在没有/之前调用自身的情况下return时检查停止条件。 那个条件可能有问题。

基于快速浏览,我在 function 中看不到任何会使堆栈帧过大的东西。 然而,递归 function 总是有一个限制,因为每次调用都使用堆栈(局部变量加上 function 参数)。

达到 6500 的限制似乎很奇怪,因为完美平衡的树应该只接受(log base 2)调用(大约 12 或 13),除非您的列表已经排序 - 在这种情况下快速排序是出了名的糟糕,并且可能然后拨打6500电话。

如果这是一个练习,请尝试选择一个随机的 pivot,这应该会给你更好的平衡。 如果您正在寻找实际的排序,请尝试使用较少递归的方法,例如合并排序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM