如何退出递归循环调用?你得有flag呀

继上次 递归实现列表赋值 的经历之后,今天又遇到了新的需要:给你一棵树的最深节点value值,让你找到从根到该节点的value列表。树的结构长下面这样

{
    value: 1,
    children: [
        {
            value: 2,
            children: [
                {
                    value: 3
                },
                {
                    value: 4
                }
            ]
        },
        {
            value: 5,
            children: [
                {
                    value: 6
                },
                {
                    value: 7
                }
            ]
        }
    ]
}

如果没听明白的话,你就把它想象成一个级联框,给定最后一级value值,返回从第一级到最后一级的列表。就拿上面的树结构举例,我简单画了个级联框

在这里插入图片描述

如果 value是 3 或 4 的话,返回的 value列表 应该是 [1, 2, 3][1, 2, 4]

如果是 value 是 6 或 7 的话,返回的 value 列表应该是 [1, 5, 6][1, 5, 7]

当然,有的可能只有两级级联,所以 value 也可能是 2 或者 5 ,那么返回的 value 列表则是 [1, 2][1, 5]


好,问题分析完了,下面想办法解决。因为之前用过 递归实现列表赋值 ,为了图省事,顺便再练习一下遍历算法,那就敲定递归!直接上代码

// 1. 创建数组valueList作为栈
let valueList = []
let targetValue = 6

function traversalTree(tree) {
  tree.map((item) => {
    // 2. 当value === targetValue,返回栈
    if (item.value === targetValue) {
      valueList.push(item.value)
      return valueList
    }
    // 3. 如果有children属性,把key入栈,访问children
    if (item.children) {
      valueList.push(item.value)
      traversalTree(item.children)
    }
    // 4. 没有children属性,跳到上一级
    // 注意!这里不是清空栈! valueList = []
    valueList.pop()
  })
}

