TreeSet CompareTo没有给出令人满意的结果

问题描述

我正在尝试创建字典中所有单词中所有字母的集合。

我为此使用TreeSet,因为我必须进行很多比较操作。


public class main {

    public static void main(String[] args) {

        Set<String> lines = new TreeSet<>();
        lines.add("ba");
        DictAwareSolver myGuesser = new DictAwareSolver(lines);
        myGuesser.makeGuess();
    }
}

这是我在教室上课的课

package solver;

import sun.reflect.generics.tree.Tree;

import java.util.*;
import java.lang.System;

public class DictAwareSolver extends HangmanSolver
{

    private Set<String> dict;


    TreeSet<Node> myTree = new TreeSet<>();


    //getters

    public Set<String> getDict() {
        return dict;
    }
    


    // methods

    public DictAwareSolver(Set<String> dictionary) {
        this.dict = dictionary;
        // Implement me!
    } // end of DictAwareSolver()


    @Override
    public void newGame(int[] wordLengths,int maxIncorrectGuesses)
    {
        // Implement me!
    } // end of newGame()


    @Override
    public char makeGuess() {
        Set<String> guessDict = getDict();

        Iterator dictItr = guessDict.iterator();

        while (dictItr.hasNext())
        {
            String word = (String) dictItr.next();

            for (int i = 0; i<word.length(); i++)
            {
                Node temp = new Node(word.charat(i));
                myTree.add(temp);
            }
        }

        Iterator treeItr = myTree.iterator();

        while (treeItr.hasNext())
        {
            Node n = (Node) treeItr.next();
            System.out.println(n.getLetter() + "-->"+n.getFrequency());
        }
        // Todo: This is a placeholder,replace with appropriate return value.
        return '\0';
    } // end of makeGuess()


    @Override
    public void guessFeedback(char c,Boolean bGuess,ArrayList< ArrayList<Integer> > lPositions)
    {
        // Implement me!
    } // end of guessFeedback()

} // end of class DictAwareSolver

class Node implements Comparable<Node>{
    private char letter;
    private int frequency;

    public Node(char letter)
    {
        this.letter = letter;
        this.frequency = 1;
    }

    public void countIncrementer()
    {
        int newCount = getFrequency()+1;
        setFrequency(newCount);
    }

    // getters

    public char getLetter() {
        return letter;
    }

    public int getFrequency() {
        return frequency;
    }

    // setters


    public void setFrequency(int frequency) {
        this.frequency = frequency;
    }

    @Override
    public int compareto(Node o) {
        if (getLetter() == o.letter)
        {
            o.countIncrementer();
            return 0;
        }
        else if (getLetter() > o.getLetter())
        {
            return 1;
        }
        else
        {
            return -1;
        }
    }
}

运行此命令时,我添加1st的值均为2。在这种情况下,输出

a-> 1 b-> 2

但我期望

a-> 1 b-> 1

如果您指出问题所在,将会非常有帮助。我认为应该是我的compareto方法中的 o.countIncrementer(); 中的内容。我是Java新手。

解决方法

代码假设TreeSet仅在集合中已经存在相等元素的情况下才对比较器调用比较器,并且如果进行这样的比较,则只会进行一次比较。但是,这不是实现TreeSet的方式。在TreeSet的{​​{3}}中,无法保证比较如何发生或以何种频率进行比较。由于这不是API的记录部分,因此TreeSet的作者可以自由地以他们希望的任何合理方式实现此功能,只要它符合记录的API。实际上,还允许他们更改版本之间(例如Java 6和Java 7)或不同实现之间(例如Oracle与IBM)的实现方式。

简而言之,如果文档不能保证某种行为,则您的代码不应依赖该行为。

要了解您所看到的特定行为,将添加到TreeSet中的第一个元素(在您使用的Java版本中)与自身进行比较。尽管这也许令人惊讶,但API并没有禁止它。可能有或没有充分的理由(我相信Java 7中添加了检查,以在将NullPointerException作为第一个元素添加到{{1时,强制抛出null }}不允许每API documentation使用null。但是,最后,检查的原因对API的用户来说无关紧要,因为API不允许这样做。

TreeSet
public static void main(String[] args) {
    System.out.printf("Java vendor & version: %s %s\n",System.getProperty("java.vendor"),Runtime.version());

    TreeSet<Character> set = new TreeSet<>(new LoggingComparator<>());
    set.add('a');
}

private static class LoggingComparator<T extends Comparable<? super T>> implements Comparator<T> {
    @Override
    public int compare(T o1,T o2) {
        System.out.println(o1 + " <=> " + o2);
        return o1.compareTo(o2);
    }
}