【问题标题】:When to use ArrayList over array in recursion何时在递归中使用 ArrayList 而不是数组
【发布时间】:2011-04-22 09:19:35
【问题描述】:

所以我有这个问题。我试图编写一个程序来打印括号的所有有效可能排列,即我们可以有 3 个括号 ((()))、(()())、()()()、(())()等等

我有一个工作代码

public static void main(String[] args) {
    int number = 3; // No. of brackets
    int cn = number;
    int on = number;
    // open and closed brackets respectively
    char[] sol = new char[6];
    printSol(on, cn, sol, 0);
}

public static void printSol(int cn, int on, char[] sol, int k) {
    if (on == 0 && cn == 0) {
        System.out.println("");
        for (int i = 0; i < 6; i++) {
            System.out.print(sol[i]);
        }
    }

    else {
        if (on > 0) {
            if (cn > 0) {
                sol[k] = '(';
                printSol(on - 1, cn, sol, k + 1);
            }
        }

        if (cn > on) {
            sol[k] = ')';
            printSol(on, cn - 1, sol, k + 1);
        }
    }
}

现在的问题是我想使用 ArrayList 而不是 char 数组来执行此操作。 我尝试过,但出现错误。如果有人有任何建议,请告诉我。问这个问题的主要目的是我想知道在递归问题中我什么时候更喜欢 ArrayLists 而不是数组。

附: 我很抱歉缩进不佳,因为由于冲浪限制,我不得不输入整个程序,并且可能存在一些语法错误,但我已尽力而为。 谢谢 莫希特

【问题讨论】:

  • 感谢您为我缩进
  • 您在尝试 ArrayList 时遇到了哪些错误?知道这一点会更容易找到问题。
  • 请具体说明您遇到的错误 - 编译、运行时、测试失败还是...?一般来说,您的问题越详细、越准确,您获得的帮助就越大……

标签: java arrays recursion arraylist


【解决方案1】:

您希望避免在递归时按值传递大型数据结构,因为它会消耗大量内存。总的来说,这是我唯一能想到的。传递对数组或 ArrayList 的引用是可以的。一般来说,我更喜欢 ArrayList。

请查看 Java 的 Stack 类来解决这个问题。

【讨论】:

  • 好的,错误是我得到了错误的解决方案。使用 ArrayList 重写代码将花费大量时间。与数组不同,ArrayList 越来越长。我的递归步骤是在 sol 为 ArrayList sol ; 的每个步骤中调用 printSol(cn, on , sol)
  • Tony 我不想使用任何 API 并且想要获得低水平的知识。任何人都可以帮助我使用 ArrayList 解决这个问题吗?
  • +1,栈是正确的数据结构。但我不会使用Stack,这太糟糕了,是公认的大型库设计缺陷,应该慢慢死去。我会使用Deque(具体类型LinkedList)。
  • 您的问题似乎不仅仅是数组 vs arrayList ;-)
  • @unhillbilly:1) 正如你所说,它是同步的。 2)它使用继承而不是组合,这意味着你不能把它“当作一个堆栈”:它总是把 Vector 的方法当作包袱,这意味着人们可以对它做你不应该做的事情一个堆栈。相关,3)“堆栈”应该是接口的名称,这样您至少可以拥有一个仅用于堆栈操作的接口(类似于队列和双端队列)并具有不同的实现。 4) 虽然它没有被官方弃用,但 Javadoc 说不要使用它,而是使用 Deque
【解决方案2】:

我认为您使用char[] 做得很好。速度很快,很中肯。

我想说您在实践中遇到的大多数递归问题都没有遵循这种模式。这是因为通常在遇到需要递归的问题时,您会在搜索树上针对一个特定 目标(树上的一个特定叶节点)执行搜索。您正在执行迭代:您正在尝试访问树上的每个叶节点,并为每个叶节点执行一个操作。

使用常见的搜索算法(如深度优先搜索),您无需在递归时准备结果,而是在找到目标后放松时准备结果。