很顺利啊,那看看函数返回的结果是什么。我去,怎么拿到的值是 undefined ?查了查资料,发现里头的 return valueList 语句并没有真正退出 traversalTree 函数。当语句取到我们需要的 vlaue 时,可能已经在第二级或第三级级联框中,也就是在第二层或第三层堆栈中,return 只是返回到上一层堆栈(第一层或第二层),继续执行未完成的语句。 在这里插入图片描述
好家伙,这么一说还得多加个 return 才行。那万一嵌套太深了可咋整?嵌套多了那不得……(脑补一下地狱回调的代码

换个思路

既然简单的 return 行不通,那就换条路走。百度了一下发现还有种方法 —— try...catch。大体思路就是把遍历的操作放在 try 中,当遇到符合条件的情况时主动 throw 一个错误,用 catch 捕获,这样就能跳出嵌套了。因为整个递归算法都在 try 语句中,所以退出 try 语句后,也就退出了递归算法(真的是这样吗?🤔)

function traversalTree(tree) {
  try {
    tree.map((item) => {
      // 2. 当value === targetValue,返回栈
      if (item.value === targetValue) {
        valueList.push(item.value)
        throw valueList
      }
      // 3. 如果有children属性,把key入栈,访问children
      if (item.children) {
        valueList.push(item.value)
        traversalTree(item.children)
      }
      // 4. 没有children属性,跳到上一级
      valueList.pop()
    })
  } catch (valueList) {
    return valueList
  }
}

又跑了一遍代码,函数返回值竟然还是 undefined。纳闷了,咋又失败了呢?于是打了个断点去查了查堆栈

在这里插入图片描述

在主动 throw (找到值)后,从堆栈中可以看到,如果处理完 catch 中的语句,代码还是会回到堆栈处理没调用完的函数。也就是说,简单地使用 try...catch 是不起作用的。

接着想办法

到这里我有点明白过来了,try...catch可以提前终止循环,但不能跳出堆栈,他只是申请回到上一次调用,和 return 功能一致。如果想要跳出这么多的堆栈,还得加一个判断,来一次一次地跳出去。对于我们的算法来说,需要有一个 flag 变量判断是否已经找到 targetValue ,并且在每一次递归调用去做判断。

function getValueList(targetValue) {
  // 1. 创建数组valueList作为栈
  var valueList = []
  let flag = false
  const that = this
  // 这里的that主要是传递this,还有一种this绑定的方法我忘了,就先凑合着吧...
  traversalTree(tree, that)
  return valueList

  function traversalTree(tree, that) {
    tree.map((item, index, arr) => {
      if (flag) return

      // 2. 当value === targetValue,返回栈
      if (item.value === targetValue) {
        valueList.push(item.value)
        flag = true
        return
      }

      // 3. 如果有children属性,把key入栈,访问children
      if (item.children) {
        valueList.push(item.value)
        traversalTree(item.children, that)
      }

      // 4. 读完了当前级的所有内容并且不是第一级
      if (arr.length - 1 === index && that.arrUnlike(arr, that.goodsTypeOptions)) {
        valueList.pop()
      }
    })
  }
}

function arrUnlike(arr1, arr2) {
  if (arr1.length !== arr2.length) return true
  for (const i in arr1) {
    if (arr1[i] !== arr2[i]) {
      return true
    }
  }
  return false
}

P.s. 递归是世界上最好的语言(逃

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 24 点是一个数学游戏,目标是使用 4 个给定的数字和加减乘除运算符,使得计算的结果为 24。 下面是用递归函数解决 24 点游戏的 C 语言代码的一种方法: ``` #include <stdio.h> #include <stdlib.h> #include <stdbool.h> // 定义运算符的枚举类型 typedef enum {ADD, SUB, MULT, DIV} Operator; // 定义递归函数,用于计算表达式的值 double calculate(double a, double b, Operator op) { switch (op) { case ADD: return a + b; case SUB: return a - b; case MULT: return a * b; case DIV: return a / b; } } // 定义递归函数,用于解决 24 点游戏 bool solve24(double *numbers, int n) { if (n == 1) { // 如果只剩一个数字,判断是否为 24 return abs(numbers[0] - 24) < 1e-6; } // 遍历所有数字对 for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { // 保存剩余数字 double remaining[3]; int k = 0; for (int l = 0; l < n; l++) { if (l != i && l != j) { remaining[k++] = numbers[l]; } } // 遍历所有运算符 for (int l = 0; l < 4; l++) { Operator op = l; double result = calculate(numbers[i], numbers[j], op); // 将计算结果加入剩余数字数组中 remaining[2] = result; if (solve24(remaining, 3)) { return true; } } } } return false; } int main() { // 定义要给定的 4 个数字 double numbers[] = {4, 7, 8, 9}; ### 回答2: 递归函数是一种在函数内部调用自身的编程技巧。为了解决24点游戏,我们可以使用递归函数来尝试所有可能的数值组合和运算符排列。 首先,我们可以定义一个递归函数来穷举所有可能的运算符排列。假设我们有4个数a、b、c、d,我们可以通过递归函数来生成所有可能的排列: ``` void permute(int* nums, int* flag, int depth, int* result) { if (depth == 4) { // 在此处理可能的运算符排列 return; } for (int i = 0; i < 4; i++) { if (flag[i] == 0) { flag[i] = 1; result[depth] = nums[i]; permute(nums, flag, depth + 1, result); flag[i] = 0; } } } ``` 然后,我们可以定义另一个递归函数来穷举所有可能的数值组合和运算符排列。假设我们有4个数a、b、c、d和3个运算符的选择(+、-、*、/),我们可以通过递归函数来生成所有可能的组合: ``` void calculate(float* nums, int* operators, int depth) { if (depth == 3) { float result; // 在此处理数值组合和运算符排列 return; } for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (operators[j] == 0) { operators[j] = 1; calculate(nums, operators, depth + 1); operators[j] = 0; } } } } ``` 在处理可能的运算符排列和数值组合时,我们可以使用循环来进行相应的处理。最后,我们可以在递归函数中加入数值和运算的判断逻辑,通过比较计算结果是否等于24来确定是否找到解。如果找到解,我们可以打印出相应的数值和运算符排列。 以上就是一个用递归函数解决24点游戏的思路和大致的代码实现。当然,还需要进一步完善和优化代码,添加相应的数学运算和边界条件判断等,以确保算法的正确性和效率。 ### 回答3: 递归函数可以用来解决24点游戏的问题,下面是一个使用C语言写的示例代码。 #include <stdio.h> #include <stdbool.h> bool solve24(int arr[], int size); bool calculate(double a, double b, double merge, double result) { if (solve24((int *)&merge, 4)) { return true; } if (solve24((int *)&result, 4)) { return true; } if (solve24((int *)&a, 4) || solve24((int *)&b, 4)) { return true; } if (a + b != result && a - b != result && b - a != result && a * b != result && a / b != result && b / a != result) { return false; } return true; } bool solve24(int arr[], int size) { if (size == 1) { if (arr[0] == 24) { return true; } else { return false; } } double a, b; int i, j; for (i = 0; i < size; ++i) { for (j = i + 1; j < size; ++j) { a = arr[i]; b = arr[j]; // 生成新的数组,将计算的结果放入新的数组中 int m, n; double merge, result; n = 0; for (m = 0; m < size; ++m) { if (m != i && m != j) { arr[n++] = arr[m]; } } arr[n] = a + b; if (calculate(a, b, merge, result)) { return true; } arr[n] = a - b; if (calculate(a, b, merge, result)) { return true; } arr[n] = b - a; if (calculate(a, b, merge, result)) { return true; } arr[n] = a * b; if (calculate(a, b, merge, result)) { return true; } if (b != 0) { arr[n] = a / b; if (calculate(a, b, merge, result)) { return true; } } if (a != 0) { arr[n] = b / a; if (calculate(a, b, merge, result)) { return true; } } } } return false; } int main() { int arr[4]; printf("请输入4个数字,以空格分隔:"); for (int i = 0; i < 4; ++i) { scanf("%d", &arr[i]); } if (solve24(arr, 4)) { printf("可以通过+-*/组合得到24。\n"); } else { printf("无法通过+-*/组合得到24。\n"); } return 0; } 该代码使用了递归的思想来逐一尝试将4个数字进行加减乘除的运算,最终判断是否可以得到24。在solve24函数中,通过循环将数组中的两个数字a和b取出,并生成一个新的数组,将计算的结果放入新的数组中。然后,对新数组进行递归调用solve24函数,直到数组长度为1,表示找到了一种可以得到24的组合。函数calculate用来判断四则运算的结果是否为24。最后,通过输入4个数字,调用solve24函数判断是否可以得到24,并输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值