CS61B_lab02

题目描述:

dcatenate(IntList A, IntList B):返回一个由A的所有元素组成的列表,后面是B的所有元素。可能会修改A。Don't use 'new'。

复制代码
    public static IntList dcatenate(IntList A, IntList B) {
        if(A == null){
            return B;
        }
        IntList ptr = A;
        while(ptr.rest != null){
            ptr = ptr.rest;
        }
        ptr.rest = B;
        return A;
    }
复制代码

与其类似:

    public static void dSquareList(IntList L) {

        while (L != null) {
            L.first = L.first * L.first;
            L = L.rest;
        }
    }

 

这段代码定义了一个静态方法 `dSquareList`,它接受一个 `IntList` 类型的参数 `L`。该方法首先检查参数 `L` 是否为 `null`,如果不是,就将 `L.first` 的值替换为其自身的平方,然后将 `L` 指向下一个元素 `L.rest`。循环会一直执行,直到 `L` 变成 `null` 为止。

在主程序中,首先创建一个 `IntList` 类型的变量 `origL`,它包含三个整数元素 1、2 和 3。然后调用 `dSquareList` 方法,将 `origL` 作为参数传递给它。该方法会修改 `origL` 的元素值,将它们变成 1、4 和 9。因为 `origL` 是一个对象,而不是基本类型的值,所以在 `dSquareList` 方法中修改 `L` 的同时也修改了 `origL`。

需要注意的是,该方法没有返回值,而是直接修改了输入的参数 `L`。如果需要保留原始列表的副本,则需要在调用该方法之前先进行复制。

 

如果仅仅调用变量的值,如L.first ,L.rest,而不是修改原有的变量,如:this.rest = new IntList(this.first, this.rest),那么就不会对原有的变量进行修改。

如果是创建一个新的变量,并且将原有的变量赋值给新的变量,譬如 IntList ptr = A;那么对 ptr 这个新的变量操作就相当于对A操作,ptr就相当于一个指针。

复制代码
    public static IntList incrList(IntList L, int x) {
        /* Your code here. */
        if(L == null){
          return null;
        }
        IntList ls = new IntList(L.first + x, incrList(L.rest, x));
        return ls;
    }

    /** Returns an IntList identical to L, but with
      * each element incremented by x. Not allowed to use
      * the 'new' keyword. */
    public static IntList dincrList(IntList L, int x) {
        /* Your code here. */
        if(L == null){
          return null;
        }
        IntList ls = L;
        ls.first += x;
        ls.rest = dincrList(ls.rest, x);
        return L;
    }
复制代码

第一段代码就不会对原有的L进行改变,而第二段代码机会改变L。

 

复制代码
    public void addAdjacent(){
        if(this.rest == null){
            return;
        }
        IntList ptr = this;
        if(ptr.first == ptr.rest.first){
            ptr = new IntList(ptr.first * 2, ptr.rest.rest);
            ptr.addAdjacent();
        }else{
            ptr.rest.addAdjacent();
        }
    
    }
复制代码

根据这段代码,`addAdjacent()`方法在当前IntList实例上执行,并且通过递归方式遍历整个IntList链表。

代码的实现是,首先检查链表的长度是否大于1,如果不是,则不执行任何操作并立即返回。

否则,将当前节点指针`ptr`初始化为当前实例,然后检查`ptr`和`ptr.rest`的第一个元素是否相同。如果是,则将`ptr`重新赋值为一个新的IntList实例,其第一个元素为`ptr.first * 2`,第二个元素为`ptr.rest.rest`,然后调用`addAdjacent()`方法递归地处理剩余部分的链表。如果不是,则递归地调用`addAdjacent()`方法来处理下一个节点。

由于在递归调用中重新创建了一个新的IntList实例,并将其赋值给了`ptr`变量,因此在返回上一级递归时,当前节点的值并没有改变。因此,代码并没有改变原始链表的值。

要改变原始链表的值,需要在递归调用时对当前节点进行修改,而不是创建新的IntList实例并将其赋值给ptr变量。

复制代码
public void addAdjacent() {
    if (this.rest == null) {
        return;
    }

    if (this.first == this.rest.first) {
        this.first *= 2;
        this.rest = this.rest.rest;
        this.addAdjacent();
    } else {
        this.rest.addAdjacent();
    }
}
复制代码

 

一个值得一看的例子

复制代码
public class Pokemon {
public String name;
public int level;

public Pokemon(String name, int level) {
    this.name = name;
    this.level = level;
}

    public static void main(String[] args) {
        Pokemon p = new Pokemon("Pikachu", 17);
        int level = 100;
        change(p, level);
        System.out.println("Name: " + p.name + ", Level: " + p.level);
    }
    
    public static void change(Pokemon poke, int level) {
        poke.level = level;
        level = 50;
        poke = new Pokemon("Gengar", 1);
    }
}
复制代码

poke 只是指向了p, poke.level = level;这行代码是能够修改p的, 但是后来 poke = new Pokemon("Gengar", 1);就相当于让poke指向了另外一个对象,而这个不会更改p的值。且chage中的 level是main函数中的level 2进制编码的一个拷贝。相当于cpp的浅拷贝。

 

 

复制代码
 1 public static IntList square(IntList L) {
 2     if (L == null) {
 3         return null;
 4     }
 5     IntList newL = new IntList(L.first * L.first, null);
 6     IntList current = newL;
 7     IntList oldCurrent = L.rest;
 8     while (oldCurrent != null) {
 9         current.rest = new IntList(oldCurrent.first * oldCurrent.first, null);
10         oldCurrent = oldCurrent.rest;
11         current = current.rest;
12     }
13     return newL;
14 }
复制代码

与这段代码效果相同,都不会修改原有列表。只是第一段代码使用的是迭代,而第二段代码使用的是递归。

    public static IntList square(IntList L) {
        if(L == null){
            return L;
        }
        L = new IntList(L.first * L.first, L.rest);
        L.rest = square(L.rest);
        return L;
    }

而这段代码就会修改原有列表

复制代码
    public static IntList squareList(IntList L) {
        if(L == null){
            return L;
        }
        IntList new_L = new IntList(L.first, L.rest);
        IntList ptr = new_L;
        while(ptr != null){
            ptr.first *= ptr.first;
            ptr= ptr.rest;
        }
        return new_L;
    }
复制代码

第三段代码之所以会修改原始列表,是因为它在每个节点上直接修改该节点的值,而该节点是从原始列表中复制得来的。因此,当修改该节点的值时,原始列表中相应的节点的值也会被修改。这是因为Java中对象和数组的传递方式是引用传递,即传递的是对象或数组的引用(或指针),而不是对象或数组本身的值。因此,当一个方法对传递的对象或数组进行修改时,会直接修改原始对象或数组的值。

相比之下,第二段代码中创建了新的IntList节点,并将新节点作为修改后的列表的头返回。因此,它并没有直接修改原始列表,而是通过递归调用来构造新的列表。

posted @   哎呦_不想学习哟~  阅读(102)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示