解决这个问题的最好方法是画一些图片。然后尝试将问题分解为子问题。让我们从简单的情况开始:长度为 2 的列表:
ListItem two = new ListItem(1, ListItem(2, null));
这是一张照片
two = ( number == 1
( next == ( number == 2
( next == null
这是另一张照片:
+---+ +---+ 这里的“/”是上面的“null”,它终止了列表。
| 1 |->| 2 |-/
+---+ +---+
这样想:一个列表由第一个 ListItem 组成,它通过“next”指向列表的其余部分。空列表则为空,最后一个 ListItem 的“下一个”始终为空。 (空)。
现在,当我们被要求“拉伸”一个列表时,到底发生了什么?比方说,到 2 点?
好吧,空列表很简单,它不会改变。但这也无关紧要,因为null.stretch() 将以您正在使用的语言结尾。那么长度为 1 的列表就是我们最简单的实际案例:
我们有:
我们有我们想要的
+---+ +---+ +---+
| 1 |-/ | 1 |-->| 1 |-/
+---- +---+ +---+
好的,这并不难。我们已经有了一个长度为 1 的列表。我们需要做的就是把它挂在一个新的 ListItem 的下一个上,我们将得到一个长度为 2 的列表。显然,我们需要能够将某些内容添加到现有列表中。将它添加到前面是最简单的,因此我们将为此定义一个小助手:
ListItem addItemToFront(int number) {
return new ListItem(number, this);
}
好的,现在让我们编写代码并将其命名为stretchFirstItemByOne:
ListItem stretchFirstItemByOne() {
return this.addItemToFront(this.number);
}
你会看到我在这些例子中经常使用 this.something(),
虽然没有必要。我只是想清楚
这些是对当前对象 (this) 的方法调用。
但是,假设我们想要拉伸更大的 n?您已经尝试过——有点不幸——使用上面的 for 循环。你可以这样做。但我会用不同的方式来做。
ListItem stretchFirstItem(n) {
if (n == 1) // stretching to length 1 means nothing
return this; // to do. just return this.
else {
// well, if we stretch our item to length n-1 first
// then all we have to do is stretch it by one and
// we're done.
return this.stretchFirstItem(n-1).stretchFirstItemByOne();
}
}
停下来想想那个。如果遇到问题,请将其重写为 for 循环。
这一切都很好,你可能会说,但它只处理长度为 1 的列表。多么真实,多么真实。
假设您有一个长度为 3 的列表,并且您想将其拉伸 2。
+---+ +---+ +---+
( | 1 |->| 2 |->| 3 |-/ ).stretch(2)
+---+ +---+ +---+
难吗?好吧,我们至少可以开始了。如果列表只有一项,我们知道如何处理:
ListItem stretch(int n) {
ListItem restOfList = this.next;
if (restOfList == null) { // this list has length one
return this.stretchFirstItem(n);
} else {
// if we had the rest of the list stretched, then we could
// add this.number to the front of this stretched list, stretch
// that first item and then we'd be done.
}
}
嘿,但 stretch 不应该为我们这样做吗,你知道,拉伸整个列表吗?难道我们不能用它来拉伸列表的其余部分,这样我们就可以做简单的事情并拉伸第一项吗?但是我们甚至还没有写完拉伸——我的意思是——它不起作用。不可能那么容易,不是吗?可以吗?
ListItem stretch(int n) {
ListItem restOfList = this.next;
if (restOfList == null) { // this list has length one
return this.stretchFirstItem(n);
} else {
return restOfList //-------------------------
.magic(...) // Left as an exercise for
.moreMagic(...) // the reader.
.zyzzy(...); //-------------------------
}
}