发布于2026-07-18 阅读(0)
扫一扫,手机访问
BinarySearch 这个二分查找方法,在 C# 里可不是随便拿来就能用的——它要求数据必须已经升序排序,否则结果根本不可信。而且当目标值不存在时,它返回的不是常见的 -1,而是负数,这个负数的数学含义是“应插入位置的按位取反值”。这不是 bug,而是设计上的刻意安排,理解这一点才能真正用好它。

Array.BinarySearch 返回负数?这是最容易被误解的地方。当你要找的值不存在时,Array.BinarySearch 返回的是 ~index,也就是插入位置的按位取反。比如返回 -4,意味着如果要把这个值放进去,应该放在索引 3 的位置(因为 ~3 == -4)。所以判断是否找到,必须用 result >= 0,而不是 result != -1——后者是很多新手掉进去的坑。如果没找到,想获取插入位置,用 ~result(但仅在 result < 0 时有效)。对于 List,要调用 list.BinarySearch(item),别用 list.FindIndex 或 LINQ 的 IndexOf,它们做的是线性扫描,不是二分。
BinarySearch 要求数组必须严格升序这一点没有商量余地。哪怕只有一个逆序元素,比如 [1,3,2,4],结果都可能错乱——算法不会校验顺序,它只管按二分逻辑一路推进,顺序错了,逻辑就全歪了。升序是硬性前提,不是“建议”。如果数组是降序的,必须用自定义 IComparer,并且整个查找过程中比较器要保持一致,不能中途换。浮点数数组尤其要小心:double.NaN 会导致未定义行为,建议用 Comparer 或者显式处理 NaN。字符串默认区分大小写,如果需要忽略大小写,记得传入 StringComparer.OrdinalIgnoreCase。
List.BinarySearch 和 Array.BinarySearch 的关键区别两个 API 表面相似,但行为细节有差异,混用容易出错。Array.BinarySearch 有多个重载,支持从指定索引和长度范围进行查找;而 List 没有等效的“子范围”参数,只能对整个列表操作。如果 List 的 BinarySearch 传入 null 且 T 是引用类型,会抛出 ArgumentNullException。另外,自定义比较器必须实现 IComparer,不能只写一个 Func 委托——后者需要包装成 Comparer 才能用。
如果数据是动态变化的,而且查找频率很高,先 Sort() 再 BinarySearch() 反而可能比线性扫描还慢。BinarySearch 的时间复杂度是 O(log n),但前提是数据已经排好序;排序本身是 O(n log n),单次查找完全划不来。高频读写场景,更推荐用 SortedSet 或 SortedList,它们自动维护顺序,Contains 方法底层就是二分查找。如果只是偶尔查一次,数据量又小(比如小于几千),直接用 Contains 或 FirstOrDefault 更直观,也不容易出错。
真正用好 BinarySearch 的关键,是把“数据有序”当成一个契约来维护,而不是当成一次性的预处理步骤。一旦顺序被破坏,所有后续查找结果都失去意义——这一点比具体怎么写代码更难调试,但也是所有二分查找应用中最根本的教训。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8