递归函数return

197 阅读2分钟

这篇文章记录一下自己对递归函数return的理解。

递归函数执行实际上就是栈调用的方式,递归最底部的程序执行,实际上就是栈顶元素执行。达到递归终止条件之后,栈顶函数执行完被释放,也就是最内部的递归程序执行完,然后是下一级的程序执行,也就是再浅一层的函数执行。最后层层出栈完成最终程序执行。

如果你的递归程序,只需要执行而不需要有返回值,那么写递归程序的时候就不需要写返回值。

// 向树中插入节点是一个纯执行的过程,所以不需要有返回值
  protected insertNode(node: TreeNode<T>, element: T) {
    if (this.compareFn(element, node.element) === Compare.LESS_THAN) {
      if (node.left === null) {
        node.left = new TreeNode(element)
      } else {
        this.insertNode(node.left, element)
      }
    } else if (node.right === null) {
      node.right = new TreeNode(element)
    } else {
      this.insertNode(node.right, element)
    }
  }

如果你的递归程序要有返回值,因为递归程序栈是层层结束的,栈顶的元素要想往栈下面传递的话,就需要return作为传输介质。因此如果要有返回值的话,递归程序执行就需要使用return

  /** 输入一个节点,查看这个节点及其子节点是否有满足element元素的节点 */
  private searchNode(node: TreeNode<T>, element: T) {
    if (node === null) return false

    if (this.compareFn(element, node.element) === Compare.LESS_THAN) {
      return this.searchNode(node.left, element)
    } else if (this.compareFn(element, node.element) === Compare.BIGGER_THAN) {
      return this.searchNode(node.right, element)
    }
    // 上面两个条件都不满足就说明相等,找到了,返回true
    return true
  }

还有一种情况是又有执行又有返回值,常见于对某些内容做更改并把更改的内容返回回去,此时应该赋值和返回都去做。

比如下面这种情况,要对二叉搜索树移除一个节点。

此时要返回一个删除后的新的树,因此要对树的内容赋值,因为有返回,还要写return。对于这种比较复杂的递归问题不要慌,只需要构建起来最为简单的递归小例子,然后验证代码就可以。

  /** 从一棵树中移除某个元素,会生成新的树 */
  remove(element: T) {
    this.root = this.removeNode(this.root, element)
  }

  private removeNode(node: TreeNode<T>, element: T) {
    if (node === null) {
      return null
    }

    if (this.compareFn(element, node.element) === Compare.LESS_THAN) {
      node.left = this.removeNode(node.left, element)
      return node
    } else if (this.compareFn(element, node.element) === Compare.BIGGER_THAN) {
      node.right = this.removeNode(node.right, element)
      return node
    } else {
      // key is equal to node.item

      // handle 3 special conditions
      // 1 - a leaf node
      // 2 - a node with only 1 child
      // 3 - a node with 2 children

       // case 1
       if (node.left == null && node.right == null) {
        node = null;
        return node;
      }
      
      // case 2
      if (node.left == null) {
        node = node.right;
        return node;
      } else if (node.right == null) {
        node = node.left;
        return node;
      }

      // case 3
      const aux = this.minNode(node.right);
      node.element = aux.element;
      node.right = this.removeNode(node.right, aux.element);
      return node;
    }
  }