C语言中BST奇偶/负数统计函数countIf异常问题排查
问题:二叉搜索树统计函数
countIf在含负数的数据集上失效的原因分析 你的countIf函数递归遍历的逻辑本身是没问题的,但问题出在**isOdd函数对负数奇数的判断逻辑**上——这是C语言取模运算的特性导致的容易踩的小坑!
问题根源
先看你的isOdd实现:
int isOdd (TreeItem n) { return n%2; }
在C语言中,取模运算的结果符号和被除数保持一致:
- 正数奇数:比如
5%2返回1,此时isOdd返回1,符合预期(代表是奇数) - 负数奇数:比如
-5%2返回**-1**,而不是你预期的1!
当countIf累加这个返回值时,-1会被计入总和,相当于抵消了一个有效计数。比如你的第二个测试集里有-5和-9两个负数奇数,它们会贡献-2而不是+2,直接导致最终统计结果比实际值少了4,自然就出错了。
反观你的isEven函数:
int isEven (TreeItem n) { return !(n%2); }
它之所以没问题,是因为不管n%2返回0、1还是-1,取反后都会得到正确的0或1:
- 偶数(包括负偶数):
n%2是0,!0为1,正确 - 奇数(包括负奇数):
n%2是1或-1,!1和!(-1)都是0,正确
修复方案
把isOdd改成明确返回0或1的逻辑,避免依赖取模结果的符号:
方案1:直接判断取模结果是否非零
int isOdd (TreeItem n) { return (n % 2 != 0); }
不管n%2返回1还是-1,只要不等于0,就说明是奇数,返回1,否则返回0。
方案2:用位运算更高效(推荐)
奇数的二进制最后一位永远是1(补码表示下,正负奇数都适用),所以可以直接判断最低位:
int isOdd (TreeItem n) { return ((n & 1) != 0); }
位运算不仅效率更高,还能彻底避免取模运算的符号问题,逻辑更可靠。
额外验证
你的isNegative函数逻辑是正确的:
int isNegative (TreeItem n) { return (n < 0); }
负数返回1,非负数返回0,累加后能正确统计负数节点数量,不会出现类似问题。
内容的提问来源于stack exchange,提问作者Billi
相关产品推荐
相关产品推荐

