java 对充满相等整数值的数组进行排序时出现堆栈溢出错误

ncgqoxb0  于 2023-04-04  发布在  Java
关注(0)|答案(2)|浏览(109)

我正在尝试对一个有100000个元素的数组进行排序,并且所有元素都是相等的。这是我的quickSort代码:

public static void quickSortFirst(int[] arr, int left, int right) {
    if (left < right) {
      int pivotIndex = partition(arr, left, right);
      quickSortFirst(arr, left, pivotIndex - 1);
      quickSortFirst(arr, pivotIndex + 1, right);
    }
  }

  private static int partition(int[] arr, int left, int right) {
    int pivot = arr[left];
    int i = left + 1;
    int j = right;
    while (i <= j) {
      while (i <= j && arr[i] <= pivot) {
        i++;
      }
      while (i <= j && arr[j] > pivot) {
        j--;
      }
      if (i <= j) {
        swap(arr, i, j);
      }
    }
    swap(arr, left, j);
    return j;
  }

  private static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }

它可以排序1000和10000个元素没有任何问题对接时,计数的元素上升,它给一个堆栈溢出.我尝试了很多代码,我发现在互联网上关于快速排序,但他们没有解决这个问题.每当我使用100000元素,我得到溢出

z31licg0

z31licg01#

使用这样的算法和你的数组值(都是相等的),条件arr[j] > pivot永远不会为真,j永远不会递减。
然后i..j段的分区将始终是i..(j-2),pivot和j。在递归过程中,堆栈将与数组大小成比例增长,从而触发堆栈溢出。
你可以做的一件事是在(i+j)/2+1附近设置一个阈值,当所有的arr[j]都相等时,将j减小到这个阈值。(我还没有用一个小数组检查极限条件)。这将使pivot大致位于表的中间,堆栈大小需要与数组大小的对数成比例。
注意,你仍然会有一个已经排序的数组的堆栈溢出!为了避免这样的事情,你应该在数组中随机获得一个枢轴数,而不是总是第一个项目。

kuuvgm7e

kuuvgm7e2#

您的stackoverflow错误可能来自两个可能的来源:
1.它可能是由无限递归引起的
1.可能是堆栈太小造成的
你的函数调用被存储在内存中的一个叫做the stack的部分。首先,让我们了解栈一般是如何工作的。
堆栈是项的集合(计算机科学中的数据),一个放在另一个的顶部,所以,这个数据结构中的最后一项必须是第一个离开它的项,简言之,它是一个LIFO(后进先出),这是合乎逻辑的,因为一般来说,如果结束符号在函数调用中不为真,则需要将两个新的函数调用添加到处理中,并且在它们的调用者之前对其进行评估。
堆栈至少支持以下操作:

  • push:向栈顶添加一个新项(当你递归调用同一个方法时,你正在做两次push)
  • pop:从栈顶移除一个元素并返回它的求值(函数执行完成并将其结果添加到调用者)
  • top:计算顶层元素,但不将其从堆栈中拉出

内存堆栈通过处理函数调用自动执行堆栈部分的逻辑。然而,如果问题是代码使用了太多内存,那么您需要将代码转换为迭代代码

https://www.tutorialspoint.com/difference-between-recursion-and-iteration
那么,如何将递归代码转换为迭代工作呢?基本上,你需要一个循环,该循环在堆栈不为空时运行,每当需要新项时,将两侧推入堆栈,并在循环的每一步弹出堆栈顶部。
Javarevisited给出了快速排序的迭代实现:

import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;

/**
 * Java Program to implement Iterative QuickSort Algorithm, without recursion.
 *
 * @author WINDOWS 8
 */
public class Sorting {

    public static void main(String args[]) {

        int[] unsorted = {34, 32, 43, 12, 11, 32, 22, 21, 32};
        System.out.println("Unsorted array : " + Arrays.toString(unsorted));

        iterativeQsort(unsorted);
        System.out.println("Sorted array : " + Arrays.toString(unsorted));
    }

    /*
     * iterative implementation of quicksort sorting algorithm.
     */
    public static void iterativeQsort(int[] numbers) {
        Stack stack = new Stack();
        stack.push(0);
        stack.push(numbers.length);

        while (!stack.isEmpty()) {
            int end = stack.pop();
            int start = stack.pop();
            if (end - start < 2) {
                continue;
            }
            int p = start + ((end - start) / 2);
            p = partition(numbers, p, start, end);

            stack.push(p + 1);
            stack.push(end);

            stack.push(start);
            stack.push(p);

        }
    }

    /*
     * Utility method to partition the array into smaller array, and
     * comparing numbers to rearrange them as per quicksort algorithm.
     */
    private static int partition(int[] input, int position, int start, int end) {
        int l = start;
        int h = end - 2;
        int piv = input[position];
        swap(input, position, end - 1);

        while (l < h) {
            if (input[l] < piv) {
                l++;
            } else if (input[h] >= piv) {
                h--;
            } else {
                swap(input, l, h);
            }
        }
        int idx = h;
        if (input[h] < piv) {
            idx++;
        }
        swap(input, end - 1, idx);
        return idx;
    }

    /**
     * Utility method to swap two numbers in given array
     *
     * @param arr - array on which swap will happen
     * @param i
     * @param j
     */
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

另一个可能的问题是,你最终得到了一个无限递归,它没有检测到算法实现了它的目的,并继续将函数调用推入堆栈,直到函数调用超出堆栈的限制。在这种情况下,你需要彻底检查递归的结束符号,看看是否一切都实现得很好,如果这是你的问题,我们知道调用树的高度是log2(n),如果n = 100000,那么这个高度是16.61,看起来并不深。

相关问题