我有一个类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
时按键引用元素。 我可以使用什么样的集合来维护我的对象,使它们保持排序状态,并且它们可以按索引顺序遍历?
答案 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
返回值为零