如何使MergeSort对不同的对象通用

本文关键字:对象 何使 MergeSort | 更新日期: 2023-09-27 18:29:44

我目前有一个合并排序,它根据每个节点中一个名为"F"(So-Node.F)的整数对节点列表进行排序。

然而,我提出了对另一个对象列表(实体)使用MergeSort的需求。然而,我想根据每个实体中一个名为"AmountEaten"(So Entity.AmountEaten)的整数对其进行排序。

现在我的问题是->使MergeSort类适用于所有对象。我已经用"object"替换了排序中对Node的所有引用,但如何允许自定义排序标准?有没有办法将其作为参数提供。

如果这没有意义,在MergeSort中,我比较两个值(例如Left.F<Right.F)。对于泛型对象,这是不起作用的,因为F不存在。我希望能够比较对象中的任何东西,在我的排序中(例如Left.AmountEaten<Right.AmountEten)。我不知道如何将其作为参数。我立刻想到了代表,但我不确定这是怎么回事/是否正确。

由于排序处理的是列表,而不是单个对象,所以我不能简单地给出F/AmountEaten参数,因为我想访问变量,而不是值。

如果您需要更多细节/不了解,请询问。

我似乎已经得出了某种形式的结论,但你能帮我把它发挥作用吗

MergeSort类:

static class MergeSort
{
    public static IList<object> Sort(IList<object> input, Comparison<object> comparison /* Comparison is a delegate that works out the difference
                                                                                         * between 2 values - Same signature used by List<T>.Sort */)
    {
        List<object> Result = new List<object>();
        Queue<object> Left = new Queue<object>(); //Switched from lists to queues because removing at index 0 is more efficient
        Queue<object> Right = new Queue<object>();
        //Dequeue() and Count() have a time complexity of O(1)
        if (input.Count <= 1)
            return input;
        int midpoint = input.Count / 2;
        for (int i = 0; i < midpoint; i++)
            Left.Enqueue(input[i]);
        for (int i = midpoint; i < input.Count; i++)
            Right.Enqueue(input[i]);
        Left = new Queue<object>(Sort(Left.ToList(), comparison)); //Recursion! :o
        Right = new Queue<object>(Sort(Right.ToList(), comparison)); ; //This line and the one above split the list into smaller lists (left and right)
        Result = Merge(Left, Right, comparison); //This joins the lists together
        return Result;
    }
    private static List<object> Merge(Queue<object> Left, Queue<object> Right, Comparison<object> comparison)
    {
        int cmp = comparison(Left.Peek(), Right.Peek());
        //If cmp is less than 0, left is less. If it is greater, left is greater
        List<object> Result = new List<object>();
        while (Left.Count /* O(1) operation */ > 0 && Right.Count > 0)
        {
            if (cmp < 0)
                Result.Add(Left.Dequeue());
            //Left.RemoveAt(0) - Using a list to remove at a certain point is inefficient
            else
                Result.Add(Right.Dequeue());
        }
        while (Left.Count > 0)
            Result.Add(Left.Dequeue());
        while (Right.Count > 0)
            Result.Add(Right.Dequeue());
        return Result;
    }
}
}

用法:

Entities = MergeSort.Sort(Entities, (p, q) => p.F.CompareTo(q.F)).ToList();

如何使MergeSort对不同的对象通用

通常,最好的签名与List<T>.Sort(...):使用的签名相似

static void MergeSort<T>(IList<T> coll, Comparison<T> comparison)
{
    ...
    // < 0 coll[i] < coll[j], == 0 coll[i] == coll[j], > 0 coll[i] > coll[j]
    int cmp = comparison(coll[i], coll[j]);
    ...
}

用途:

MergeSort(coll, (p, q) => p.F.CompareTo(q.F));

请注意,如果F是一个整数,您经常会看到类似于:(p, q) => p.F - q.F的比较。这是因为如果是p.F > q.F,则是p.F - q.F > 0,依此类推

另一种可能的变体是LINQ OrderBy(...) 使用的变体

通常,最好的签名与List<T>.Sort(...):使用的签名相似

static void MergeSort<T, TKey>(IList<T> coll, Func<T, TKey> selector)
{
    var comparer = Comparer<Tkey>.Default;
    ...
    // < 0 coll[i] < coll[j], == 0 coll[i] == coll[j], > 0 coll[i] > coll[j]
    int cmp = comparer(selector(coll[i]), selector(coll[j]));
    ...
}

用途:

MergeSort(coll, p => p.F);

在这里,我们将一个能够返回"排序键"的委托传递给该方法,如p => p.F。它有点慢,更难使用(但它可能在LINQ中使用,因为它与SQL中的操作更相似)