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节点,并将新节点作为修改后的列表的头返回。因此,它并没有直接修改原始列表,而是通过递归调用来构造新的列表。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)