为什么.NET中没有SortedList <T>?

Tim*_*mwi 29 .net sortedlist base-class-library

为什么只有一个SortedList<TKey, TValue>看起来更像是字典,但SortedList<T>实际上只是一个总是排序的列表?

根据有关SortedList的MSDN文档,它实际上是在内部实现为动态大小的数组KeyValuePair<TKey, TValue>,始终按键排序.作为任何类型的列表,同一个类不会更有用T吗?那个名字也不合适吗?

Gab*_*abe 10

虽然没有人能真正告诉你为什么没有SortedList<T>,但有可能讨论为什么SortedList需要一个关键和一个值.字典将键映射到值.执行此操作的典型方法是使用二叉树,哈希表和列表(数组),但哈希表最常见,因为对于大多数操作它们都是O(1).

它在O(1)中不支持的主要操作是按顺序获取下一个键.如果您希望能够这样做,通常使用二叉树,为您提供排序字典.

如果您决定将映射实现为列表,则应保持元素按键排序,以便查找为O(lg n),以排序列表的形式为您提供另一个排序字典.当然这个名字SortedDictionary已经被采用,但SortedList事实并非如此.我可能把它称为SortedListDictionarySortedDictionaryList,但我没有去命名它.


Tal*_*oni 7

现在有:)

public class SortedList<T> : ICollection<T>
{
    private List<T> m_innerList;
    private Comparer<T> m_comparer;

    public SortedList() : this(Comparer<T>.Default)
    {
    }

    public SortedList(Comparer<T> comparer)
    {
        m_innerList = new List<T>();
        m_comparer = comparer;
    }

    public void Add(T item)
    {
        int insertIndex = FindIndexForSortedInsert(m_innerList, m_comparer, item);
        m_innerList.Insert(insertIndex, item);
    }

    public bool Contains(T item)
    {
        return IndexOf(item) != -1;
    }

    /// <summary>
    /// Searches for the specified object and returns the zero-based index of the first occurrence within the entire SortedList<T>
    /// </summary>
    public int IndexOf(T item)
    {
        int insertIndex = FindIndexForSortedInsert(m_innerList, m_comparer, item);
        if (insertIndex == m_innerList.Count)
        {
            return -1;
        }
        if (m_comparer.Compare(item, m_innerList[insertIndex]) == 0)
        {
            int index = insertIndex;
            while (index > 0 && m_comparer.Compare(item, m_innerList[index - 1]) == 0)
            {
                index--;
            }
            return index;
        }
        return -1;
    }

    public bool Remove(T item)
    {
        int index = IndexOf(item);
        if (index >= 0)
        {
            m_innerList.RemoveAt(index);
            return true;
        }
        return false;
    }

    public void RemoveAt(int index)
    {
        m_innerList.RemoveAt(index);
    }

    public void CopyTo(T[] array)
    {
        m_innerList.CopyTo(array);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        m_innerList.CopyTo(array, arrayIndex);
    }

    public void Clear()
    {
        m_innerList.Clear();
    }

    public T this[int index]
    {
        get
        {
            return m_innerList[index];
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return m_innerList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return m_innerList.GetEnumerator();
    }

    public int Count
    {
        get
        {
            return m_innerList.Count;
        }
    }

    public bool IsReadOnly
    {
        get
        {
            return false;
        }
    }

    public static int FindIndexForSortedInsert(List<T> list, Comparer<T> comparer, T item)
    {
        if (list.Count == 0)
        {
            return 0;
        }

        int lowerIndex = 0;
        int upperIndex = list.Count - 1;
        int comparisonResult;
        while (lowerIndex < upperIndex)
        {
            int middleIndex = (lowerIndex + upperIndex) / 2;
            T middle = list[middleIndex];
            comparisonResult = comparer.Compare(middle, item);
            if (comparisonResult == 0)
            {
                return middleIndex;
            }
            else if (comparisonResult > 0) // middle > item
            {
                upperIndex = middleIndex - 1;
            }
            else // middle < item
            {
                lowerIndex = middleIndex + 1;
            }
        }

        // At this point any entry following 'middle' is greater than 'item',
        // and any entry preceding 'middle' is lesser than 'item'.
        // So we either put 'item' before or after 'middle'.
        comparisonResult = comparer.Compare(list[lowerIndex], item);
        if (comparisonResult < 0) // middle < item
        {
            return lowerIndex + 1;
        }
        else
        {
            return lowerIndex;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @MariuszJamro,实际上`SortedList&lt;T&gt;` 不能实现`IList&lt;T&gt;`,因为有些操作在排序集合的上下文中没有意义——比如索引设置器、`InsertAt` 和`RemoveAt` (7认同)
  • @ironstone13 我认为实现 `RemoveAt(int index)` 没有问题,列表仍然会被排序。 (6认同)
  • 你可以实现 `IList&lt;T&gt;` 并在调用 `InsertAt()` 时抛出异常。虽然不理想,但这就是数组实现`IList&lt;T&gt;` 的方式,我认为比根本不实现接口更可取。 (4认同)
  • @Tal 你可以使用 BinarySearch 而不是 FindIndexForSortedInsert (3认同)
  • 未实现 IList 的列表。惊人的 :) (2认同)

Ale*_* D. 5

我认为解决这个问题的方法是实现一个List<T>以排序方式添加的扩展方法(只需 2 行代码;),然后List<T>可以用作排序列表(假设您避免使用List.Add(...)):

    public static void AddSorted<T>(this List<T> list, T value)
    {
        int x = list.BinarySearch(value);
        list.Insert((x >= 0) ? x : ~x, value);
    }
Run Code Online (Sandbox Code Playgroud)