我有一个Integer
[21, 9, 13, 47, 5, 10, 19, 36, 20, 11, 13]
的列表,我正在尝试编写一个递归函数,它将返回原始列表中的每个其他整数作为列表
(即{{1 }})。
我正在使用LispList的自定义实现。该对象称为 LispList ,它是不可变的并且(显然)未编入索引。它提供了以下方法:
E head() - 返回调用它的列表的第一项
LispList< E> tail() - 返回一个新列表,该列表除了调用它的列表的第一项外都包含
LispList< E> cons(E item) - 接受一个参数并返回一个新的列表,其头部是参数,其尾部是调用它的列表。
boolean isEmpty() - 如果调用它的列表是空列表,则返回true,否则返回false。
静态< T> LispList< T> empty() - 返回一个空列表。
经过几个小时的尝试后,我想出了一种方法,我使用一个初始化为2的计数器并使用它来跟踪偶数编号的元素,这些元素应该被挑出并放入一个新的LispList并返回。
但是,当我运行代码时,它会抛出NullPointerException而我看不清楚原因。也许我刚刚盯着屏幕看了太久!
这是从[21, 13, 5, 19, 20, 13]
调用的方法:
main
辅助方法:
public static <T> LispList<T> pickEveryOther(LispList<T> ls) {
int counter = 2;
LispList<T> ls1 = pickEveryOtherHelper(ls.tail(), counter);
return ls1;
}
非常感谢您的努力。
答案 0 :(得分:2)
这应该可以解决问题,只需抓住头部,然后尝试将尾巴拉两次并对其进行处理。只是说明它可以在每个尾部之后成为一个空列表。然后将头部添加到递归的结果中。
public static <T> LispList<T> everyOther(LispList<T> lispList) {
if (lispList.isEmpty()) {
return lispList.empty();
}
T head = lispList.head();
LispList<T> tail = lispList.tail();
if (!tail.isEmpty()) {
tail = tail.tail();
}
tail = everyOther(tail);
return tail.cons(head);
}
答案 1 :(得分:1)
解决方案是在每次递归时从列表中弹出2个值,并使用2个值之一构建新列表。
你没有真正说明“每隔一个”是指第1,第3,第5,......还是第2,第4,第6 ......,所以这里有两个解决方案。
public static <T> LispList<T> pickOdd(LispList<T> ls) {
if (ls.isEmpty())
return ls; // return empty
LispList<T> tail1 = ls.tail();
if (tail1.isEmpty())
return ls; // return of(ls.head())
LispList<T> tail2 = tail1.tail();
if (tail2.isEmpty())
return tail2.cons(ls.head()); // return of(ls.head())
return pickOdd(tail2).cons(ls.head());
}
public static <T> LispList<T> pickEven(LispList<T> ls) {
if (ls.isEmpty())
return ls; // return empty
LispList<T> tail1 = ls.tail();
if (tail1.isEmpty())
return tail1; // return empty
LispList<T> tail2 = tail1.tail();
if (tail2.isEmpty())
return tail1; // return of(ls.tail().head())
return pickEven(tail2).cons(tail1.head());
}
为了测试它,我确实实现了LispList
,有两个辅助方法(of(...)
和toString()
):
final class LispList<E> {
private final E head;
private final LispList<E> tail;
private LispList(E head, LispList<E> tail) {
this.head = head;
this.tail = tail;
}
/** returns the first item of the list it is called on */
public E head() {
if (isEmpty()) throw new IllegalStateException();
return this.head;
}
/** returns a new list consisting of all but the first item of the list it is called on */
public LispList<E> tail() {
if (isEmpty()) throw new IllegalStateException();
return this.tail;
}
/** takes an argument and returns a new list whose head is the argument and whose tail is the list it is called on */
public LispList<E> cons(E item) {
return new LispList<>(item, this);
}
/** returns true if the list it is called on is the empty list, returns false otherwise */
public boolean isEmpty() {
return this.tail == null;
}
/** returns an empty list */
public static <T> LispList<T> empty() {
return new LispList<>(null, null);
}
@SafeVarargs
public static <T> LispList<T> of(T ... values) {
LispList<T> ls = empty();
for (int i = values.length - 1; i >= 0; i--)
ls = ls.cons(values[i]);
return ls;
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner(", ", "[", "]");
for (LispList<E> ls = this; ! ls.isEmpty(); ls = ls.tail())
joiner.add(String.valueOf(ls.head()));
return joiner.toString();
}
}
<强> TEST 强>
LispList<Integer> ls = LispList.of(21, 9, 13, 47, 5, 10, 19, 36, 20, 11, 13);
System.out.println("List: " + ls);
System.out.println("Odd : " + pickOdd(ls));
System.out.println("Even: " + pickEven(ls));
<强>输出强>
List: [21, 9, 13, 47, 5, 10, 19, 36, 20, 11, 13]
Odd : [21, 13, 5, 19, 20, 13]
Even: [9, 47, 10, 36, 11]