BinarySearch 要求数据必须升序排序,否则结果不可靠;未找到时返回 ~index(如-4表示应插入索引3),需用 result >= 0 判断是否找到,插入位置为 ~result。

BinarySearch 在 C# 中不能直接用于任意数组或集合——它要求数据必须已升序排序,否则结果不可靠,甚至返回负数(表示插入位置的补码),这不是 bug,是设计使然。
为什么 Array.BinarySearch 返回负数?
这是最常被误解的点。当目标值不存在时,Array.BinarySearch 不返回 -1,而是返回 ~index(按位取反后的插入位置)。比如返回 -4,说明若插入该值,应放在索引 3 的位置(因为 ~3 == -4)。
- 务必用
(result >= 0)判断是否找到,而不是(result != -1) - 若需获取插入位置,用
~result,但仅在result 时有效 - 对
List<t></t>,要调用list.BinarySearch(item),而非list.FindIndex或 LINQIndexOf
BinarySearch 要求数组必须严格升序
哪怕只有一个逆序元素(如 [1,3,2,4]),结果就可能错乱——算法不校验顺序,只按二分逻辑推进。
- 升序是硬性前提,不是“建议”。降序数组必须用自定义
IComparer<t></t>,且整个查找过程都要保持一致 - 浮点数数组慎用默认比较:
double.NaN会导致未定义行为;建议用Comparer<double>.Default</double>或显式处理 NaN - 字符串默认区分大小写;如需忽略大小写,传入
StringComparer.OrdinalIgnoreCase
泛型 List<t>.BinarySearch</t> 和 Array.BinarySearch 的关键区别
二者 API 表面相似,但行为细节不同,混用容易出错。
-
Array.BinarySearch有多个重载,支持从指定索引/长度范围查找;List<t>.BinarySearch</t>没有等效的“子范围”参数,只能对整个列表操作 -
List<t></t>的BinarySearch方法返回值语义与数组完全一致,但若传入null且T是引用类型,会抛ArgumentNullException - 自定义比较器必须实现
IComparer<t></t>,不能只写一个Func<t></t>——后者得包装成Comparer<t>.Create(...)</t>
性能陷阱:别在每次查找前排序
如果数据动态变化、查找频次高,先 Sort() 再 BinarySearch() 反而比线性扫描还慢。
-
BinarySearch时间复杂度 O(log n),但前提是数据已排序;排序本身是 O(n log n),单次查找不划算 - 高频读写场景,考虑
SortedSet<t></t>或SortedList<tkey></tkey>,它们自动维护顺序,Contains就是二分 - 若只是偶尔查、数据量小(Contains 或
FirstOrDefault更直观,也更不容易出错
真正要用好 BinarySearch,关键是把“数据有序”当成契约来维护,而不是当成一次性的预处理步骤。一旦顺序被破坏,所有后续查找结果都失去意义——这点比具体怎么写代码更难调试。


















