You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中对存储定长排序键值对的byte[]执行Binary search的方法

实现方案

有两种主流实现方式,优先推荐手动实现二分查找的方案,性能更高、灵活性更强。

方案1:手动实现二分查找(推荐)

直接针对加载到内存的byte[]缓冲区编写二分逻辑,不需要额外做类型转换,适配任意定长键长和记录长度。
核心逻辑是直接按记录长度计算中间位置的偏移,对比键对应的字节段即可,参考实现代码如下:

/// <summary>
/// 定长记录二分查找
/// </summary>
/// <param name="buffer">加载了全部记录的字节缓冲区</param>
/// <param name="recordSize">单条记录的总长度(字节)</param>
/// <param name="keyLength">键的长度(字节)</param>
/// <param name="searchKey">要搜索的键的字节数组</param>
/// <returns>找到则返回记录的起始偏移,未找到返回负的插入位置,和.NET内置二分返回规则一致</returns>
public static int BinarySearchRecords(byte[] buffer, int recordSize, int keyLength, byte[] searchKey)
{
    if (buffer == null || buffer.Length % recordSize != 0)
        throw new ArgumentException("缓冲区长度不是单条记录长度的整数倍");
    if (searchKey == null || searchKey.Length != keyLength)
        throw new ArgumentException("搜索键长度和设定的键长不一致");

    int left = 0;
    int right = buffer.Length / recordSize - 1;

    while (left <= right)
    {
        int mid = left + (right - left) / 2; // 避免整数溢出
        int recordOffset = mid * recordSize;
        
        // 对比键字节段,用内置Span方法性能更高
        int compareResult = buffer.AsSpan(recordOffset, keyLength)
            .SequenceCompareTo(searchKey.AsSpan());

        if (compareResult == 0)
        {
            // 找到记录,如需直接返回对应int值,可替换为return BitConverter.ToInt32(buffer, recordOffset + keyLength);
            return recordOffset;
        }
        else if (compareResult < 0)
        {
            left = mid + 1;
        }
        else
        {
            right = mid - 1;
        }
    }

    return ~left;
}

如果要搜索的目标是字符串,只需要用对应编码(比如ASCII、UTF8)把字符串转成字节数组再传入searchKey参数即可。

方案2:封装结构适配Array.BinarySearch

如果一定要使用.NET内置的Array.BinarySearch方法,需要先把字节缓冲区映射为自定义结构数组,再传入自定义比较器实现。
该方案需要处理结构序列化的问题,适配不同键长的灵活度更低,还会产生额外的内存拷贝,性能不如方案1。示例结构定义如下(以键长6为例):

// 禁用字节对齐,保证结构内存布局和文件记录一致
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Record
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public byte[] Key;
    public int Value;
}

后续需要把byte[]缓冲区转换为Record[]数组,再实现IComparer<Record>接口传入Array.BinarySearch即可。

内容的提问来源于stack exchange,提问作者Marc Bernier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 01:54:03