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

如何实现可自动整理为范围的内存高效型自定义Int+Range列表

这思路太赞了!对于连续数字占比高的场景,用范围(Range)替代单个数字存储,确实能把内存占用压到极低。我来一步步带你实现这个自定义集合,核心就是自动合并相邻/重叠范围的逻辑,还会包含常用的操作方法:

1. 先定义轻量的Range基础结构

我们用值类型struct来实现Range,它内存开销极小(仅两个int的大小),还能直接栈分配。同时给它加些实用方法,方便后续合并和判断:

public struct Range
{
    public int Start { get; }
    public int End { get; }

    // 单个数字直接转成Range(起始=结束)
    public Range(int singleValue) : this(singleValue, singleValue) { }

    // 构造连续范围的Range
    public Range(int start, int end)
    {
        if (start > end)
            throw new ArgumentOutOfRangeException(nameof(start), "起始值不能大于结束值");
        Start = start;
        End = end;
    }

    // 判断当前范围是否包含某个数字
    public bool Contains(int value) => value >= Start && value <= End;

    // 判断是否能和另一个Range合并(相邻或重叠都算)
    public bool CanMergeWith(Range other)
    {
        // 比如1-5和6-10(相邻)、1-5和3-7(重叠)都可以合并
        return other.Start <= End + 1 && other.End >= Start - 1;
    }

    // 合并两个Range成一个新范围
    public Range MergeWith(Range other)
    {
        if (!CanMergeWith(other))
            throw new InvalidOperationException("无法合并不相邻/不重叠的Range");
        return new Range(Math.Min(Start, other.Start), Math.Max(End, other.End));
    }

    // 重写ToString,方便调试查看
    public override string ToString() => Start == End ? $"{Start}" : $"{Start}-{End}";
}
2. 实现核心的紧凑数字集合类

这个类的关键是添加元素时自动合并范围,同时保持内部Range列表的有序性,方便后续合并和查询:

public class CompactNumberCollection
{
    // 内部用List存Range,因为List本身的内存效率就很高
    private readonly List<Range> _ranges = new List<Range>();

    // 添加单个数字的快捷方法
    public void Add(int value) => Add(new Range(value));

    // 添加一个Range的核心方法
    public void Add(Range range)
    {
        if (_ranges.Count == 0)
        {
            _ranges.Add(range);
            return;
        }

        // 先找出所有能和当前Range合并的现有范围
        var mergeTargets = new List<Range>();
        foreach (var existing in _ranges)
        {
            if (existing.CanMergeWith(range))
                mergeTargets.Add(existing);
        }

        // 如果有可合并的范围,先移除它们,再和当前范围合并成新的大Range
        if (mergeTargets.Count > 0)
        {
            foreach (var target in mergeTargets)
            {
                _ranges.Remove(target);
                range = range.MergeWith(target);
            }
        }

        // 把合并后的Range插入到有序位置,保证列表始终按Start升序排列
        InsertSorted(range);
    }

    // 按Start升序插入,方便后续快速查找和合并
    private void InsertSorted(Range range)
    {
        int insertIndex = _ranges.FindIndex(r => r.Start > range.Start);
        if (insertIndex == -1)
            _ranges.Add(range);
        else
            _ranges.Insert(insertIndex, range);
    }

    // 检查某个数字是否存在(用二分查找优化性能,因为列表是有序的)
    public bool Contains(int value)
    {
        int left = 0;
        int right = _ranges.Count - 1;
        while (left <= right)
        {
            int mid = (left + right) / 2;
            var currentRange = _ranges[mid];
            if (currentRange.Contains(value))
                return true;
            if (value < currentRange.Start)
                right = mid - 1;
            else
                left = mid + 1;
        }
        return false;
    }

    // 枚举所有数字(用yield返回,不会生成完整数组,内存友好)
    public IEnumerable<int> GetAllNumbers()
    {
        foreach (var range in _ranges)
        {
            for (int i = range.Start; i <= range.End; i++)
            {
                yield return i;
            }
        }
    }

    // 对外暴露只读的Range列表,防止外部修改内部结构
    public IReadOnlyList<Range> Ranges => _ranges.AsReadOnly();

    // 重写ToString,方便调试时查看集合内容
    public override string ToString() => string.Join(", ", _ranges.Select(r => r.ToString()));
}
3. 实际使用示例

来看看这个集合的自动合并效果:

var compactCollection = new CompactNumberCollection();

// 随便加一些数字和范围
compactCollection.Add(1);
compactCollection.Add(2);
compactCollection.Add(3);
compactCollection.Add(5);
compactCollection.Add(new Range(7, 10));
compactCollection.Add(6); // 会自动和5、7-10合并成5-10
compactCollection.Add(new Range(12, 15));
compactCollection.Add(11); // 自动合并成11-15

// 输出集合内容:1-3, 5-10, 11-15
Console.WriteLine(compactCollection);

// 检查数字是否存在
Console.WriteLine(compactCollection.Contains(8)); // 输出True
Console.WriteLine(compactCollection.Contains(4)); // 输出False

// 遍历所有数字(不会生成完整数组,内存友好)
foreach (var num in compactCollection.GetAllNumbers())
{
    Console.Write($"{num} ");
}
// 输出:1 2 3 5 6 7 8 9 10 11 12 13 14 15
4. 内存效率对比(直观感受)

比如存储1-3000、3002、4000-5000:

  • 用List<int>:总共是3000+1+1001=4002个int,每个int占4字节,总内存16008字节(约15.6KB)
  • 用CompactNumberCollection:只存3个Range,每个Range占8字节,总内存24字节,差距一目了然
5. 可选优化方向

如果需要更灵活的功能,可以考虑这些扩展:

  • 支持移除操作:删除数字或范围时,需要拆分现有Range,逻辑稍复杂但可行
  • 泛型适配:把int换成long、short等数值类型,适配更大范围的数字
  • 线程安全:多线程场景下,添加锁或改用线程安全的内部集合

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:25:01