Java 在对象更改值时维护树集排序
我有一个对象,它使用Comparable定义了“自然排序顺序”。 这些被储存在树丛中Java 在对象更改值时维护树集排序,java,collections,refresh,treeset,sortedset,Java,Collections,Refresh,Treeset,Sortedset,我有一个对象,它使用Comparable定义了“自然排序顺序”。 这些被储存在树丛中 除了删除和重新添加对象之外,当用于定义排序顺序的成员被更新时,还有其他方法更新排序吗?我认为没有现成的方法可以做到这一点 您可以使用观察者模式,当您更改元素内的值时,该模式会通知树集,然后它会删除并重新插入该值 通过这种方式,您可以隐式地对列表进行排序,而无需手动操作。。当然,这种方法需要通过修改插入行为(在刚添加的项目上设置观察/通知机制)来扩展树集。唯一的内置方式是删除和重新添加。如果您确实需要使用集,那么
除了删除和重新添加对象之外,当用于定义排序顺序的成员被更新时,还有其他方法更新排序吗?我认为没有现成的方法可以做到这一点 您可以使用观察者模式,当您更改元素内的值时,该模式会通知树集,然后它会删除并重新插入该值
通过这种方式,您可以隐式地对列表进行排序,而无需手动操作。。当然,这种方法需要通过修改插入行为(在刚添加的项目上设置观察/通知机制)来扩展树集。唯一的内置方式是删除和重新添加。如果您确实需要使用
集,那么我想您就不走运了
不过,我要加入一个通配符-如果您的情况足够灵活,可以使用列表而不是集合
,那么您可以使用Collections.sort()
按需重新排序列表
。如果列表
顺序不需要太多更改,则应执行此操作。正如其他人所指出的,没有内置方式。但您始终可以使用您选择的构造函数对该树集进行子类化,并添加所需的功能:
public class UpdateableTreeSet<T extends Updateable> extends TreeSet<T> {
// definition of updateable
interface Updateable{ void update(Object value); }
// constructors here
...
// 'update' method; returns false if removal fails or duplicate after update
public boolean update(T e, Object value) {
if (remove(e)) {
e.update(value);
return add(e);
} else {
return false;
}
}
}
public类UpdateableTreeSet扩展TreeSet{
//可更新的定义
接口可更新{void update(对象值);}
//这里的构造器
...
//“update”方法;如果删除失败或更新后重复,则返回false
公共布尔更新(TE,对象值){
如果(删除(e)){
e、 更新(价值);
返回add(e);
}否则{
返回false;
}
}
}
从那时起,您必须调用((updateabletreset)mySet).update(anElement,aValue)
来更新排序值和排序本身。这确实需要您在数据对象中实现一个附加的update()
方法。这有助于了解对象将以小增量还是大增量进行更改。如果每个更改都很小,那么最好将数据放在一个列表中并保持排序。要做到这一点,你必须
binarySearch查找元素的索引
修改元素
当元素大于其右侧邻居时,将其与其右侧邻居交换
或者,如果没有发生这种情况:当元素小于其左侧邻居时,将其与其左侧邻居交换
但是你必须确保没有人可以在不经过“你”的情况下更改元素
编辑:还有!Glassed List对这一点有一定的支持:
我也遇到了类似的问题,找到了这个线程和tucuxi的答案(谢谢!),在此基础上我实现了自己的UpdateableTreeSet
。我的版本提供了
- 在这样一个集合上迭代
- 计划(延迟)循环内的元素更新/删除
- 无需创建集合的临时副本
- 循环结束后,作为批量操作执行所有更新/删除
UpdateableTreeSet
对用户隐藏了很多复杂性。除了延迟的批量更新/删除外,tucuxi所示的单元素更新/删除在类中仍然可用
更新2012-08-07:该课程提供了一些介绍性自述,其中包括原理图示例代码以及单元测试,详细说明了如何(不)使用它。当我试图实现类似于苹果iPhone滚轮滚动的动态滚动窗格时,我发现了这个问题。树集合中的项目属于此类:
/**
* Data object that contains a {@code DoubleExpression} bound to an item's
* relative distance away from the current {@link ScrollPane#vvalueProperty()} or
* {@link ScrollPane#hvalueProperty()}. Also contains the item index of the
* scrollable content.
*/
private static final class ItemOffset implements Comparable<ItemOffset> {
/**
* Used for floor or ceiling searches into a navigable set. Used to find the
* nearest {@code ItemOffset} to the current vValue or hValue of the scroll
* pane using {@link NavigableSet#ceiling(Object)} or
* {@link NavigableSet#floor(Object)}.
*/
private static final ItemOffset ZERO = new ItemOffset(new SimpleDoubleProperty(0), -1);
/**
* The current offset of this item from the scroll vValue or hValue. This
* offset is transformed into a real pixel length of the item distance from
* the current scroll position.
*/
private final DoubleExpression scrollOffset;
/** The item index in the list of scrollable content. */
private final int index;
ItemOffset(DoubleExpression offset, int index) {
this.scrollOffset = offset;
this.index = index;
}
/** {@inheritDoc} */
@Override
public int compareTo(ItemOffset other) {
double d1 = scrollOffset.get();
double d2 = other.scrollOffset.get();
if (d1 < d2) {
return -1;
}
if (d1 > d2) {
return 1;
}
// Double expression has yet to be bound
// If we don't compare by index we will
// have a lot of values ejected from the
// navigable set since they will be equal.
return Integer.compare(index, other.index);
}
/** {@inheritDoc} */
@Override
public String toString() {
return index + "=" + String.format("%#.4f", scrollOffset.get());
}
}
其中垂直偏移是一个树集
。如果你打印出
设置每次调用此更新代码段时,您都会看到它被更新。这样做没有多大好处-设置可以保证快速查找、插入和删除,而列表则需要先使用Collections.binarySearch来定位元素。我意识到这一点,这就是为什么我说“如果你的情况足够灵活的话”。性能要求可能不够宽松,因此允许使用列表
。@tucuxi列表中的二进制搜索为O(logn)。在树集中查找?还有O(log n)。@Kevin但是您必须完成实现add()、remove()和contains()版本的过程,这些版本在内部执行二进制搜索。本质上,您是在重新实现TreeSet,其中包含一个排序列表。这就是为什么我写道,移除和重新插入似乎更容易。不是因为性能,而是因为编码时间。我喜欢这样的想法,如果集合可以就地排序,而不是创建一个新实例。我认为这行不通。如果元素的值以影响排序顺序的方式更改,则很可能无法在树中找到或删除它。这只是病态的好奇,还是您在寻找特定的好处,比如说性能或代码的简单性?我在寻找一种简单的非侵入性方法,在事件更新集合中的对象时维护集合的排序顺序。更改成员资格会对收藏的其他消费者产生副作用。在我看来,触发元素调用似乎是排序集合的基本功能。GUI也有同样的问题,MVC就是解决方案。与TreeSet
相对应的GUI会定期调用update
,或者,如果某个值发生了变化,那么控制器(观察者模式)就会被模型触发,而体系结构非常准确地指出了这一点。TreeSet是我的DOTs模型,它监听websocket jms事件,然后通过presenter/controller中继模型更新
ItemOffset first = verticalOffsets.first();
verticalOffsets.remove(first);
verticalOffsets.add(first);