用 Array.BinarySearch
是最稳妥的选择
绝大多数场景下,不需要手写二分查找——C# 运行时已提供高度优化、泛型安全、边界处理完善的
Array.BinarySearch方法。它支持所有一维数组(
int[]、
string[]、自定义类型等),且自动处理未找到时的负数返回值(按位取反后为插入位置)。
常见错误是直接把返回值当索引用,忽略负数含义:
int[] arr = { 1, 3, 5, 7, 9 };
int index = Array.BinarySearch(arr, 6); // 返回 -4,不是“没找到就返回 -1”
if (index < 0) {
Console.WriteLine($"应插入到位置 {~index}"); // 输出:应插入到位置 3
}手写二分查找时必须检查 left
手动实现最容易出错的是循环条件和边界更新。典型错误写法:
while (left 或漏掉 <code>mid的等于判断,导致漏查或死循环。
标准实现要点:
初始right = arr.Length - 1,不是
arr.Length循环条件严格为
left更新时用
right = mid - 1和
left = mid + 1,不能写成
= mid每次计算
mid = left + (right - left) / 2防止整数溢出(尤其在大数组中)
static int BinarySearch(int[] arr, int target) {
int left = 0, right = arr.Length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
List<t>.BinarySearch</t>
和 Span<t>.BinarySearch</t>
的适用场景
如果数据来自
List<t></t>,优先用其
BinarySearch方法,它内部调用相同逻辑,但避免了数组拷贝开销;若处理的是栈上切片(如从大数组中取一段),
Span<t>.BinarySearch</t>更高效,零分配且支持自定义
IComparer<t></t>。
注意:二者都要求输入已排序,且不自动验证——传入乱序数据会返回错误结果,不会抛异常。
List<int>.BinarySearch</int>:适合频繁读、偶有修改的集合
Span<int>.BinarySearch</int>:适合高性能数值计算、内存敏感场景(.NET Core 2.1+) 三者都不支持多维数组,需自行展平或改用其他结构
泛型版本要小心 IComparable<t></t>
和 null
对引用类型(如
string或自定义类)使用泛型二分时,若元素可能为
null,而比较器未显式处理,
Array.BinarySearch<string></string>可能抛
NullReferenceException。
解决方式:
用带IComparer<t></t>参数的重载,例如
StringComparer.Ordinal自定义类型确保实现
IComparable<t></t>并正确处理
null避免依赖默认比较器处理可空引用类型
比如搜索含
null的字符串数组:
string[] arr = { "a", null, "c" };
// ❌ 危险:Array.BinarySearch(arr, "b") 可能崩
// ✅ 安全:指定比较器
int idx = Array.BinarySearch(arr, "b", StringComparer.Ordinal);实际用的时候,先确认数据是否已排序、是否允许
null、是否需要插入位置信息——这些细节比算法本身更容易导致线上问题。
