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

如何实现适配自定义集合与数组的泛型归并排序函数?

需求背景

我有一个名为CustomList的自定义类,功能类似数组但支持动态扩容。我希望实现一个MergeSort函数,能同时处理CustomList和标准数组。

我的尝试代码

Sorter类实现

public class Sorter<T> where T : IEnsemble<T>
{
    public static IEnsemble<T> MergeSort(IEnsemble<T> array)
    {
        IEnsemble<T> res;
        if (array.Length > 1)
        {
            IEnsemble<T> left = MergeSort(array[0..(array.Length / 2)]);
            IEnsemble<T> right = MergeSort(array[(array.Length / 2)..]);
            res = MergeSort(left, right);
            return res;
        }
        else { return array; }

    }

    public static IEnsemble<T> MergeSort(IEnsemble<T> left, IEnsemble<T> right)
    {
        int leftPointer = 0;
        int rightPointer = 0;
        IEnsemble<T> res = new IEnsemble<T>(left.Length + right.Length);
        while (leftPointer < left.Length || rightPointer < right.Length)
        {
            if (rightPointer == right.Length || (leftPointer < left.Length && left[leftPointer].CompareTo(right[rightPointer]) < 0))
            {
                res[leftPointer + rightPointer] = left[leftPointer];
                leftPointer++;
            }
            else
            {
                res[leftPointer + rightPointer] = right[rightPointer];
                rightPointer++;
            }
        }
        return res;
    }
}

IEnsemble接口定义

public interface IEnsemble<T>
{
    T this[int i] { get; set; }
    IEnsemble<T> this[Range range] { get; }
    int Length { get; }
}

遇到的问题

  • 范围操作返回的是接口而非具体实现类,不确定是否会引发问题;
  • 代码中IEnsemble<T> res = new IEnsemble<T>(left.Length + right.Length);无法运行,因为接口不能被实例化。

核心疑问

我想创建一个能同时支持自定义集合类(带索引和范围操作)和标准数组的泛型归并排序函数,这是否可行?如果可行,该怎么实现?


解决方案

完全可行,核心是解决接口不能实例化的问题,同时兼容标准数组和自定义集合。以下是具体实现步骤:

1. 调整接口与约束

首先给IEnsemble<T>新增创建实例的方法,同时给元素类型T加上比较约束(归并排序依赖元素比较);另外需要给标准数组做接口适配,因为原生数组不实现自定义接口。

调整后的IEnsemble接口

public interface IEnsemble<T> where T : IComparable<T>
{
    T this[int index] { get; set; }
    IEnsemble<T> this[Range range] { get; }
    int Length { get; }
    // 新增:创建指定长度的集合实例
    IEnsemble<T> CreateInstance(int length);
}

标准数组的接口适配类

创建包装类让数组实现IEnsemble<T>:

public class ArrayWrapper<T> : IEnsemble<T> where T : IComparable<T>
{
    private readonly T[] _array;

    public ArrayWrapper(T[] array) => _array = array;

    public T this[int index]
    {
        get => _array[index];
        set => _array[index] = value;
    }

    public IEnsemble<T> this[Range range]
    {
        get
        {
            var (offset, length) = range.GetOffsetAndLength(_array.Length);
            var subArray = new T[length];
            Array.Copy(_array, offset, subArray, 0, length);
            return new ArrayWrapper<T>(subArray);
        }
    }

    public int Length => _array.Length;

    public IEnsemble<T> CreateInstance(int length)
    {
        return new ArrayWrapper<T>(new T[length]);
    }

    // 方便转换回原生数组
    public T[] ToArray() => _array;
}

让CustomList实现调整后的接口

确保你的CustomList<T>实现IEnsemble<T>的所有成员,包括CreateInstance方法:

public class CustomList<T> : IEnsemble<T> where T : IComparable<T>
{
    // 你的原有实现逻辑(动态扩容、元素存储等)
    private T[] _items;
    public int Length => _items.Length;

    // 假设已有指定初始长度的构造函数
    public CustomList(int initialLength)
    {
        _items = new T[initialLength];
    }

    public T this[int index]
    {
        get => _items[index];
        set => _items[index] = value;
    }

    public IEnsemble<T> this[Range range]
    {
        get
        {
            var (offset, length) = range.GetOffsetAndLength(Length);
            var subList = new CustomList<T>(length);
            for (int i = 0; i < length; i++)
            {
                subList[i] = _items[offset + i];
            }
            return subList;
        }
    }

    public IEnsemble<T> CreateInstance(int length)
    {
        return new CustomList<T>(length);
    }
}

2. 修改MergeSort函数

现在可以通过CreateInstance方法创建目标类型的实例,替代直接实例化接口的错误写法:

public static class Sorter
{
    public static IEnsemble<T> MergeSort<T>(IEnsemble<T> ensemble) where T : IComparable<T>
    {
        if (ensemble.Length <= 1)
            return ensemble;

        int mid = ensemble.Length / 2;
        var left = MergeSort(ensemble[0..mid]);
        var right = MergeSort(ensemble[mid..]);

        return Merge(left, right);
    }

    private static IEnsemble<T> Merge<T>(IEnsemble<T> left, IEnsemble<T> right) where T : IComparable<T>
    {
        int leftPtr = 0, rightPtr = 0, current = 0;
        // 使用左集合的CreateInstance创建结果,保证返回类型与输入一致
        var result = left.CreateInstance(left.Length + right.Length);

        while (leftPtr < left.Length && rightPtr < right.Length)
        {
            if (left[leftPtr].CompareTo(right[rightPtr]) <= 0)
            {
                result[current] = left[leftPtr];
                leftPtr++;
            }
            else
            {
                result[current] = right[rightPtr];
                rightPtr++;
            }
            current++;
        }

        // 处理剩余元素
        while (leftPtr < left.Length)
        {
            result[current] = left[leftPtr];
            leftPtr++;
            current++;
        }

        while (rightPtr < right.Length)
        {
            result[current] = right[rightPtr];
            rightPtr++;
            current++;
        }

        return result;
    }
}

3. 使用示例

对标准数组排序

int[] arr = { 3, 1, 4, 1, 5, 9 };
var wrapper = new ArrayWrapper<int>(arr);
var sortedWrapper = Sorter.MergeSort(wrapper);
int[] sortedArr = sortedWrapper.ToArray();

对CustomList排序

var customList = new CustomList<int> { 5, 2, 7, 1 };
var sortedList = (CustomList<int>)Sorter.MergeSort(customList);

关于范围操作返回接口的问题

范围操作返回接口完全没问题,归并排序的递归过程只依赖接口定义的行为(索引访问、长度获取、实例创建),不需要关心具体实现类。只要所有实现类的范围操作都正确返回符合接口要求的实例,就不会有逻辑问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 05:33:20