java—唯一包含键但在不同字段上排序的集

p4tfgftt  于 2021-06-29  发布在  Java
关注(0)|答案(5)|浏览(318)

我正在寻找一个java集合,可能在标准库中,它能够收集以下结构:

class Item {
    String key;
    double score;
}

并具有以下特性:
只允许一个具有相同密钥的项(如一个集合)
在max o(logn)中插入、删除、检查存在
按分数排序的遍历,在max o(logn)中查找下一个
据我所知,标准orderedset必须具有与equals()接口一致的可比较接口,但这不是我的情况,因为具有不同键的两个项可能具有相同的分数。
事实上,我注意到treeset使用返回0的比较器来检查项目是否已经存在。
有什么建议吗?

qlckcl4x

qlckcl4x1#

感谢那些让我思考他们的评论和回答的人。我相信我们可以通过使用:

TreeMap<Double, HashSet<Item>>

只是因为(我没有说过)两个相等的键产生相同的分数;但一般来说,有两个集合Map就足够了:一个(有序的)以有序字段作为键,另一个(不有序的)以唯一字段作为键。

hujrc8aj

hujrc8aj2#

我认为不存在这样的结构。您没有指定遍历性能要求,因此可以使用一个普通集,将值添加到列表中,并按遍历的分数对该列表进行排序。

cfh9epnr

cfh9epnr3#

哈希集不保证其元素的任何顺序。如果需要这种保证,可以考虑使用树集来保存元素,但要实现unique by键并保持恒定的时间覆盖 hashCode() 以及 equals() 有效地满足您的以下需求:

class Item {
    String key;
    double score;

    public Item(String key, double score) {
        this.key = key;
        this.score = score;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Item item = (Item) o;
        return key.equals(item.key);
    }

    @Override
    public int hashCode() {
        return Objects.hash(key);
    }

    @Override
    public String toString() {
        return "Item{" +
                "key='" + key + '\'' +
                ", score=" + score +
                '}';
    }
}

// main
public static void main(String[] args) {

        Set<Item> itemSet = new HashSet<>();

        itemSet.add(new Item("1", 1));
        itemSet.add(new Item("1", 2));
        itemSet.add(new Item("2", 1));

        //to get a sorted TreeSet
        //Add all your objects to the TreeSet, you will get a sorted Set.
        //TreeSet myTreeSet = new TreeSet();
        //myTreeSet.addAll(itemSet);
        //System.out.println(myTreeSet);
}

输出:

Item{key='1', score=1.0}
Item{key='2', score=1.0}
bttbmeg0

bttbmeg04#

现在insert已经放宽到o(logn),您可以使用一个双集来完成这项工作,即实现您自己的集,在幕后维护2个集。
最好是你能修改类 Item 实施 equals() 以及 hashCode() 只使用 key 现场。在这种情况下,你的班级将使用 HashSet 和一个 TreeSet . 如果 hashCode() 涵盖的不仅仅是 key 字段,然后使用两个 TreeSet 物体。

final class ItemSet implements NavigableSet<Item> {

    private final Set<Item> keySet = new HashSet<>();
    //                           or: new TreeSet<>(Comparator.comparing(Item::getKey));
    private final TreeSet<Item> navSet = new TreeSet<>(Comparator.comparingDouble(Item::getScore)
                                                                 .thenComparing(Item::getKey));

    //
    // Methods delegating to keySet for unique key access and for unordered access
    //

    @Override public boolean contains(Object o) { return this.keySet.contains(o); }
    @Override public boolean containsAll(Collection<?> c) { return this.keySet.containsAll(c); }
    @Override public int size() { return this.keySet.size(); }
    @Override public boolean isEmpty() { return this.keySet.isEmpty(); }

    //
    // Methods delegating to navSet for ordered access
    //

    @Override public Comparator<? super Item> comparator() { return this.navSet.comparator(); }
    @Override public Object[] toArray() { return this.navSet.toArray(); }
    @Override public <T> T[] toArray(T[] a) { return this.navSet.toArray(a); }
    @Override public Item first() { return this.navSet.first(); }
    @Override public Item last() { return this.navSet.last(); }
    @Override public Item lower(Item e) { return this.navSet.lower(e); }
    @Override public Item floor(Item e) { return this.navSet.floor(e); }
    @Override public Item ceiling(Item e) { return this.navSet.ceiling(e); }
    @Override public Item higher(Item e) { return this.navSet.higher(e); }

    //
    // Methods delegating to both keySet and navSet for mutation of this set
    //

    private final class ItemSetIterator implements Iterator<Item> {
        private final Iterator<Item> iterator = ItemSet.this.navSet.iterator();
        private Item keyToRemove;
        @Override
        public boolean hasNext() {
            return iterator.hasNext();
        }
        @Override
        public Item next() {
            keyToRemove = iterator.next();
            return keyToRemove;
        }
        @Override
        public void remove() {
            iterator.remove();
            ItemSet.this.keySet.remove(keyToRemove);
            keyToRemove = null;
        }
    }

    @Override
    public Iterator<Item> iterator() {
        return new ItemSetIterator();
    }
    @Override
    public void clear() {
        this.keySet.clear();
        this.navSet.clear();
    }
    @Override
    public boolean add(Item e) {
        if (! this.keySet.add(e))
            return false; // item already in set
        if (! this.navSet.add(e))
            throw new IllegalStateException("Internal state is corrupt");
        return true;
    }
    @Override
    public boolean remove(Object o) {
        if (! this.keySet.remove(o))
            return false; // item not in set
        if (! this.navSet.remove(o))
            throw new IllegalStateException("Internal state is corrupt");
        return true;
    }
    @Override
    public boolean addAll(Collection<? extends Item> c) {
        boolean changed = false;
        for (Item item : c)
            if (add(item))
                changed = true;
        return changed;
    }
    @Override
    public boolean removeAll(Collection<?> c) {
        boolean changed = false;
        for (Object o : c)
            if (remove(o))
                changed = true;
        return changed;
    }
    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public Item pollFirst() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public Item pollLast() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> descendingSet() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public Iterator<Item> descendingIterator() {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public SortedSet<Item> headSet(Item toElement) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> headSet(Item toElement, boolean inclusive) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public SortedSet<Item> tailSet(Item fromElement) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> tailSet(Item fromElement, boolean inclusive) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public SortedSet<Item> subSet(Item fromElement, Item toElement) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public NavigableSet<Item> subSet(Item fromElement, boolean fromInclusive, Item toElement, boolean toInclusive) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

}
xurqigkl

xurqigkl5#

只允许一个具有相同密钥的项(如一个集合)
你的 Item 类应该只使用 key 属性。
在固定时间内插入、移除、检查是否存在 TreeSet add()和remove()是o(ln n),因此它们不符合您的条件。 HashSet add()和remove()通常是o(1)。
按分数排序的遍历
你的表现要求是什么?您将多久遍历一次集合?如果您主要是添加和删除项目,很少遍历它,那么您可以制作 HashSetTreeSet 在遍历操作期间。

相关问题