具有快速查找的排序集(与HashSet一样快)?

时间:2014-07-23 22:44:50

标签: java algorithm data-structures hashmap treemap

我正在寻找能够满足这两个要求的某种设置数据结构:

  1. 排序
  2. O(1)for lookup
  3. 这是我到目前为止所得到的,但我真的希望有一个现有的,不那么尴尬的数据结构。

    /**
     * This MUST support both 
     * (1) Looking up by A - O(n)
     * (2) Iteration by sorted Foo<A, B>
     */
    public class MySet<Foo<A, B>> extends TreeSet<Foo<A, B>>
    { 
        private Map<A, Foo<A, B>> temp = new HashMap<A, Foo<A, B>>();
    
        public Foo<A, B> getNode(A a)
        {
           return temp.get(a);
        }
    
        @Override
        public boolean add(Foo<A, B> foo)
        {
           temp.put(foo.getA(), foo);
           return super.add(foo);
        }
    }
    

    我的Foo课程如下:

    public class Foo<A, B>
    {
        private A a; //Can NEVER be null
        private B b; //Can NEVER be null
    
        //... constructor and stuff omitted 
    
        public int compareTo(Foo<A, B> that)
        {
            if (this.equals(that))
               return 0;
    
            //Compare by a first
            int ret = this.a.compareTo(that);
            if (ret == 0)
                return 0;
    
            //Compare by b
            return this.b.compareTo(that.b);            
        }
    
        public boolean equals(Object obj)
        {
            if (!(obj instanceof Foo))
                return false;
    
            Foo rhs = (Foo) obj;
    
            return this.a.equals(rhs.a) && this.b.equals(rhs.b);
        }
    }
    

    更新

    以下是我的设置的用例:

    MySet<Foo<SomeA, SomeB>> mySet = getTheData(); //getTheData() returns a set with a bunch of Foo objects
    
    SomeA a = getA(); //getA() returns some instance of SomeA that I'm interested in
    

    我希望能够检查集合并RETRIEVE一个Foo对象(如果存在),以便Foo.getA()== a;

    mySet.getNode(a); 
    

2 个答案:

答案 0 :(得分:0)

你可以通过使用一些额外的空间来获得它。所以你需要一个HashSet。此外,每个元素都将指向排序顺序中的下一个值。我们假设您有键1,3,5,10,并且您正在使用线性探测。

value array   =  [3, 5, null, null, 10,   1];
pointer array =  [1, 4, null, null, null, 0];

因此值数组包含值。哈希函数决定值的位置。所以在上面的例子中,h(1)= 5(1进入索引5),h(3)= 0,h(5)= 1,h(10)= 4.索引2,3为零(未来元素的开放空间)。指针数组说明哪个元素在排序顺序中跟随当前元素。所以,让我们说我们正在做set.contains(3),它将导致计算h(3)(将产生0),并且我们知道该元素存在于集合中。如果我们想要按照排序顺序在元素集中的下一个元素,我们会查看指针数组中的值。因此对于值3(在值数组中的位置0),我们通过查找指针数组中的索引(pointer_array [0],即1)来获取排序顺序中的下一个元素,然后查找value_array [1],即5。

这是一个非常常见的实现。 Java的LinkedHashMap通常用作LRU缓存,它实现为哈希映射+双向链接密钥列表。双向链表中的键按其访问顺序排列。

在您的情况下,当您插入元素时,您需要调整非常慢的指针数组。你必须进行线性扫描。 如果这不是只读的,您可以使用以下方法

在您的数据结构中,有一个hashset和一个avl树,一个红黑树或任何其他平衡的二叉树。每当你进行containsKey测试时,它都是 O(1)。无论何时枚举,都可以使用二进制树在线性时间中按排序顺序遍历它们。无论何时插入新元素,还要将其插入二叉树和HashSet中。删除时,从哈希集和二叉树中删除该元素。因此删除和插入变为 O(log n)

答案 1 :(得分:-2)

我认为您应该尝试在google guava库中使用MultiMaps。 它的使用非常简单:

Map<Salesperson, List<Sale>> map = new Hashmap<SalesPerson, List<Sale>>();
public void makeSale(Salesperson salesPerson, Sale sale) {
    List<Sale> sales = map.get(salesPerson);
    if (sales == null) {
      sales = new ArrayList<Sale>();
      map.put(salesPerson, sales);
    }
    sales.add(sale);
}

可以替换为,

Multimap<Salesperson, Sale> multimap = new ArrayListMultimap<Salesperson,Sale>();
public void makeSale(Salesperson salesPerson, Sale sale) {
    multimap.put(salesperson, sale);
}

但是你必须要小心,多图将使用相同的键来保留条目,这与使用最新的等效键替换等效键的hashmaps不同。

Google Guava Libraries具有许多具有不同功能的其他数据结构。您可以在其维基上找到有关它的信息。

希望这有用。