TreeSet在一本书中找到k个最常用的单词?

时间:2018-03-31 11:45:12

标签: java data-structures time-complexity trie treeset

通常使用trie和堆的组合来解决在书中找到k个最常用单词的常见问题(可以动态添加单词)。

但是,我认为即使使用TreeSet也应该足够,并且对于插入和检索具有log(n)性能。

treeset将包含一个自定义对象:

class MyObj implements Comparable{
  String value;
  int count;

 public int incrementCount(){count++;}

 //override equals and hashcode to make this object unique by string 'value'

 //override compareTo to compare count
}

每当我们在树集中插入对象时,我们首先检查该元素是否已经存在于树集中,如果是,那么我们得到obj并递增该对象的count变量。

每当我们想要找到k个最大的单词时,我们只是迭代树集的前k个元素

您对上述方法有何看法?我觉得这种方法更容易编码和理解,并且还匹配trie和heap方法的时间复杂度以获得k个最大元素

编辑:如其中一个答案中所述,在插入myobj之后递增计数变量不会对树集/树形图进行重新排序。因此,在递增计数后,我还需要删除并重新插入treeset / treemap中的对象

2 个答案:

答案 0 :(得分:2)

将对象输入TreeSet后,如果compareTo方法的比较中使用的属性发生更改,则TreeSet(或基础TreeMap)< em>不重新排序元素。因此,这种方法不能按预期工作。

这是一个演示它的简单示例

public static class MyObj implements Comparable<MyObj> {
    String value;
    int count;

    MyObj(String v, int c) {
        this.value = v;
        this.count = c;
    }
    public void incrementCount(){
        count++;
    }

    @Override
    public int compareTo(MyObj o) {
        return Integer.compare(this.count, o.count); //This does the reverse. Orders by freqency
    }
}
 public static void main(String[] args) {
    Set<MyObj> set = new TreeSet<>();
    MyObj o1 = new MyObj("a", 1);
    MyObj o2 = new MyObj("b", 4);
    MyObj o3 = new MyObj("c", 2);
    set.add(o1);
    set.add(o2);
    set.add(o3);
    System.out.println(set);
   //The above prints [a-1, c-2, b-4]

   //Increment the count of c 4 times
    o3.incrementCount();
    o3.incrementCount();
    o3.incrementCount();
    o3.incrementCount();
    System.out.println(set);
   //The above prints [a-1, c-6, b-4]

正如我们所看到的,c-6对应的对象没有被推到最后。

   //Insert a new object
    set.add(new MyObj("d", 3));
    System.out.println(set);
   //this prints [a-1, d-3, c-6, b-4] 
}

修改
注意事项/问题:

  • 比较两个单词时使用count,如果两个单词具有相同的频率,则会删除一个单词。因此,如果频率相同,则需要比较实际的单词。
  • 如果我们删除并重新插入具有更新频率的对象,它将起作用。但为此,您需要从MyObj获取该对象(指定value TreeSet实例以了解到目前为止的频率)。集合没有get方法。其contains方法仅委托给基础TreeMap's containsKey方法,该方法使用compareTo逻辑(而不是equals)来标识对象。 compareTo函数还考虑了单词的频率,因此我们无法识别集合中的单词以将其删除(除非我们在每次添加时迭代整个集合)

答案 1 :(得分:1)

如果删除并插入对象,TreeMap应该有效,使用整数键作为频率,将MyObj列表作为值,键按频率排序。上述代码的更新证明了这一点:

public class MyObj  {
String value;
int count;

MyObj(String v, int c) {
    this.value = v;
    this.count = c;
}

public int getCount() {
    return count;
}

public void incrementCount() {
    count++;
}



@Override
public String toString() {
    return value + " " + count;
}

public static void put(Map<Integer, List<MyObj>> map, MyObj value) {
    List<MyObj> myObjs = map.get(value.getCount());
    if (myObjs == null) {
        myObjs = new ArrayList<>();
        map.put(value.getCount(),myObjs);
    }
    myObjs.add(value);
}

public static void main(String[] args) {
    TreeMap<Integer, List<MyObj>> set = new TreeMap<>();
    MyObj o1 = new MyObj("a", 1);
    MyObj o2 = new MyObj("b", 4);
    MyObj o3 = new MyObj("c", 2);
    MyObj o4 = new MyObj("f", 4);

    put(set,o1);
    put(set,o2);
    put(set,o3);
    System.out.println(set);

    put(set,o4);
    System.out.println(set);
}

}