Java 按树形图中的键排序自定义数据结构

Java 按树形图中的键排序自定义数据结构,java,sorting,treemap,Java,Sorting,Treemap,我正试着把一个树形图按键排序。键是一些具有int、List、String等的自定义数据结构。 我希望排序的成员有一些重复项。假设这个成员是等级。多个对象可以具有相同的秩 简化版本示例: 注意:在CompareTo中,不会有意返回0以下的方法,以避免忽略重复项。(如果这不是避免重复项的正确方法,请更正我) import java.util.TreeMap; 公共类树测试{ 公共静态void main(字符串[]args){ TreeMap t=新的TreeMap(); 自定义c1=新自定义();

我正试着把一个树形图按键排序。键是一些具有int、List、String等的自定义数据结构。 我希望排序的成员有一些重复项。假设这个成员是等级。多个对象可以具有相同的秩

简化版本示例:

注意:在CompareTo中,不会有意返回0以下的方法,以避免忽略重复项。(如果这不是避免重复项的正确方法,请更正我)

import java.util.TreeMap;
公共类树测试{
公共静态void main(字符串[]args){
TreeMap t=新的TreeMap();
自定义c1=新自定义();
c1.设定名称(“a”);
c1.setRank(0);
自定义c2=新自定义();
c2.设定名称(“b”);
c2.setRank(1);
自定义c3=新自定义();
c3.设定名称(“c”);
c3.setRank(0);
t、 put(c1,“第一”);
t、 put(c2,“第二”);
t、 put(c3,“第三”);
System.out.println(t.keySet());
对于(自定义c:t.keySet()){
系统输出println(t.get(c));
}
}
}
和自定义对象

package com.example.ui;

 public class Custom implements Comparable<Custom>{

int rank;
String name;

public int getRank() {
    return rank;
}

public void setRank(int rank) {
    this.rank = rank;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}



@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + rank;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Custom other = (Custom) obj;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    if (rank != other.rank)
        return false;
    return true;
}

    // 0 is not returned intentionally to NOT ignore duplicates.
 public int compareTo(Custom o) {
    if(o.rank>this.rank)
        return 1;
    if(o.rank==this.rank)
        return -1;
    return -1;
 }
 }
package com.example.ui;
公共类自定义实现{
整数秩;
字符串名;
public int getRank(){
返回等级;
}
公共无效设置秩(整数秩){
这个.等级=等级;
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
@凌驾
公共int hashCode(){
最终整数素数=31;
int结果=1;
result=prime*result+((name==null)?0:name.hashCode();
结果=素数*结果+秩;
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj)
返回true;
if(obj==null)
返回false;
如果(getClass()!=obj.getClass())
返回false;
自定义其他=(自定义)对象;
if(name==null){
if(other.name!=null)
返回false;
}如果(!name.equals(other.name))
返回false;
if(秩!=其他.rank)
返回false;
返回true;
}
//不是有意返回0以不忽略重复项。
公共整数比较(自定义o){
如果(o.rank>this.rank)
返回1;
if(o.rank==this.rank)
返回-1;
返回-1;
}
}
输出::

[com.example.ui.Custom@fa0, com.example.ui.Custom@fbe, com.example.ui.Custom@f80] null null null [com.example.ui。Custom@fa0,com.example.ui。Custom@fbe,com.example.ui。Custom@f80] 无效的 无效的 无效的 预期: 第一、第二、第三分别基于等级0、1、0

我看了谷歌上的几个例子。它们中的大多数都是在TreeMap排序上的基本用法,使用带有原始数据类型的键或值,但在对成员进行排序时,没有一个具有重复项 是自定义密钥数据结构的一部分


请帮助?

问题是您对
compareTo
的实现与equals不一致,这是所需的。从API文档中:

请注意,排序由排序映射维护(无论是否为 如果提供了显式比较器,则必须与equals一致 此排序映射用于正确实现映射接口

一种可能的一致性实现是,如果秩值相等,则首先按秩进行比较,然后按名称进行比较。对于具有相同等级和相同名称的两个自定义实例,您不应期望能够将它们作为键存储在同一映射中-这违反了映射的约定

public int compareTo(Custom o) {
  int ret = this.rank - o.rank;

  // Equal rank so fall back to comparing by name.
  if (ret == 0) {
    ret = this.name.compareTo(o.name);
  }

  return ret;
}

如前所述,equals和compareTo的实现彼此不一致。如果我没有看错您的问题,您需要的是保留具有相同密钥的副本。我建议你调查一下谷歌番石榴的收藏。它为每个值对象创建集合容器,以便保留具有相同键的不同值。 e、 g

该数据结构中的约束条件是K,V对必须是唯一的。也就是说,不能在多重贴图中插入(“rank1”、“Joe”)两次


一个重要的注意事项:您看到这么多使用简单类型,特别是字符串的Map示例的原因是Map中的键必须是不可变的。对象的equals和hashcode值在用作映射中的键时不得更改。转换到您的示例中,您无法执行
customObject.setRank(…)
操作并在将秩值用作键时更新它。为此,您首先需要删除键及其值,对其进行更新,然后再次插入。

您还可以通过将Comparator实现为匿名内部类型并重写compare()来返回所需的比较

public class TreeMaps 
{
    public static void main(String[] args) 
    {
    Custom c1 = new Custom(1,"A");
    Custom c2 = new Custom(3,"C");
    Custom c3 = new Custom(2,"B");

    TreeMap<Custom , Integer > tree = new TreeMap<Custom, Integer>  (new Comparator<Custom>() {

                                            @Override
                                            public int compare(Custom o1, Custom o2) {

                                                return o1.rank - o2.rank;
                                            }
                                        });
    tree.put(c1, 1);
    tree.put(c2, 2);
    tree.put(c3, 3);

    System.out.println(tree);
}
}

class Custom
{
int rank ; 
String name  ; 
public Custom(int rank , String name) {
    this.rank = rank ;
    this.name = name ;

}

@Override
public String toString()
{
    return "Custom[" + this.rank + "-" + this.name + "]" ;
}
}
公共类树映射
{
公共静态void main(字符串[]args)
{
海关c1=新海关(1,“A”);
自定义c2=新自定义(3,“C”);
自定义c3=新自定义(2,“B”);
树映射树=新树映射(新比较器(){
@凌驾
公共整数比较(自定义o1、自定义o2){
返回o1.rank-o2.rank;
}
});
树.put(c1,1);
树。put(c2,2);
树。put(c3,3);
System.out.println(树);
}
}
阶级风俗
{
整数秩;
字符串名;
公共自定义(整数秩、字符串名){
这个.等级=等级;
this.name=名称;
}
@凌驾
公共字符串toString()
{
返回“Custom[”+this.rank+“-”+this.name+“]”;
}
}

首先,您的print语句应该是
System.out.println(c.getName())+1。另一个问题是,对于具有相同秩的两个对象,您返回-1,这意味着您处于同时具有
a
B
的情况,这违反了Comparable的约定。这假设您不能从
this.rank-o.rank
获得溢出。这可能是一个安全的假设。即使它是一个
int
它也可能不需要。@Peter-Fair point,老实说,我这样做是为了保持示例代码小。
treeMultimap.put ("rank1", "Joe");
treeMultimap.put ("rank1", Jane");
treeMultimap.get ("rank1"); // Set("Joe","Jane");
public class TreeMaps 
{
    public static void main(String[] args) 
    {
    Custom c1 = new Custom(1,"A");
    Custom c2 = new Custom(3,"C");
    Custom c3 = new Custom(2,"B");

    TreeMap<Custom , Integer > tree = new TreeMap<Custom, Integer>  (new Comparator<Custom>() {

                                            @Override
                                            public int compare(Custom o1, Custom o2) {

                                                return o1.rank - o2.rank;
                                            }
                                        });
    tree.put(c1, 1);
    tree.put(c2, 2);
    tree.put(c3, 3);

    System.out.println(tree);
}
}

class Custom
{
int rank ; 
String name  ; 
public Custom(int rank , String name) {
    this.rank = rank ;
    this.name = name ;

}

@Override
public String toString()
{
    return "Custom[" + this.rank + "-" + this.name + "]" ;
}
}