SortedDictionary
(.NET 2+)或SortedSet
(仅限.NET 4)可能是您想要的。它们都是树形结构。
SortedList
是一个愚蠢的类,与List
在结构上没有任何区别。
然而,我仍然不完全清楚为什么您需要这个排序列表。
也许如果您能详细说明一下,我们可以找到一个解决方案,您根本不需要排序。例如,一个简单的HashSet
就可以做到。如果哈希处理得当,它在查找和插入方面都比SortedList
或任何树形结构更快。
好的,现在我明白您想要合并排序列表了,我可以尝试编写一个实现。
首先,我使用SortedDictionary
来存储所有数组的头部,并实现了合并。在每次迭代中,我从字典中删除最小的元素,并添加相同数组中的下一个元素。性能测试表明,SortedDictionary
的开销巨大,几乎不可能比简单的连接+排序更快。它甚至难以匹配小型测试中SortedList
的性能。
接着我用自己实现的二叉堆替换了SortedDictionary
。性能提升非常巨大(超过6倍)。这个堆实现甚至在一些测试中都能击败.Distinct()
(通常是最快的)。
下面是我的代码:
class Heap<T>
{
public Heap(int limit, IComparer<T> comparer)
{
this.comparer = comparer;
data = new T[limit];
}
int count = 0;
T[] data;
public void Add(T t)
{
data[count++] = t;
promote(count-1);
}
IComparer<T> comparer;
public int Count { get { return count; } }
public T Pop()
{
T result = data[0];
fill(0);
return result;
}
bool less(T a, T b)
{
return comparer.Compare(a,b)<0;
}
void fill(int index)
{
int child1 = index*2+1;
int child2 = index*2+2;
if(child1 >= Count)
{
data[index] = data[--count];
if(index!=count)
promote(index);
}
else
{
int bestChild = child1;
if(child2 < Count && less(data[child2], data[child1]))
{
bestChild = child2;
}
data[index] = data[bestChild];
fill(bestChild);
}
}
void promote(int index)
{
if(index==0)
return;
int parent = (index-1)/2;
if(less(data[index], data[parent]))
{
T tmp = data[parent];
data[parent] = data[index];
data[index] = tmp;
promote(parent);
}
}
}
struct ArrayCursor<T>
{
public T [] Array {get;set;}
public int Index {get;set;}
public bool Finished {get{return Array.Length == Index;}}
public T Value{get{return Array[Index];}}
}
class ArrayComparer<T> : IComparer<ArrayCursor<T>>
{
IComparer<T> comparer;
public ArrayComparer(IComparer<T> comparer)
{
this.comparer = comparer;
}
public int Compare (ArrayCursor<T> a, ArrayCursor<T> b)
{
return comparer.Compare(a.Value, b.Value);
}
}
static class HeapMerger
{
public static IEnumerable<T> MergeUnique<T>(this T[][] arrays)
{
bool first = true;
T last = default(T);
IEqualityComparer<T> eq = EqualityComparer<T>.Default;
foreach(T i in Merge(arrays))
if(first || !eq.Equals(last,i))
{
yield return i;
last = i;
first = false;
}
}
public static IEnumerable<T> Merge<T>(this T[][] arrays)
{
var map = new Heap<ArrayCursor<T>>(arrays.Length, new ArrayComparer<T>(Comparer<T>.Default));
Action<ArrayCursor<T>> tryAdd = (a)=>
{
if(!a.Finished)
map.Add(a);
};
for(int i=0;i<arrays.Length;i++)
tryAdd(new ArrayCursor<T>{Array=arrays[i], Index=0});
while(map.Count>0)
{
ArrayCursor<T> lowest = map.Pop();
yield return lowest.Value;
lowest.Index++;
tryAdd(lowest);
}
}
}