有没有同样有效的方法
处理所有可能的对,如果
使用列表而不是
数组?
List<T> 只是 T[] 的精美包装,当超出列表容量时,它会偶尔调整大小。
你的算法已经是最优的了。如果您想将它与List<T> 一起使用,那么只需将声明从void MyMethod (MyThing[] myArray) 更改为void MyMethod (List<MyThing> myArray)。
有没有更好的收藏
比 List 更特殊的用法?我不
需要排序,我只新建
收藏,清除现有
收藏,添加到收藏,
枚举一个集合或进程
配对如上。随便收藏
我使用,我可能需要 100 到 10000 个
他们,所以他们不会太昂贵
创建/保留。
首先让我们试着了解一些关于数据结构的东西:
在内部,List<T> 保存一个大小为 N 的数组;当您将项目添加到数组中时,如果超出内部数组的大小,则列表将允许大小为 N*2 的新数组,复制元素,然后添加新元素。调整大小的最坏情况为 O(n);但是,每次调整大小时将数组加倍意味着您必须添加两倍于以前的元素才能触发最坏情况的行为。列表有一个属性,可以为它们提供amortized O(1) 插入,这意味着您可以在 O(n) 时间内执行 n 次操作。
通常,LinkedList 的插入速度非常快。据我所知,它不使用底层数组,而是有一个节点集合,其中包含指向集合中相邻项目的 Next 和 Previous 指针。从好的方面来说,最坏情况下的插入是 O(1),但由于引用的局部性较差(即列表中的相邻项在内存中不相邻),有时链表在理论上可能低于最佳性能。
我个人从未见过迭代数组比链表慢的场景。在您过多考虑引用的局部性之前,我肯定会先考虑一个乏味的链表。
话虽如此,如果您真的想要一个具有良好引用局部性的动态大小的集合,而且还支持快速插入,那么请尝试VList。它具有您正在寻找的两个属性,并且非常容易编写:
public class VList<T> : IEnumerable<T>
{
VListNode<T> RootNode;
public int Count { get; private set; }
public VList() : this(4) { }
public VList(int size)
{
RootNode = new VListNode<T>(4, null);
}
public void Add(T element)
{
if (RootNode.Count == RootNode.MaxSize)
RootNode = new VListNode<T>(RootNode.MaxSize * 2, RootNode);
RootNode.Add(element);
Count++;
}
public void Clear()
{
RootNode = new VListNode<T>(4, null);
}
public IEnumerator<T> GetEnumerator()
{
VListNode<T> node = RootNode;
while (node != null)
{
foreach (T t in node)
yield return t;
node = node.Next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
public class VListNode<T> : IEnumerable<T>
{
readonly T[] Elements;
public VListNode<T> Next { get; private set; }
public int Count { get; private set; }
public int MaxSize { get; private set; }
public VListNode(int size, VListNode<T> next)
{
MaxSize = size;
Elements = new T[size];
Next = next;
}
public void Add(T element)
{
Elements[Count] = element;
Count++;
}
public IEnumerator<T> GetEnumerator()
{
// iterate in reverse to return elements in LIFO order.
for (int i = Count - 1; i >= 0; i--)
yield return Elements[i];
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
上面的简单实现应该支持 Add in O(1),同时保持良好的引用局部性。