2015-06-05 48 views
5

我想建立一个通用的数据结构,需要保存键和值,并在同一时间跟踪索引的哪些键和值放入像arraylist只做复杂的O(log n)或减。是否有可能创建具有log(n)复杂性的ArrayList属性的Map?

我尝试解决此问题的解决方案,并创建了具有整数的各种TreeMaps - 索引和valuse,反之亦然,并且与键相同。

为了更清楚起见,索引代表用户的插入顺序。所以如果我有3个元素,那么他们的索引是0 1 2,如果元素0被删除,那么我需要推1到0和2到1和一个新的元素将被添加索引2.

我的问题是什么时候我删除一个键和它的值,如果我想插入下一个键和值在正确的索引中,我必须确保所有的旧键都被设置回1.我不知道该怎么做,也不会掉下来变成O(n)复杂性。

我的目标是使用现有的数据结构并将它们混合以获得此结果,请参阅我实施的方法,因为我需要这些方法。

我加入我的代码以供参考,任何帮助将不胜感激。

谢谢

汤姆

import java.util.Collection; 
import java.util.HashMap; 
import java.util.TreeMap; 
import java.util.Map; 

public class SuperStruct<K,V> 
{ 
    private Map<K,V> mInternalKeyToValueMap;//all the keys and their values 
    private Map<Integer,V> mIndexToValueMap;//index's for values according to the entrance order to 
    private Map<V,Integer> mValueToIndexMap;//values and their index's 
    private Map<Integer,K> mIndexToKeyMap;//index's and their keys according to entrance order 
    private Map<K,Integer> mKeyToIndexMap;//keys and their index's 
    private int mNextIndex;//index for the data structure according to the order data was received by user 

    public SuperStruct(){ 
     mInternalKeyToValueMap = new TreeMap<K,V>(); 
     mIndexToValueMap = new TreeMap<Integer,V>(); 
     mValueToIndexMap = new TreeMap <V,Integer>(); 
     mIndexToKeyMap = new TreeMap <Integer, K>(); 
     mKeyToIndexMap = new TreeMap <K,Integer>();  
    } 
    public boolean containsKey(Object key) { 
     boolean containable = mInternalKeyToValueMap.containsKey(key); 
     return containable; 
    } 

    public boolean containsValue(Object value) { 
     boolean containable = mValueToIndexMap.containsKey(value); 
     return containable; 
    } 

    public V get(Object key) { 
     if(mInternalKeyToValueMap.containsKey(key)){ 
      V value = mInternalKeyToValueMap.get(key); 
      return value; 
     } 
     return null; 
    } 



    public Collection<K> keySet() { 

     return mInternalKeyToValueMap.keySet(); 
    } 
    /** 
    * This method is putting the key and the value in the main TreeMap "mInternalKeyToValueMap", while on the mean time updating 4 other TreeMaps 
    * with data regarding to the index in which data was received from the user. 
    * all in all this method runs in complexity of 6*(O(log n)) that sums down to O(log n) cause constants don't calculate over the whole 
    * Complexity calculation 
    * In case that a key already had a mapping to it and we overwrite the value we will run in complexity of 11*(O(log n)) which still sums down to O(log n) 
    * cause constants don't calculate over the whole 
    */ 

    public V put(K key, V value) { 
     if(mValueToIndexMap.containsKey(value))//preventing duplications of value 
      return value; 
      if(mInternalKeyToValueMap.containsKey(key)){//when a key already exist in system and we want to overwrite its value 
       int indexToDelete = mKeyToIndexMap.get(key);//we get the index of the value we over-write 
       V value1 = mIndexToValueMap.get(indexToDelete);//using this index we get the value 
       mValueToIndexMap.remove(value1);//we remove the value and its index 
       mIndexToValueMap.remove(indexToDelete);//we remove the index and its value 
      } 
      mInternalKeyToValueMap.put(key, value);//putting the new value for the key in the main TreeMap 
      mValueToIndexMap.put(value, mNextIndex);//populating the TreeMap of values and their index's - the order we received them from the user 
      mIndexToValueMap.put(mNextIndex, value);//This TreeMap holds the index's for each value according to the order of insertion by user 
      mIndexToKeyMap.put(mNextIndex, key);//This TreeMap holds the index's for each key according to the order of insertion by user 
      mKeyToIndexMap.put(key,mNextIndex);//populating the TreeMap of keys and their index's - the order we received them from the user 
      ++mNextIndex;//advancing the index which mark the insertion order of arguments to structure 
      return null; 

    } 


