是否有可能创建一个具有log(n)复杂度的ArrayList属性的Map ?



我试图建立一个通用的数据结构,需要保持键和值,并在同一时间保持跟踪的索引,其中键和值被放在像arraylist做只是在复杂度为0 (log n)或更少。

我试图解决这个问题,并创建了各种TreeMaps,具有整数索引和值,反之亦然,与键相同。

为了更清楚,索引符号表示来自用户的插入顺序。所以如果我有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);
    }
    }

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

如果你同时在树和数组列表中存储对象,你仍然有在数组列表中定位对象的问题,我无法在少于O(n)的时间内以直接的方式工作。可能在ArrayList上有一些变化,也许是一个自定义构造,但这似乎需要做很多工作。

相反,我建议您考虑红黑树或类似的平衡树,其修改在红黑树通过有序索引访问时注意到:对于树的每个节点,也存储以给定节点为根的子树中的节点计数。在插入和删除操作期间,您必须更新受旋转操作影响的所有节点的计数。这仍然可以在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)时间内找到第二棵树中节点的"顺序统计量"。

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

在任何一棵树中删除之前,先将引用推迟到另一棵树中,然后删除第一棵树中的节点,然后删除另一棵树中相应的节点,这两个操作都是O(log n)。

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

可以吗?

最新更新