【问题标题】:What is the cause of this stack overflow?这个堆栈溢出的原因是什么?
【发布时间】:2011-12-13 20:40:33
【问题描述】:

我正在为一个使用StringBuilder 生成字符串的所有排列的Android 应用程序用Java 编写一个函数。

每当函数运行时,程序都会立即终止,并且 DDMS(Dalvic 虚拟机调试工具)在我的函数中声明堆栈溢出。

private void reorder(String reorder_this, StringBuilder in_this){

    for(int i = 0; i < reorder_this.length(); i++)
    {
        if(i == reorder_this.length())
        {
            in_this.append(System.getProperty("line.separator"));
        }
        else
        {
            in_this.append(reorder_this.charAt(i));
            reorder(reorder_this.substring(0, i) + reorder_this.substring(i), in_this);
        }
    }
}

您可以看到我对这个问题采用了递归方法,我相信这最终会用输入字符串的所有可能排列填充字符串构建器,每个排列后跟换行符。

有人知道什么可能导致堆栈溢出吗?

【问题讨论】:

  • 您是否使用小字符串(如“ABC”)跟踪执行情况? (我的意思是“用手”追踪,或者在紧要关头,记录……但“玩电脑”真的很有帮助。)
  • 我在嵌套的 for 循环中找到了一个更有效的解决方案。我最近一直在使用方案,并且一直停留在递归范式中。
  • 非尾递归函数通常效率较低;递归经常因为它的通信方式而发光,而不一定是它的执行方式。

标签: java android recursion stack-overflow


【解决方案1】:

简而言之,除非您的字符串长度为 0,否则您的函数无法终止。

您的方法首先将i 设置为0,并测试i 是否小于第一个参数的长度。如果是(除了空字符串之外的所有字符串都是这种情况),您将立即递归,因为您不能严格小于长度并且等于长度。在您的递归调用中,您传入一个长度完全相同的字符串(实际上,正如 Thilo 指出的那样,完全相同的字符串)。这表明该算法的第二个问题:递归算法应该对每个递归调用的“较小”参数进行操作。

很快就能在此处获得StackOverflowException。每个递归调用都会推送一个新的堆栈帧。

【讨论】:

  • 没错,reorder_this.substring(0, i) + reorder_this.substring(i) 将再次与 reorder_this 相同。
  • 在那种情况下甚至没有达到。 0 永远不会
  • @EJP,我认为我的主张是正确的,因为该方法只有在 for 循环完成时才能终止。这就是我所说的“基本情况”,尽管我的术语可能令人困惑,因为很容易将“基本情况”作为 if 子句的内容。因为 OP 在 for 循环中前进之前递归,所以永远不会达到 完成循环的“基本情况”除非原始字符串为空。所以是的,正如我相信你所指出的那样,永远不会达到 if 语句的真实部分。但是那个真实的部分不是我所说的基本情况,因为它是在一个循环中。
  • 啊,我明白了。我的问题源于我对 substring 函数的误解。看起来它的第二个参数实际上表示指定索引之前的索引。
  • @Ray Toal 这是基本情况,因为它是不递归的。循环与它无关。
【解决方案2】:

Java 中任何堆栈溢出的原因都是无限递归。

private void reorder(String reorder_this, StringBuilder in_this){
    for(int i = 0; i < reorder_this.length(); i++)
    {
        if(i == reorder_this.length())
        {

这个块是不可到达的,通过构造。所以你的终止条件永远不会满足。

【讨论】:

    【解决方案3】:

    我认为问题出在这一行:

    reorder(reorder_this.substring(0, i) + reorder_this.substring(i), in_this);
    

    reorder_this.substring(0, i) + reorder_this.substring(i) 将产生一个等同于reorder-this 的字符串

    【讨论】:

      猜你喜欢
      • 2012-08-31
      • 2010-11-01
      • 1970-01-01
      • 2010-11-09
      • 2015-06-02
      • 1970-01-01
      • 2010-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多