    public V remove(Object key) { 
     if(mInternalKeyToValueMap.containsKey(key)==true && (mInternalKeyToValueMap.get(key)!=null)) 
     { 
      V value = mInternalKeyToValueMap.get(key); 
      mInternalKeyToValueMap.remove(key);//removing map for the value 
      int mIndexToRemoveValue = mValueToIndexMap.get(value);//getting the right index to remove the value 
      mIndexToValueMap.remove(mIndexToRemoveValue);//vacating the value for this index 
      mIndexToKeyMap.remove(mIndexToRemoveValue);//vacating the key for this index 
      mKeyToIndexMap.remove(key);//removing a key and index in the keyToIndex Map 
      mValueToIndexMap.remove(value);//removing a key and index in the ValueToIndex Map 
      return value; 

     } 
     return null; 
    } 


    public Collection<V> values() {  
     return mInternalKeyToValueMap.values(); 
    } 

    public Collection<V> getStrcutureSorted(){ 
     return mValueToIndexMap.keySet(); 
    } 

    public V getValueByIndex(int index){//return the index in which the value sits in, if not present null 
     V value = mIndexToValueMap.get(index); 
      return value; 
    } 

    public Integer getIndexByKey(K key){ 
     Integer returnable = mKeyToIndexMap.get(key); 
     if(returnable == null) 
      return -1; 
     return returnable; 


    } 
    public K getKeyByIndex(int index){ 
     return mIndexToKeyMap.get(index); 
    } 
    } 
+0

https://stackoverflow.com/questions/44170832/access-tree-with-ordinal-index –

回答

2

这是一个有趣的难题。这感觉应该是可能的,但细节是难以捉摸的。问题出在删除后的索引更新操作中。例如,如果索引存储在树节点中,那么在删除操作之后,平均n/2个索引将不得不被更改,这会删除您正在争取的O(log n)属性。

如果将对象同时存储在树中和ArrayList中,则仍然存在在ArrayList中查找对象的问题,我无法以简单的方式在小于O(n)的时间内工作, 。可能在ArrayList上有一些变化,也许是一种自定义构造,但是这看起来像很多工作。

取而代之,我建议你考虑一个红黑树或类似的平衡树,其修改记录在Red-black tree access by ordinal index:对于树的每个节点,还存储以给定节点为根的子树中的节点数。在插入和删除操作期间,您必须更新受旋转操作影响的所有节点的计数。这仍然可以在O(log n)时间完成,但它很复杂。

然后按照通常的递归算法,二进制搜索第k个最小(或最大)元素也将在O(log n)时间内运行。

以下是该技术的更多参考文献:http://www.cs.usfca.edu/~galles/cs673/lecture/lecture8.pdf,http://fdatamining.blogspot.ca/2011/09/functional-red-black-tree-with-dynamic.html, http://en.wikipedia.org/wiki/Order_statistic_tree。这应该让你开始。

更新:实施细则

你将要做的是创建两棵树。其中一个可能是普通的平衡树(如红黑树),用键/值对来保存对象的引用。您可以搜索关键字并获取O(log n)中的对应值;插入和删除也将是O(log n)。另外,这第一棵树中的节点将持有对第二棵树中节点的引用(见下文)。

第二棵树也会保存对第一棵树中节点的引用,但是它会像上面讨论的那样是一个顺序统计树。插入将始终将新项目放在树的右端。

对这个数据结构的插入操作应该是按键插入到第一个树中,插入到顺序统计树的右侧,并且每个插入节点中的引用将被更新为指向适当的位置在另一棵树上。

可以在第一棵树上对O(log n)中的给定键执行搜索操作,该操作将返回适当的值,并且在对另一棵树的引用之后,可以用于查找“顺序统计量“在O(log n)时间中的第二棵树中的节点,通过遍历树到根并执行简单的计算。

可以在O(log n)时间的第二棵树上对队列中的第k个位置进行搜索操作,返回对第二棵树的引用,该引用可以被解引用以获得关联的键/值对。

在两棵树中删除之前都会先引用另一棵树,然后删除第一棵树中的节点,然后删除另一棵树中的对应节点,都是O(log n)操作。

我认为就是这样。一切都可以在O(log n)时间完成。第二棵树的空间很小,但只包含引用;空间仍然是O(n)。

运作的?

+0

我不确定这将在OP的情况下工作。其“索引”的概念是基于用于构造树的关键。 OP希望“索引”引用与插入顺序无关的插入顺序。 – ishnid

+1

是的,你说得对。但我有一个直觉,这可能会有所帮助。我认为它的确如此,但答案比我最初的答案更详细。我会在几分钟后发布更新。 –

+0

是的,我认为你的更新后的文章将工作。我在睡觉前发布了我的回复,并且今天早上一直在执行一个实施。我想出了与你的建议非常相似的东西。我认为唯一的变化是我有一个Entry类,它将关键字,值和引用存储到每个树中的适当节点。 – ishnid

相关问题