任何.net集合,其复杂度为0(1)或O(Logn),用于查找和删除,添加和插入

时间:2015-01-21 12:26:47

标签: c# .net generics collections observablecollection

我遇到了一个非常奇怪的情况,我创建了一个类ObservableList看起来如下所示

class observableList<T>:IObservableList<T>, IList, IUserCollectionType 
{

  private List<T> _list;

  private HashSet<T> _containedElements

// for each operation add,insert,remove I keep HashSet and List in synch.
}

}

我需要HashSet来快速查找,但HashSet不是有序集合,我需要列表,因为我需要引发CollectionChanged事件,但它需要item的索引。因此,为了订购我必须采取列表并快速查找我必须采取HashSet,

但是现在,我遇到了一个问题,即从列表中删除O(n)。首先我必须得到索引,然后使用removeAt()方法,我必须得到索引,因为我不得不提出收集更改事件。

现在,我正在寻找一种具有O(1)或O(Logn)复杂性的解决方案,用于查找以及删除也具有排序功能。 我无法使用dicitonary,因为如果我将索引作为键,并删除任何项目,那么我必须将项目键更新为1.

**那么,为什么我们没有O(1)或附近的集合

1。对于查找
 2.对于拆卸,添加和插入  3.应该订购收集

在Java中,有人告诉我可能有一个类Linkedhashmap,但我不确定。那么,.NET是否有此集合的替代品。

或者我们是否有任何类似的集合的开源库。

1 个答案:

答案 0 :(得分:2)

通过在.Net的LinkedHashSetLinkedList<T>类中构建类似于Java Dictionary<K,V>的内容,您可以获得所要求的性能。这可以为您提供O(1)查找,插入和删除,以及保留插入顺序。

我正在草拟下面的这个解决方案;请注意,这会遗漏一些问题,例如检查重复元素,或实际实现IObservableList部分以及您可能需要的其他一些方法。另请注意,这基本上是伪代码,我没有编译或测试它。

class LinkedHashSet<T>
{
    private LinkedList<T> _list;
    private Dictionary<T, LinkedListNode<T>> _containedElements

    public void Add(T value)
    {
        LinkedListNode<T> newNode = _list.AddLast(value);
        _containedElements[value] = newNode;
    }

    public void Remove(T value)
    {
        LinkedListNode<T> node = _containedElements[value];
        _containedElements.Remove(value);
        _list.Remove(node);
    }

    public bool Contains(T value)
    {
        return _containedElements.ContainsKey(value);
    }
}

编辑:解决整个问题

正如我在评论中已经说过的那样,我注意到上述问题不是一个完整的解决方案,因为问题还涉及一个额外的操作:在列表中查找给定项目的索引(至少在删除的背景。)

我没有完全解决的解决方案,但我确实有一个可能有效的想法,所以这里是让这个答案更完整:

您可以使用平衡二叉树结构(例如红黑树)替换上例中的LinkedList。此树中的每个节点都引用一个值(就像链接列表中的每个节点一样),并且每个节点还会在树中存储其后代的计数。

您可以在O(log(n))时间内通过索引i找到任何元素,方法是从根目录开始,并在左侧保留最多i个节点。由于每个节点都有助于告诉您下降的计数,因此您只需要查看遇到的每个节点的左子节点,以确定是否需要向左或向右继续(或者当前节点包含您的目标)。

在红黑树中照常插入或删除元素,但需要更新所有受影响节点及其祖先的下降计数。我没有完全解决这个问题,但我很确定在O(log(n))时间内这仍​​然是可能的,就像在“普通”的红黑树一样。

最后,您可以在O(log(n))时间内找到任何元素的索引,方法是从其节点开始并向上走树,计算左侧的所有节点(再次使用每个节点的下降计数)节点)。在上面的例子中,节点本身将被字典引用,这样你就可以有效地找到它。

总结,将上面示例中的LinkedList替换为此处描述的树数据结构将为您提供O(log(n))插入,删除,按值查找索引和通过索引进行值查找,O(1)遍历(摊销),O(1)包含检查,所有假设字典操作都使用O(1)。