我有这段代码:
static int countStu = 0;
public static int countStudent(Node<Student> lst) {
// pre : true
// post : res = number of students in list
if (lst != null) {
countStu++;
countStudent(lst.getNext());
}
return countStu;
}
这种方法存在的问题是我必须在countStu
方法之外声明countStudent()
,这在我想要两次调用countStudent()
的情况下效果不佳,它会使返回价值翻倍。如何解决此问题并能够无限次地调用countStudent()
并获得正确的结果?
答案 0 :(得分:5)
代替return((lst == null)? 0 : (1 + countStudent(lst.getNext())))
。
答案 1 :(得分:1)
变化:
if(lst!=null){
countStu++;
countStudent(lst.getNext());
}
return countStu;
到
return lst==null ? 0 : (1+countStudent(lst.getNext()));
答案 2 :(得分:0)
假设这是你的功课,你真的必须在外面声明countStu
(你不应该在任何正常的代码中),你可以简单地将值包装在某个类中。添加set + get访问器并将该对象作为第二个参数传递给该函数。然后使用它,而不是全局/静态变量。
或者根本不使用变量并返回结果+ 1.不确定规则是否允许这样做。
答案 3 :(得分:0)
通常,当您尝试执行类似的操作时,尝试以某种方式删除显式状态处理。
例如,如果你必须计算函数f(x)= G(f(x-1)),你可以将G表示为无状态方法,并遵循以下模式:
public static ResultType G(ResultType input) {
// compute G stateless
}
public static ResultType F(int x) {
return G(F(x - 1));
}
这样你就不会有像现有代码那样的副作用。与您现在正在进行的操作相比,缺点通常较小(整体使用相同的堆栈深度)。
重要的是确保G和F实现是无状态的(不使用在方法体范围之外声明的变量)。
答案 4 :(得分:0)
在静态字段中保持递归状态不是线程安全的。而是将值保存在堆栈中。
我给你一个递归的例子,这个例子可能会导致StackOverflowError冒险,只有6k节点的默认堆以及不受此影响的循环版本。
public class SO3765757 {
public static int countNodeRecursive(Node<?> node) {
if(node == null) {
debug("node is null");
return 0;
}
int count = 1 + countNodeRecursive(node.getNext());
debug(count + " = " + node.toString());
return count;
}
public static int countNodeLoop(Node<?> node) {
int count = 0;
for(Node<?> currentNode = node; currentNode != null; currentNode = currentNode.getNext()) {
count += 1;
debug(count + " = " + currentNode.toString());
}
return count;
}
public static void main(String[] args) {
int count = 10;
if(args.length > 0) {
try {
count = Integer.parseInt(args[0]);
} catch(NumberFormatException e) {
}
}
Node<Student> node = getNodeTest(count);
System.out.println("Loop count = " + countNodeLoop(node));
try {
System.out.println("Recursive count = " + countNodeRecursive(node));
} catch(StackOverflowError e) {
System.out.println("Recursive count caused " + e.getClass().getName());
}
}
private static void debug(String msg) {
System.out.println("DEBUG:" + msg);
}
private static <T> Node<T> getNodeTest(int count) {
Node<T> prevNode = null;
for(int i=0;i<count;i++) {
Node<T> node;
if(prevNode == null) {
node = new NodeImpl<T>();
} else {
node = new NodeImpl<T>(prevNode);
}
prevNode = node;
}
return prevNode;
}
private static interface Node<T> {
Node<T> getNext();
}
private static class NodeImpl<T> implements Node<T> {
private final Node<T> next;
public NodeImpl() {
this.next = null;
}
public NodeImpl(Node<T> next) {
this.next = next;
}
public Node<T> getNext() {
return next;
}
}
private static interface Student {
}
}
答案 5 :(得分:0)
countStudent(lst.getNext());
如果lst.getNext()为null,为什么我需要再次调用它。在调用递归之前进行预计算,有不同的类型。当你从main方法调用这个方法countStudent时,在递归开始之前检查lst值是否为null。
public static int countStudent(Node lst){
countStu++; Node<Student> _tmp; _tmp = lst.getNext(); if (_tmp != null ) countStudent(lst.getNext()); return countStu; }