代码之家  ›  专栏  ›  技术社区  ›  Timwi

为什么.NET中没有sortedList<t>[关闭]

  •  27
  • Timwi  · 技术社区  · 15 年前

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

    根据 the MSDN documentation on SortedList ,它实际上在内部实现为动态大小的 KeyValuePair<TKey, TValue> 总是按键排序。同一个类是否比任何类型的列表更有用? T ?这是否也更适合这个名字?

    6 回复  |  直到 7 年前
        1
  •  10
  •   Gabe Timothy Khouri    15 年前

    虽然没人能真正告诉你为什么没有 SortedList<T> ,可以讨论原因 SortedList 获取一个键和一个值。字典将键映射到值。实现这一点的典型方法是使用二叉树、哈希表和列表(数组),尽管哈希表最常见,因为它们对于大多数操作都是O(1)。

    它在O(1)中不支持的主要操作是按顺序获取下一个键。如果你想做到这一点,你通常会使用二叉树,给你一个经过排序的字典。

    如果您决定将映射实现为一个列表,那么您将保留按键排序的元素,以便查找为O(lg n),从而为您提供另一个排序字典——以排序列表的形式。当然是名字 SortedDictionary 已经被带走了,但是 有序列表 不是的,我可能会叫它 SortedListDictionary SortedDictionaryList 但我没能说出它的名字。

        2
  •  4
  •   Tal Aloni    9 年前

    现在有:

    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;
            }
        }
    }
    
        3
  •  2
  •   Dan Tao    15 年前

    我想原因可能就是 List<T> 已经拥有 BinarySearch Insert ,这意味着实现自己的总是排序的列表是微不足道的。

    不是说这意味着 SortedList<T> 类不属于框架——只是它可能不是一个很高的优先级,因为任何需要它的开发人员都可以很容易地快速地编写它。

    我认为同样的情况也适用于 HashSet<T> ,因为您可以轻松地使用 Dictionary<T, byte> (例如)模拟.NET 3.5之前的版本。

    我知道这就是我在这两个案例中所做的:我有一个 UniqueSet<T> 类与安 AlwaysSortedList<T> 类,它刚刚包装了一个 字典<t,字节> 和A 列表& T; (使用) 二进制搜索 插入 ,分别为。

        4
  •  2
  •   Alex D.    8 年前

    我认为解决这个问题的方法是实现一个扩展方法 List<T> 以排序方式(仅2行代码;),然后 列表& 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);
        }
    
        5
  •  1
  •   tvanfosson    15 年前

    它是一个由键进行排序的列表。我只是在推测,但是通过提供指定与元素分离的键的能力,您的元素不必具有可比性——只需要键。我可以想象,在一般情况下,这节省了大量用于实现IComparable的代码,因为密钥可能是一种已经可以比较的类型。

        6
  •  0
  •   Matt Fenwick sagarcool89    14 年前

    RPM注释非常有效。此外,对于LINQ扩展,可以使用sort扩展方法按t的任何属性进行排序。我认为这可能是背后的主要原因。

    推荐文章