使用堆栈解决河内塔(java)

时间:2017-10-03 02:18:10

标签: java stack towers-of-hanoi

public static enum Action {
    No, LToM, MToL, MToR, RToM
}

public static int hanoiProblem2(int num, String left, String mid, String right) {
    Stack<Integer> lS = new Stack<Integer>();
    Stack<Integer> mS = new Stack<Integer>();
    Stack<Integer> rS = new Stack<Integer>();
    lS.push(Integer.MAX_VALUE);
    mS.push(Integer.MAX_VALUE);
    rS.push(Integer.MAX_VALUE);
    for (int i = num; i > 0; i--) {
        lS.push(i);
    }
    Action[] record = { Action.No };
    int step = 0;
    while (rS.size() != num + 1) {
        step += fStackTotStack(record, Action.MToL, Action.LToM, lS, mS, left, mid);
        step += fStackTotStack(record, Action.LToM, Action.MToL, mS, lS, mid, left);
        step += fStackTotStack(record, Action.RToM, Action.MToR, mS, rS, mid, right);
        step += fStackTotStack(record, Action.MToR, Action.RToM, rS, mS, right, mid);
    }
    return step;
}

public static int fStackTotStack(Action[] record, Action preNoAct,
                                 Action nowAct, Stack<Integer> fStack, Stack<Integer> tStack,
                                 String from, String to) {
    if (record[0] != preNoAct && fStack.peek() < tStack.peek()) {
        tStack.push(fStack.pop());
        System.out.println("Move " + tStack.peek() + " from " + from + " to " + to);
        record[0] = nowAct;
        return 1;
    }
    return 0;
}

public static void main(String[] args) {
    int num = 4;

    // solution 2
    int steps2 = hanoiProblem2(num, "left", "mid", "right");
    System.out.println("It will move " + steps2 + " steps.");
    System.out.println("===================================");

}

这是解决河内塔的代码。它使用三个堆栈来模拟3个塔。 我的问题是为什么它将记录变量定义为数组? Action [] record = {Action.No}; record [0] = nowAct;

我试图将它们改为 动作记录= Action.No; record = nowAct; 然后代码无法运行。

我不知道原因。如果有人能解释原因,我真的很感激。 感谢。

1 个答案:

答案 0 :(得分:0)

在您的示例中,record被定义为数组,因为它的值正在fStackTotStack方法中更改。

对此最简单的解释是因为Java通过 value 传递变量,而不是通过 reference 传递变量。它也按值传递Object引用。

例如,使用以下代码:

public void foo(int bar) {
  bar += 4;
  System.out.println("Foo's bar: " + bar);
}

public static void main(String[] args) {
  int bar = 5;
  new Foo().foo(bar);
  System.out.println("Main's bar: " + bar);
}

这将打印出来:

Foo's bar: 9 
Main's bar: 5

这是因为bar函数中的foo变量与main函数内的变量不同。只需在调用方法时复制该值。

传递数组时,变量本身仍然不同:

public void foo(int[] bar) {
  bar = new int[]{9};
  System.out.println("Foo's bar: " + bar[0]);
}

public static void main(String[] args) {
  int[] bar = {5};
  new Foo().foo(bar);
  System.out.println("Main's bar: " + bar[0]);
}

这将产生与以前相同的结果,因为foo的栏与主栏不同。

但是,Object引用按值传递。这意味着虽然变量不同,但它们所代表的值是相同的。因此:

public void foo(int[] bar) {
  bar[0] += 4;
  System.out.println("Foo's bar: " + bar[0]);
}

public static void main(String[] args) {
  int[] bar = {5};
  new Foo().foo(bar);
  System.out.println("Main's bar: " + bar[0]);
}

将打印出与以前不同的东西:

Foo's bar: 9 
Main's bar: 9

这是因为虽然foo的bar变量和主要bar变量是不同的变量,但它们指向相同的底层对象。因此,对象本身(而不仅仅是变量)的更改将持续存在。

在上面的示例中,行Action[] record = { Action.No };正在创建一个传递给fStackTotStack方法的数组。由于变量record本身没有被更改(任何地方都没有record = new Action[] {}),它指向的数组仍然是传递的数组。这意味着您可以对对象本身进行更改(在本例中为数组)。

Here is an article that can explain it better than I can.