递归函数的终止条件是必须的吗?哪怕它没用

来源:2-8 作业解析:链表的递归实现

52726814

2023-10-12 06:25:41

    // 在以dummyHead为头结点的链表的index位置插入元素e,递归算法
public void addAt(int index, T element){
      if(index < 0 || index > size){
            throw new IllegalArgumentException("Add failed. Illgegal index");
      }
      addAtHelper(dummyHead, -1, index, element);
}

private void addAtHelper(Node node, int currIndex, int index, T element){
      if(node == null){
            return;
      }

      if(currIndex < index - 1){
            addAtHelper(node.next, currIndex+1, index, element);
      }else{
            Node rear = node.next;
            node.next = new Node(element, rear);
            size++;
      }
}

hi, bobo老師,

我觉得我可以把 addAtHelper(..)中的 if(node == null) {return;} 刪了,因为 addAt()中的 index > size扔exception已經避免了 node 会等于 null 的情况。 


但如果删了的话,我的递归函数addAtHelper 就没有终止条件了。递归函数一定要有终止条件吗?哪怕这个终止条件没什么用?我有点纠结要不要删掉它,想听听你的建议。 谢谢


 我跑过测试,我的代码能跑出正确答案。

https://img.mukewang.com/climg/652720280990c21e19880766.jpg

写回答

1回答

liuyubobobo

2023-10-13

以下内容我没有验证你的程序的正确性,完全是从递归函数的书写的角度谈的。


==========


删掉 if(node == null) {return;} 后,这个递归函数还是有终止条件的。终止条件就是 else 里的内容。


为什么 else 里的内容是终止条件?因为在 else 里没有递归调用了。


换句话说,将这个递归函数写成这个样子,是逻辑等价的:


private void addAtHelper(Node node, int currIndex, int index, T element){
      
    // 递归终止条件
    if(currIndex >= index - 1){
            
       Node rear = node.next;
       node.next = new Node(element, rear);
       size++;
       return;
    }
    
    // 递归过程
    addAtHelper(node.next, currIndex+1, index, element);
}


而如果你愿意加上 node ==null 的判断,相当于给递归函数加入了两个终止条件。这是完全可以的:


private void addAtHelper(Node node, int currIndex, int index, T element){
      
    // 递归终止条件
    if(node == null){
        return;
    }
    
    if(currIndex >= index - 1){
       Node rear = node.next;
       node.next = new Node(element, rear);
       size++;
       return;
    }
    
    // 递归过程
    addAtHelper(node.next, currIndex+1, index, element);
}



实际上,如果你确认 node 不会等于 null,一个更好的方式是在 node == null 的时候抛异常,或者加入其他的错误处理机制的代码,比如先把这次运行相关的数据写进 log,再 return。


从逻辑的角度,不写 if(node == null) 是完全没有问题的,对于这个“小”程序来说,是完全正确的。但是从“软件工程”的角度看,写这个 if 是更好的。这叫做防御型编程。可以参考这里:https://class.imooc.com/course/qadetail/249635


===========


注意,这和你提出的“终止条件”是两个问题。如我上面所说,你的程序是有终止条件的。一切递归一定有终止条件,否则递归不可能终止,这就像循环会有循环结束条件一样。


而 if(node == null) 这个终止条件,在这个逻辑中,不是必须,但是协商完全没有问题,并且是我推荐的方式,因为下面要调用 node.next,所以考虑 node 为空的情况,不管他是不是真的发生,这是好的编程实践。(这就像一旦遇到除以一个变量,就应该考虑一下这个变量如果是 0 怎么办,而不用管这个变量是不是真的可能是 0。这是好的编程习惯。因为即便在当下的逻辑中,这个变量不会为 0,你不能肯定在以后的版本中,你活着别人是不是可能因为修改逻辑,使得这个变量可以为 0。)


继续加油!:)


0

算法与数据结构

波波老师5年集大成之作,算法与数据结构系统学习,考试、面试、竞赛通用

2638 学习 · 1091 问题

查看课程