递归 - 导致堆栈溢出的原因

Recursion - What's causing stack overflow

提问人:stupidmoron 提问时间:10/10/2022 更新时间:10/10/2022 访问量:44

问:

我正在使用 2D 数组作为分配进行存储桶排序。我的 BucketSort 类中的最后一个方法是递归的。对于每个递归调用,我都会通过将其除以 10 来递减用于确定基本情况的变量。我需要一双新的眼睛来看待我看不见的东西。我的代码如下:

import java.util.Arrays;
import java.util.Random;

public class BucketSort {
    
    //Random rand = new Random();
    //int length = 3 + rand.nextInt(10);
    int[] array = {97, 100, 3};
    int[][] buckets = new int[10][array.length - 1];
    int col = 0;
    int row = 0;
    boolean occupied = false;
    int max = 0;
    int maxDigits = 1;
    
    public BucketSort() { // constructor
        for (int i = 0; i < array.length; i++) {  // for each array element
            //array[i] = rand.nextInt(1000);
            System.out.print(array[i] + " ");
            if (array[i] > max)  // if current array element is greater than max
                max = array[i];  // set the new max
            System.out.println("\nMax is: " + max);
        }
        // get the number of digits in the largest number (max) in the array 
        int largest = max;  // largest is a temp var initialized to the value of max.  I'm using it in calculations because I don't wanna destroy max
        while (largest / 10 > 0) { // the largest number in the array is more than one digit
            maxDigits++;  // add 1 to maxDigits
            largest /= 10; // divide largest by 10 
            System.out.println("maxdigits is: " + maxDigits);
            System.out.println("Largest is: " + largest);
        }
    }
    
    public void distribPass() {
        // distribution pass
        for (int i = 0; i < array.length; i++) {  // for each array element
            row = array[i] % 10;  // get the ones place
            if (buckets[row][col] == 0) { // if bucket is not occupied
                buckets[row][col] = array[i];  // store the array element in bucket
            }
            else {
                occupied = true;  // bucket is occupied
                while (occupied && (col < array.length - 1)) {  // bucket is occupied
                    col++;  // move to the next column
                    if (buckets[row][col] == 0 ){  // the bucket in the new column is not occupied
                        buckets[row][col] = array[i];  // store the array element in the bucket
                        occupied = false;  // set occupied to false
                    } // end if
                } // end while
            } // end else
            
        } // end for
        
        for (row = 0; row < buckets.length; row++) {  // for each row in buckets
            //System.out.println("row: " + row + "\n");
            System.out.println();
            for (col = 0; col < buckets[row].length; col++) {  // for each column in current row
                System.out.print(buckets[row][col] + "\t");  // print contents of the current bucket
            }
        }
    } // end distribPass
    
    public void gatherPass() {
        int index = 0;  // reset the array index to 0
        System.out.println("Gathering Pass");
        for (row = 0; row < buckets.length; row++) {  // for each row in buckets
            for (col = 0; col < buckets[row].length; col++) {  // for each column of current row
                if (buckets[row][col] != 0) {  // there's a number in the current bucket
                    array[index] = buckets[row][col];  // copy the number from the bucket back into the array
                    System.out.println(array[index]);
                    index++;  // move to the next position in the array
                    buckets[row][col] = 0;  // reset current bucket to 0
                }
            }
        }
    }
    
    public void sort() {
        // tens digit, hundreds digit, etc.
        row = 0;
        col = 0;
        System.out.println("Testing the sort method");
        for (int i = 0; i < array.length; i++) {  // for each array element
            for (int digit = 2; digit <= maxDigits; digit++) {  // for each digit of the current array element
                row = getPlace(array[i], digit - 1);  // get the proper bucket row to store the current array element in
                System.out.println("Digit is: " + digit + " Place is " + row);
            }
            // do another distribution pass
            if (buckets[row][col] == 0) {  // current bucket is not occupied
                buckets[row][col] = array[i];  // store the current array item in the current bucket
            }
            else {  // current bucket is occupied
                occupied = true;  // set occupied to true
                while (occupied && (col < array.length - 1)) {
                    col++;  // move to the next column
                    if (buckets[row][col] == 0) {  // if current bucket is not occupied
                        buckets[row][col] = array[i];  // store the current array item in the current bucket
                        occupied = false;  // set occupied to false
                    }
                }
            }
        }
        gatherPass();
    }
    
    public int getPlace(int num, int exp) {
        int intPlace;
        double doublePlace;
        if (num >= Math.pow(10, exp) && num < Math.pow(10, exp + 1)) {  // for example, to check if a number is between 10 and 100
            // base case
            doublePlace = num / Math.pow(10, exp);
            intPlace = (int) doublePlace;
            return intPlace;
        }   
        else
            return getPlace(num / 10, exp);  // recursive call
    }
        
}
public class BucketSortTest {
    public static void main(String[] args) {
        BucketSort screwup = new BucketSort();
        screwup.distribPass();
        screwup.gatherPass();
        screwup.sort();
    }
}
Java 递归

评论

4赞 Bradley Thomas 10/10/2022
在条件退出递归的预期位置之前放置一个断点,逐步执行并检查变量以找出为什么不这样做。

答:

0赞 SRJ 10/10/2022 #1

您的程序具有以下方法getPlace

public int getPlace(int num, int exp) {
        int intPlace;
        double doublePlace;
        if (num >= Math.pow(10, exp) && num < Math.pow(10, exp + 1)) {  // for example, to check if a number is between 10 and 100
            // base case
            doublePlace = num / Math.pow(10, exp);
            intPlace = (int) doublePlace;
            return intPlace;
        }
        else
            return getPlace(num / 10, exp);  // recursive call
    }

我查看了您的代码,当它被调用时,它在一次传递中很好,但在 num become 和 exp become 的第二遍中,这会导致无限递归并且永远不会进入基本条件并导致 .num value 3exp value 1getPlace01stackoverflow exception

因此,您必须在基本情况下处理这种情况以终止 .infinite recursion

评论

0赞 stupidmoron 10/10/2022
我解决了递归问题,但我尝试使用另一个数据数组运行程序,结果顺序错误。在上面的程序中,我使用了 [97, 100, 3]。新数据为 [97, 100, 3, 12475, 1500, 90]。它的顺序是 [100, 1500, 90, 3. 97, 12475]。我一直在看着这个,直到我脸色发青。任何帮助将不胜感激。
0赞 SRJ 10/10/2022
有关存储桶排序的实现,请参阅资源。这可能有助于快速找到代码中的错误。