在运行时更改树图的比较器
Change comparator of treemap during runtime
我看到设置比较器的唯一方法是通过 TreeMap 构造函数。例如:
TreeMap myMap = new TreeMap(myComparator);
但是,我想决定在运行时使用什么类型的比较器。我可以创建多个 TreeMap 或一个的新实例,但我发现它会留下更大的内存占用空间。
有办法实现吗?还是我这边有设计缺陷?
我建议您推迟 TreeMap
的创建,直到您知道哪个 Comparator
是合适的。如果这是不可能的(例如,因为您需要使用对 TreeMap
的引用来初始化其他对象),请考虑将 TreeMap
隐藏在将延迟初始化它的方法或 class 后面,或者使用工厂模式。
如果这也是不可能的,请使用您自己的 Comparator
实现来初始化 TreeMap
,并在那里做出决定(compareTo()
在您开始向其中添加项目之前不会被调用TreeMap
)。如果你走这条路,你必须非常小心,不要在你开始向树中添加项目后改变比较器的行为!
至于 为什么 TreeMap
(或大多数其他采用 Comparator
的集合)不允许您更改 Comparator
,请参阅@Evgeniy Dorofeev 的回答。
TreeMap 不允许更改 Comparator,因为内部树结构依赖于 Comparator,更改它会使内部树无效。
您可以按如下方式实现您的比较器:
//first impl
final Comparator<String> first = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
//second impl
final Comparator<String> second = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
Comparator<String> inst=first;
//Treemap initialization
TreeMap<String, String> t = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//call of the impl
return inst.compare(o1, o2);
}
});
.....
//switch during runtime
inst = second;
....
你可以这样做:
class MyCompartor<T> implements Comparator<T> {
Comparator<T> changeableComparator;
public void setComparator(Comparator<T> comparator) {
this.changeableComparator = comparator;
}
@Override
public int compare(T o1, T o2) {
return changeableComparator.compare(o1, o2);
}
}
但这太疯狂了。您不能也不得在运行时更改 TreeMap
的 Comparator
。树不会根据新的 Comparator
.
自行重组
相反,为每个新的 Comparator
创建一个新的 TreeMap
(也就是说,如果您无法像其他人建议的那样在已知比较类型时初始化映射)。
或者,将 TreeMap 子类化并添加一个具有上述可变 Comparator
的重组方法,但实际上这与创建新的 TreeMap
几乎相同(性能方面)。您唯一要消除的是内存分配。
我看到设置比较器的唯一方法是通过 TreeMap 构造函数。例如:
TreeMap myMap = new TreeMap(myComparator);
但是,我想决定在运行时使用什么类型的比较器。我可以创建多个 TreeMap 或一个的新实例,但我发现它会留下更大的内存占用空间。
有办法实现吗?还是我这边有设计缺陷?
我建议您推迟 TreeMap
的创建,直到您知道哪个 Comparator
是合适的。如果这是不可能的(例如,因为您需要使用对 TreeMap
的引用来初始化其他对象),请考虑将 TreeMap
隐藏在将延迟初始化它的方法或 class 后面,或者使用工厂模式。
如果这也是不可能的,请使用您自己的 Comparator
实现来初始化 TreeMap
,并在那里做出决定(compareTo()
在您开始向其中添加项目之前不会被调用TreeMap
)。如果你走这条路,你必须非常小心,不要在你开始向树中添加项目后改变比较器的行为!
至于 为什么 TreeMap
(或大多数其他采用 Comparator
的集合)不允许您更改 Comparator
,请参阅@Evgeniy Dorofeev 的回答。
TreeMap 不允许更改 Comparator,因为内部树结构依赖于 Comparator,更改它会使内部树无效。
您可以按如下方式实现您的比较器:
//first impl
final Comparator<String> first = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
//second impl
final Comparator<String> second = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
Comparator<String> inst=first;
//Treemap initialization
TreeMap<String, String> t = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//call of the impl
return inst.compare(o1, o2);
}
});
.....
//switch during runtime
inst = second;
....
你可以这样做:
class MyCompartor<T> implements Comparator<T> {
Comparator<T> changeableComparator;
public void setComparator(Comparator<T> comparator) {
this.changeableComparator = comparator;
}
@Override
public int compare(T o1, T o2) {
return changeableComparator.compare(o1, o2);
}
}
但这太疯狂了。您不能也不得在运行时更改 TreeMap
的 Comparator
。树不会根据新的 Comparator
.
相反,为每个新的 Comparator
创建一个新的 TreeMap
(也就是说,如果您无法像其他人建议的那样在已知比较类型时初始化映射)。
或者,将 TreeMap 子类化并添加一个具有上述可变 Comparator
的重组方法,但实际上这与创建新的 TreeMap
几乎相同(性能方面)。您唯一要消除的是内存分配。