using System; using System.Collections; using System.Collections.Generic; namespace CollectionsExt { // 如果需要高频率的插入、删除、访问容器中的唯一数据,使用这个结构。比单独的List效率高,因为 // 哈希表的访问时间O(1)要快于遍历List确定数据唯一性的时间O(n) // 空间换时间,综合了list(数组)和字典(哈希表)的优点,支持 // 1. 快速的随机访问 // 2. 快速的插入和删除 // 3. 唯一值 // 4. 顺序遍历 // 5. 排序 internal class IndexedSet : IList { //This is a container that gives: // - Unique items // - Fast random removal // - Fast unique inclusion to the end // - Sequential access //Downsides: // - Uses more memory // - Ordering is not persistent // - Not Serialization Friendly. //We use a Dictionary to speed up list lookup, this makes it cheaper to guarantee no duplicates (set) //When removing we move the last item to the removed item position, this way we only need to update the index cache of a single item. (fast removal) //Order of the elements is not guaranteed. A removal will change the order of the items. readonly List m_List = new List(); Dictionary m_Dictionary = new Dictionary(); public void Add(T item) { m_List.Add(item); m_Dictionary.Add(item, m_List.Count - 1); } public bool AddUnique(T item) { if (m_Dictionary.ContainsKey(item)) return false; m_List.Add(item); m_Dictionary.Add(item, m_List.Count - 1); return true; } public bool Remove(T item) { int index = -1; if (!m_Dictionary.TryGetValue(item, out index)) return false; RemoveAt(index); return true; } public IEnumerator GetEnumerator() { throw new System.NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Clear() { m_List.Clear(); m_Dictionary.Clear(); } public bool Contains(T item) { return m_Dictionary.ContainsKey(item); } public void CopyTo(T[] array, int arrayIndex) { m_List.CopyTo(array, arrayIndex); } public int Count { get { return m_List.Count; } } public bool IsReadOnly { get { return false; } } public int IndexOf(T item) { int index = -1; m_Dictionary.TryGetValue(item, out index); return index; } public void Insert(int index, T item) { //We could support this, but the semantics would be weird. Order is not guaranteed.. throw new NotSupportedException("Random Insertion is semantically invalid, since this structure does not guarantee ordering."); } public void RemoveAt(int index) { T item = m_List[index]; m_Dictionary.Remove(item); if (index == m_List.Count - 1) m_List.RemoveAt(index); else { // 交换 int replaceItemIndex = m_List.Count - 1; T replaceItem = m_List[replaceItemIndex]; m_List[index] = replaceItem; m_Dictionary[replaceItem] = index; m_List.RemoveAt(replaceItemIndex); } } public T this[int index] { get { return m_List[index]; } set { T item = m_List[index]; m_Dictionary.Remove(item); m_List[index] = value; m_Dictionary.Add(item, index); // 这里有问题,应该是value } } public void RemoveAll(Predicate match) { //I guess this could be optmized by instead of removing the items from the list immediatly, //We move them to the end, and then remove all in one go. //But I don't think this is going to be the bottleneck, so leaving as is for now. int i = 0; while (i < m_List.Count) { T item = m_List[i]; if (match(item)) Remove(item); else i++; } } //Sorts the internal list, this makes the exposed index accessor sorted as well. //But note that any insertion or deletion, can unorder the collection again. public void Sort(Comparison sortLayoutFunction) { //There might be better ways to sort and keep the dictionary index up to date. m_List.Sort(sortLayoutFunction); //Rebuild the dictionary index. for (int i = 0; i < m_List.Count; ++i) { T item = m_List[i]; m_Dictionary[item] = i; } } } }