两个链接列表的总和

时间:2014-09-06 07:34:30

标签: java

一个类Nat表示一个数字(n),它具有指向n-1数字的前置字段,如果pre为null则表示该数字为零。

public class Nat { 

     private final Nat pre; 
     public Nat (Nat pre) { this.pre = pre; } 
     public Nat () { this(null); } 
     public boolean isZero () { return pre == null; } 
     public Nat succ () { return new Nat(this); } 

     … 
    }

我必须添加一个添加两个数字的方法,我不明白这假设如何返回一个代表“this”和其他的总和的Nat!

public Nat plus (Nat other) { 

 if (other.isZero()) 
 return this; 

 return succ().plus(other.pre); 
} 

我认为它创造了一个“Nats”,它始终指向这个(前)的第二个Nat。 有人可以帮帮我吗?

4 个答案:

答案 0 :(得分:4)

好吧,如果this代表nother代表m,那么计算n + m相当于计算{{1} +} + n+1,这正是m-1返回的内容。

在递归结束时,第一个数字到达succ().plus(other.pre),第二个数字到达n+m。这就是0为真时返回this的原因。

答案 1 :(得分:1)

您不会将数字直接存储在列表中并以递归方式创建:

  1. [null] - > 0
  2. [null - > Nat1(pre = null)] - > 1
  3. [null - > Nat1(pre = null) - > Nat2(pre = Nat1)] - > 2
  4. 为什么plus()有效:

    现在我们可以看到添加x+y可以更改为(x-1)+(y+1)等,直到0 + (y + x)。在您的代码中,您对添加本身并不感兴趣,但是您希望到达代表求和结果的Nat。您可以使用上述转换以递归方式执行此操作,直到other0 - 这是您的基本情况,它只计算递归调用并确保您执行x次。

    示例:

    [null -> Nat1(pre=null) -> Nat2(pre=Nat1) -> Nat3(pre=Nat2) -> Nat4(pre=Nat3) -> Nat5(pre=Nat5)]
    

    我们假设您要添加32。首先,您从other=Nat2开始,然后在Nat3上调用它,这样您就可以Nat3's获得Nat4后继,并使用plus()other's上调用Nat1前导plus(),仍然没有为零,因此您使用Nat4's前身Nat5呼叫Nat1's后继(null)上的this,您点击你的基础案例并返回Nat5,此时递归为{{1}}。

答案 2 :(得分:1)

  • 类似于尾递归

基本上它展开了等式

n + k = (n + 1) + (k - 1)

直到k为零。在这个过程中会创建很多临时Nats,但最终结果是Nat,其他Nat加数为零:你在第一个Nat中积累了结果。记下所有调用的算法的简单执行,你会看到它。

示例:1 + 2

1.plus(2)
-- 1.succ().plus(1)
---- 1.succ().succ().plus(0)
------> 1.succ().succ() == 3 
编辑:与其他帖子相反,我认为这是严格来说是递归递归。实际上,不会在同一对象实例上始终调用plus()方法。但这种行为确实是递归的。那么这取决于你的定义

答案 3 :(得分:0)

这种递归在功能语言中更容易理解。

我确信其他帖子足够明确plusa+b变为a+1+b-1)。

必须明确的是与此部分有关:

 public Nat (Nat pre) { this.pre = pre; } 
 ...
 public Nat succ () { return new Nat(this); } 

调用succ()时,它会返回一个新的Object,所以this来自此处:

 public Nat succ () { return new Nat(this); } 

将来自pre

 public Nat (Nat pre) { this.pre = pre; } 

这就是succ有效的原因,因为最后会有类似this.pre.pre....pre的内容。

为了更好地理解,您可以输入(最终在方法中添加一些打印行):

public static void main(String[] args) {
    System.out.println("==== A new number is 0 ====");
    Nat n1 = new Nat();                 // 0 
    System.out.println(n1.isZero());    // true
    Nat n2 = new Nat();                 // 0
    System.out.println(n2.isZero());    // true
    Nat sum = n1.plus(n2);              // 0
    System.out.println(sum.isZero());   // true
    System.out.println(n2.isZero());    // true
    System.out.println("==== Test succ and pre ====");
    Nat one = n1.succ();                // 1
    System.out.println(one.isZero());   // false
    Nat two = one.plus(one);            // 1 + 1
    System.out.println(two.isZero());   // false
    System.out.println(two.pre.isZero());       // false
    System.out.println(two.pre.pre.isZero());   // true
}