维护排序顺序C#

时间:2015-07-23 13:37:04

标签: c# .net performance sorting icomparable

我有一个类Foo,其中包含一个对象列表:List<Bar>。每个Bar都有一个属性,可以对它们进行排序(类型TimeSpan,表示持续时间),Bar是一个不可变对象 - 也就是说,持续时间不会改变运行算法。目前,对于每个Foo,如果要对其进行排序(即最短持续时间的Bar),我还会保留列表中第一个Bar。像这样:

public class Foo
{
    public List<Bar> AllBars { get; set; }

    public Bar FirstBar { get; set; }

    public Foo (Bar bar)
    {
        FirstBar = bar;

        AllBars = new List<Bar>() { bar };
    }

    public AddBar(Bar bar)
    {
        if(bar.Duration < FirstBar.Duration)
        {
            FirstBar = bar;
        }

        AllBars.Add(bar);
    }
}

此类Foo用于处理性能(速度)至关重要的算法中。记忆很重要但不如速度快。有一个 n Foo列表,每个列表都包含 m Bar s。直到这一刻,这门课一直很好。我现在希望为用户提供多种选择,这意味着我需要随机访问列表中的前几个Bar

我希望按顺序存储我的Bar,以便我可以按顺序按索引访问它们。在我的Bar课程中,我实施了IComparable以允许Bar在持续时间上进行比较,但我坚持选择合适的数据类型。我查看System.Collections.SortedList但是(除非我错了)这似乎是在实现IDictionary时按键引用元素。 我可以使用什么样的集合来维护我的对象,使它们保持排序状态,并且它们可以按索引顺序遍历?

3 个答案:

答案 0 :(得分:3)

我更喜欢使用SortedSet<T>,这是一个二叉树,其中键和值是同一个对象。这再一次意味着添加/删除/查找是对数 - O(log n) - 但您可以按顺序迭代项目。要使此集合生效,请键入T必须实施IComparable<T>,否则您需要提供外部IComparer<T>

答案 1 :(得分:2)

为什么不使用List.Insert
插入是O(n)并允许您插入特定索引 n + n仍为O(n)

public AddBar(Bar bar)
{
    int index = 0;    
    foreach (bar b in AllBar)
    {
       if(bar.Duration < b.Duration)
         break;
       index++;
    }
    AllBars.Insert(index, bar);
}

所以你有排序和O(1)指数
以O(n)为代价加上
当前加入也是O(n)

NlogN中的SortedList然后你没有索引,因为密钥是持续时间而密钥不是唯一的

SortedSet插入是LogN但是ToList是O(n)所以你仍然是O(n)

调用列表中的Sort方法是NlogN

这回答了以下问题: 我可以使用什么样的集合来维护我的对象,使它们保持排序状态,并且它们可以按索引顺序遍历?

我认为你不会比O(n)添加更好 谁给了它一个投票然后什么是更好的解决方案?

答案 2 :(得分:2)

(根据提问者的要求从评论中提升)

如果您可以忍受“没有任何意义”的“值”,只需使用SortedList<Bar, object>,而不使用值部分。

在O(n)时间内添加yourSortedList.Add(yourBar, null)(列表必须在您插入的点之后“向上”移动所有条目)。使用i在O(1)时间内检索yourSortedList.Keys[i]条目。

请参阅SortedList<,>.Keys property documentation以获取上述说明正确的“证据”。请注意,SortedList<,>实际上由一个“列表”组成(即长度为Capacity的数组,必要时可以用更大的数组替换)。这与我认为是二叉搜索树的SortedDictionary<,>不同。

但请注意:您的SortedList<,>将无法复制,因此列表中的两个成员不允许彼此CompareTo返回值为零