【踩坑记录】逻辑运算符的执行方式

1.BUG记录

最近在写一道算法题的时候,遇到了一个bug,主要是由于逻辑运算符的执行方式所导致的。

代码如下:

bool check(int num, vector<int>& locked_num) {
    int flag = false;
    // 判断当前节点是否被上锁
    if (locks.find(num) != locks.end() && locks[num] != -1) {
        locked_num.push_back(num);
        flag = true;
    }
    for (const auto& next : children[num]) {
        // 出bug的地方
        flag = flag || check(next, locked_num);
    }
    return flag;
}

代码的主要作用是遍历多叉树,返回数中是否有被上锁的节点,同时将所有节点存储到指定的容器中。

可以看到,这是一个递归函数,使用for循环,对当前节点的所有子树进行遍历,问题就出在了,下面代码所示的这一句上面。

flag = flag || check(next, locked_num);

这里就不得不提逻辑或运算符的执行方式了。

对于 a || b  这个表达式,如果a已经为true,那么程序将不会对b进行判断,直接忽略掉b的部分。

所以,对于我上述的代码来说,一旦在某次循环中flag置为true了,或者如上述代码中,第一个if已经将flag置为true了,那么后续的递归是不会进行下去的。

所以修改此bug只需要将递归函数提前或者使用|=,具体如下:

flag =  check(next, locked_num) || flag;
// 或者
flag |= check(next, locked_num);

2.C++的逻辑运算符

这里只介绍逻辑或逻辑与运算符。

对于逻辑或运算符来说,a || b ,当a为true时,不会执行b。

对于逻辑与运算符来说,a && b,当a为false时,不会执行b。

因为当上述两种情况出现时,无论b的结果是什么,都不会影响整个表达式的结果

为什么会出现这种情况?

因为C++规定了,逻辑或逻辑与运算符是顺序执行的(在C++11之前,也被称为顺序点——sequence point)。简单来说,就是运算符左边的表达式优于右边的表达式。

这种执行方式有助于我们规避一些错误,举个最简单的例子:

if (x != 0 && 10 / x > 2) {...}

上述的例子中,能够帮助程序规避掉0除的问题。

同时,我们也可以进行区间判断借用C++ primer plus的例子):

if (age > 17 && age < 35) {
    ...
} else if (age >= 35 && age < 50) {
    ...
} else if (age >= 50 && age < 65) {
    ...
} else {
    ...
}

还有许多其他的应用,这里就不继续介绍了。

总之,我们能够灵活地使用逻辑运算符的这种性质来达到我们的目的。

3.讨论

最后,感叹一下,某些知识还是需要一段印象深刻的经历才能牢记啊。在此之前,这种逻辑运算符有这种特点我也十分清楚,但是写代码的时候就是没有注意,导致短短的一行代码,我debug了好久才找到问题。还是需要不断地实践,在充满错误的道路上不断前行!!!与看到这的读者共勉。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值