我需要根据它们的内容对某些对象进行排序(实际上根据它们的一个属性,这不是关键,可能在不同对象之间重复)。
.NET提供了两个类(SortedDictionary和SortedList),并且都使用二叉树实现。它们之间的唯一区别是
我可以使用List,实现我想要的效果,然后将Sort()方法与IComparer的自定义实现一起使用,但它不会节省时间,因为我会排序每次我想要插入一个新对象时,整个列表,而一个好的SortedList只会将该项插入正确的位置。
我需要的是一个带有RefreshPosition(int索引)的SortedList类,它只移动已更改(或插入)的对象,而不是每次内部对象更改时都使用整个列表。
我错过了一些明显的东西吗?
答案 0 :(得分:10)
也许我很慢,但这个是最简单的实现吗?
class SortedList<T> : List<T>
{
public new void Add(T item)
{
Insert(~BinarySearch(item), item);
}
}
http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx
不幸的是,Add
无法覆盖,所以我不得不new
当你List<T> list = new SortedList<T>;
我真的需要做的时候这不太好....所以我继续前进并重建了整个事情......
class SortedList<T> : IList<T>
{
private List<T> list = new List<T>();
public int IndexOf(T item)
{
var index = list.BinarySearch(item);
return index < 0 ? -1 : index;
}
public void Insert(int index, T item)
{
throw new NotImplementedException("Cannot insert at index; must preserve order.");
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
public T this[int index]
{
get
{
return list[index];
}
set
{
list.RemoveAt(index);
this.Add(value);
}
}
public void Add(T item)
{
list.Insert(~list.BinarySearch(item), item);
}
public void Clear()
{
list.Clear();
}
public bool Contains(T item)
{
return list.BinarySearch(item) >= 0;
}
public void CopyTo(T[] array, int arrayIndex)
{
list.CopyTo(array, arrayIndex);
}
public int Count
{
get { return list.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
var index = list.BinarySearch(item);
if (index < 0) return false;
list.RemoveAt(index);
return true;
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
}
或许类似这样的事情是更恰当的Remove
函数......
public bool Remove(T item)
{
var index = list.BinarySearch(item);
if (index < 0) return false;
while (((IComparable)item).CompareTo((IComparable)list[index]) == 0)
{
if (item == list[index])
{
list.RemoveAt(index);
return true;
}
index++;
}
return false;
}
假设项目可以比较相等但不相等......
答案 1 :(得分:3)
前一段时间我问了一个类似的问题,还有一些good answers there。有很多集合here。
答案 2 :(得分:3)
我最终决定写下来:
class RealSortedList<T> : List<T>
{
public IComparer<T> comparer;
public int SortItem(int index)
{
T item = this[index];
this.RemoveAt(index);
int goodposition=FindLocation(this[index], 0, this.Count);
this.Insert(goodposition, item);
return goodposition;
}
public int FindLocation(T item, int begin, int end)
{
if (begin==end)
return begin;
int middle = begin + end / 2;
int comparisonvalue = comparer.Compare(item, this[middle]);
if (comparisonvalue < 0)
return FindLocation(item,begin, middle);
else if (comparisonvalue > 0)
return FindLocation(item,middle, end);
else
return middle;
}
}
答案 3 :(得分:2)
不要忘记将项目插入由数组支持的列表中可能是一项昂贵的操作 - 插入一堆项目然后排序可能会更快,除非您真的需要在每次操作后进行排序。
或者,您可以始终包装列表并使添加操作找到正确的位置并将其插入其中。
答案 4 :(得分:1)
我过去通过编写一个在IList上进行二进制搜索的扩展方法和另一个执行插入的方法解决了这个问题。您可以在CLR源中查找正确的实现,因为有一个仅适用于数组的内置版本,然后只需将其调整为IList上的扩展。
其中一个“应该已经在BCL中了”。
答案 5 :(得分:0)
我需要的是一个SortedList类 要移动的RefreshPosition(int index) 只有更改(或插入)的对象 而不是诉诸整个清单 每次内部对象发生变化时。
当此类更新使索引无效时,为什么要使用索引进行更新?真的,我认为通过对象引用更新会更方便。您可以使用SortedList执行此操作 - 只需记住您的Key
类型与从对象中提取可比较数据的函数的返回类型相同。
class UpdateableSortedList<K,V> {
private SortedList<K,V> list = new SortedList<K,V>();
public delegate K ExtractKeyFunc(V v);
private ExtractKeyFunc func;
public UpdateableSortedList(ExtractKeyFunc f) { func = f; }
public void Add(V v) {
list[func(v)] = v;
}
public void Update(V v) {
int i = list.IndexOfValue(v);
if (i >= 0) {
list.RemoveAt(i);
}
list[func(v)] = v;
}
public IEnumerable<T> Values { get { return list.Values; } }
}
我猜是这样的。