Java 根据值集合的大小排序的映射
我试图创建一个排序映射Java 根据值集合的大小排序的映射,java,dictionary,java-7,treemap,sortedmap,Java,Dictionary,Java 7,Treemap,Sortedmap,我试图创建一个排序映射map,它根据值集的size()对元素进行排序 实际上,这是一个节点到连接到该节点的其他节点的映射。我希望快速(O(logn))访问具有最多边的节点,而无需每次排序 例如,订单应为: 3 => {1,2,4,5} 12 => {1,2,3} 14 => {3,2,3} 65 => {3,8} 6 => {2} 2 => {5} 由于TreeMap无法执行此操作,因为我无法基于值进行排序,因此我可能需要滚动一些自定义内容 编辑:集合的大小
map
,它根据值集的size()
对元素进行排序
实际上,这是一个节点到连接到该节点的其他节点的映射。我希望快速(O(logn))访问具有最多边的节点,而无需每次排序
例如,订单应为:
3 => {1,2,4,5}
12 => {1,2,3}
14 => {3,2,3}
65 => {3,8}
6 => {2}
2 => {5}
由于TreeMap
无法执行此操作,因为我无法基于值进行排序,因此我可能需要滚动一些自定义内容
编辑:集合的大小确实可能会改变,这可能会使事情变得更加复杂
实现这一目标的最简单方法是什么 下面是一个排序示例,说明如何使用两个集合进行排序。一个集合是按set::size排序的,另一个只是带有整数索引的普通映射。要使用它,必须在两个映射中保持相同的键/值对 我不确定我是否建议尝试用这个来制作一张地图。它有两个查找,按索引和按大小查找,所以它不像常规地图那样工作。这将取决于您的使用模式
package quicktest;
import static java.util.Comparator.comparing;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest
{
public static void main(String[] args) {
TreeMap<Integer,Set<Integer>> index = new TreeMap<>();
TreeMap<Set<Integer>,Integer> size = new TreeMap<>( comparing( Set::size ) );
for( int i = 0; i < 5; i++ ) {
Set<Integer> set = new HashSet<>();
for( int val = 0; val <= i; val++ ) {
set.add( val );
}
index.put( i, set );
size.put( set, i );
}
System.out.println( size.lastEntry() ); // largest set size
System.out.println( index.get( 2 ) ); // random index
}
}
packagequicktest;
导入静态java.util.Comparator.Comparating;
导入java.util.HashSet;
导入java.util.Set;
导入java.util.TreeMap;
公共类树形图
{
公共静态void main(字符串[]args){
树映射索引=新树映射();
TreeMap size=新的TreeMap(比较(Set::size));
对于(int i=0;i<5;i++){
Set=newhashset();
对于(int val=0;val这个呢
public class MapAndPriority {
Map<Integer, Set<Integer>> sets = new HashMap<Integer, Set<Integer>>();
PriorityQueue<Set<Integer>> byLength = new PriorityQueue<Set<Integer>>(1, new Comparator<Set<Integer>>() {
@Override
public int compare(Set<Integer> o1, Set<Integer> o2) {
// Compare in the reverse order!
return o2.size() - o1.size();
}
});
public void add(int i, Set<Integer> set) {
sets.put(i, set);
byLength.offer(set); // or Add, depending on the behavior you want
}
public Set<Integer> get(int i) {
return sets.get(i);
}
public Set<Integer> mostNodes() {
return byLength.peek();
}
public void remove(int i) {
// sets.remove will return the removed set, so that will be removed from byLength.
// Need to handle case when i does not exist as a key in sets
byLength.remove(sets.remove(i));
}
}
公共类映射和优先级{
映射集=新的HashMap();
PriorityQueue byLength=新的PriorityQueue(1,新的比较器(){
@凌驾
公共整数比较(集合o1,集合o2){
//按相反的顺序比较!
返回o2.size()-o1.size();
}
});
公共无效添加(int i,集合){
集合。放置(i,集合);
offer(set);//或Add,具体取决于您想要的行为
}
公共集get(int i){
返回集。获取(i);
}
公共集mostNodes(){
返回byLength.peek();
}
删除公共空间(int i){
//sets.remove将返回已删除的集,因此将从byLength中删除该集。
//当我不是集合中的键时,需要处理此情况
长度移除(集合移除(i));
}
}
如果我了解你想要什么,那么这将:
在o(nlog(n))中添加新集合
常规映射get()
将获得o(log(n))中的最大集合(mostNodes()
)
我所做的是将所有集合放在一个优先级队列中(沿着地图),然后给优先级队列一个比较器,该比较器根据大小进行比较,因此较小的大小就是“较大的”。这样,当您调用peek()
时,它将返回优先级队列中的“最小”值,由于我们的比较器,它将是最长的集合。
我并没有处理所有类型的边缘情况(比如清空时删除)
您可以查看以了解更多详细信息和复杂性。什么意思TreeMap
不起作用?您可以使用自定义比较器。@markspace比较器只允许我按键排序(除非我想采用另一种丑陋/不可靠的破解/解决方案)反转键和值。你说过要按大小查找,对吗?所以请使用两个映射。一个按集合大小排序,一个按节点ID索引。这是最简单的方法。@Konstantinoschalkia是的,现在我想它确实可能会改变,可能会使事情更加复杂。只有在插入Set.size后不更改它,这才有效ed,因为排序键(大小)是可变的。在从每个集合中添加/删除元素时,您需要进行适当的控制。或者在插入集合之前复制集合,以便以后的更改不会影响已存储的集合。我倾向于这样做。但OP希望在插入后更新indexMap;因此,获取、更改(添加/删除元素)然后返回存储这基本上就是我所说的。你的意思是不需要获取/更改/放置周期?我看不到解决方法。如果你尝试向哈希集添加“控制”,你会将一个O(1)算法更改为O(logn),其中n是系统中存储的集合总数。这看起来很糟糕,而且不灵活。不,我说这是需要的(我解释需要做什么)。我不明白插入前的克隆如何帮助我在实现中发现一个小错误。如果在插入后更改集合,则调用mostNodes
将不起作用。如果希望能够在插入后更改集合,则可以向MapAndPriority
添加另一个方法,该方法可以在集合中添加/删除元素。它然后将需要从优先级队列中删除该集合,对其进行更改,然后重新添加。只有在您确定没有其他人可以访问任何集合并在不调用建议的添加/删除方法的情况下更改其大小时,您的修复建议才会起作用。我想观察者模式将为此问题提供更合适的解决方案我不能为我的建议辩护,但一般来说,你只能公开这个类,让getter返回只读副本。