但对于您这样做的情况,char[] 效果很好。您基本上是通过参数solk 模拟堆栈(sol 保存数据,而 k 指向堆栈顶部)。正如其他人所注意到的,您可以直接使用堆栈(通过传递 Deque&lt;Character&gt; 实现,通常是 LinkedList)。

在我看来ArrayList 是倒退了一步。如果您要使用集合,请使用专为解决问题而设计的集合。

编辑:这是一个使用双端队列的未经测试的实现:

public static void printSol(int cn, int on, Deque<Character> sol) {
    if (on == 0 && cn == 0) {
        System.out.println("");
        for ( Iterator<Character> it = sol.descendingIterator(); it.hasNext(); ) {
            System.out.println(it.next());
        }
    }

    else {
        if (on > 0) {
            if (cn > 0) {
                sol.push('(');
                printSol(on - 1, cn, sol);
                sol.pop();
            }
        }

        if (cn > on) {
            sol.push(')');
            printSol(on, cn - 1, sol);
            sol.pop();
        }
    }
}

//...
printSol(3, 3, new ArrayDeque<Character>(6));

如您所见,变化很少。

编辑 2:对于这个特定问题,我们完全没有讨论过的一件事是StringBuilder

StringBuilder 是一种可变的 String 类型,可让您轻松添加和删除字符。这也是解决这个问题的好方法:

public static void printSol(int cn, int on, StringBuilder sol) {
    if (on == 0 && cn == 0) {
        System.out.println(sol);
    }

    else {
        if (on > 0) {
            if (cn > 0) {
                sol.append('(');
                printSol(on - 1, cn, sol);
                sol.deleteCharAt(sol.length()-1);
            }
        }

        if (cn > on) {
            sol.append(')');
            printSol(on, cn - 1, sol);
            sol.deleteCharAt(sol.length()-1);
        }
    }
}

【讨论】:

  • 感谢您的回复。在您回复的上下文中,让我们解决一个问题,我需要在树中找到所有可能的路径(从根到叶)。这是一个与我发布的一个类似的递归问题,我想使用一个数组并将其用作堆栈。我接受 char[] 作为解决方案没有问题,但问题是我无法理解何时在递归中使用 ArrayList。我是 Java 新手。
  • @peloooo:我会说 ArrayList 在递归中的用途非常非常少。曾经。在这个例子中绝对不是。大多数时候,当您“构建路径”到叶节点时,您需要一个堆栈。栈有两种主要的实现方式:一个只保存头节点的链表,或者一个保存指向栈顶指针的数组。如果你想在没有类的情况下实现它,你做得很好。但是如果你想使用一个集合类,这两个实现分别由LinkedListArrayDeque表示。
  • 使用数组的好处是,使用堆栈,您必须转到中间数据结构来构建结果(例如,要按顺序打印它们,您必须弹出它们首先放到另一个堆栈上以颠倒顺序)。但是 Deque 的美妙之处在于,你可以在最后切换为使用它作为队列,并使用Deque.iterator() 以 FIFO 顺序获取它们。
  • 马克,我是 java 新手,在使用 API 时特别固执(我的弱点)。你能用一段代码详细说明一下吗?
  • 嘿,感谢 Mark 的解决方案,但 FIFO 输出只会为我们的案例提供反向解决方案 ;-)。休息很好。
【解决方案3】:

我意识到没有人(包括我自己)真正回答了您的问题。我认为您已经确信在这里使用ArrayList 是不可取的。但是如何让它发挥作用呢?

最简单的方法基本上是用它来伪造一个堆栈:

public static void printSol(int cn, int on, ArrayList<Character> sol) {
   //...
   sol.add('(');
   printSol(on - 1, cn, sol);
   sol.remove(sol.size() - 1);

【讨论】:

    猜你喜欢
    • 2010-09-24
    • 2010-09-29
    相关资源
    最近更新 更多