【问题标题】:collection without duplicates but with order, with fast containment check and adding/removing [duplicate]没有重复但有顺序的集合,具有快速收容检查和添加/删除[重复]
【发布时间】:2017-10-06 15:24:46
【问题描述】:

我正在寻找一个具有快速包含检查和添加/删除方法的集合(如HashSet<T>,如果T 实施良好,则接近 O(1)),但这也有一个命令。这并不意味着索引访问 - 它只是意味着如果我迭代它,元素的顺序与我添加它们的顺序相同。

在 C# 中有类似的东西吗? HashSet<T> 甚至可以解决问题吗?(我在 MSDN 上找不到该信息,我查看了 HashSet<T>HashSet<T>.GetEnumerator。)

如果没有,我正在考虑使用包含内部HashSet<T> 和内部LinkedList<T> 的类来实现它。 HashSet<T> 将公开添加、删除和包含检查,而 LinkedList<T> 将公开枚举器。

【问题讨论】:

标签: c# collections


【解决方案1】:

您似乎正在寻找OrderedDictionary

唯一的缺点是它不支持泛型,但您可以轻松地对其进行包装或将值转换为您需要的类型。

编辑:正如 cmets 中提到的@Blorgbeard,您可以在another answer 中找到满足您确切要求的“OrderedSet”的实现(并使用@987654326 完全实现它@ 和 HashSet<T>),这可能对你有用。

这是他们的实现(感谢原作者,而不是我

public class OrderedSet<T> : ICollection<T>
{
    private readonly IDictionary<T, LinkedListNode<T>> m_Dictionary;
    private readonly LinkedList<T> m_LinkedList;

    public OrderedSet()
        : this(EqualityComparer<T>.Default)
    {
    }

    public OrderedSet(IEqualityComparer<T> comparer)
    {
        m_Dictionary = new Dictionary<T, LinkedListNode<T>>(comparer);
        m_LinkedList = new LinkedList<T>();
    }

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

    public virtual bool IsReadOnly
    {
        get { return m_Dictionary.IsReadOnly; }
    }

    void ICollection<T>.Add(T item)
    {
        Add(item);
    }

    public bool Add(T item)
    {
        if (m_Dictionary.ContainsKey(item)) return false;
        LinkedListNode<T> node = m_LinkedList.AddLast(item);
        m_Dictionary.Add(item, node);
        return true;
    }

    public void Clear()
    {
        m_LinkedList.Clear();
        m_Dictionary.Clear();
    }

    public bool Remove(T item)
    {
        LinkedListNode<T> node;
        bool found = m_Dictionary.TryGetValue(item, out node);
        if (!found) return false;
        m_Dictionary.Remove(item);
        m_LinkedList.Remove(node);
        return true;
    }

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

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

    public bool Contains(T item)
    {
        return m_Dictionary.ContainsKey(item);
    }

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

【讨论】:

  • 这将有 O(n) 添加和删除。
  • @Servy 你有任何证据证明你的主张吗?只有当您按键删除时,您才是正确的。对于其他操作,它是 O(1)。
  • 要添加一个项目,它需要在数组列表中搜索密钥对的索引,这是一个 O(n) 操作。您可以查看源代码以自己查看。你有任何证据证明它是 O(1) 吗?
  • 对我来说添加看起来像 O(1)(摊销)。来源:referencesource.microsoft.com/#System/compmod/system/…
  • 如果你认为另一个答案回答了这个问题,你应该投票关闭作为重复。只是逐字重复另一个答案是不合适的。
猜你喜欢
  • 2014-09-24
  • 2017-11-03
  • 1970-01-01
  • 2017-12-25
  • 2022-11-18
  • 1970-01-01
  • 2013-01-31
  • 2012-02-04
  • 1970-01-01
相关资源
最近更新 更多