在大型数据集中查找唯一条目的最有效方法

时间:2014-11-23 01:03:42

标签: java arrays sorting search arraylist

在此之前,我明确表示这是一项任务,我不希望完整的编码答案。我寻求的只是建议和可能帮助我的代码片段。

所以,我正在读取存储在arrayList中的大约900,000个单词。我需要在java中使用排序数组(或arraylist)计算唯一单词。

到目前为止,我只是循环遍历给定的arrayList并使用

Collections.sort(words); 

Collections.binarySearch(words, wordToLook);实现如下:

OrderedSet set = new OrderedSet();
    for(String a : words){
        if(!set.contains(a)){
            set.add(a);
        }
    }

public boolean contains(String word) {
    Collections.sort(uniqueWords);
    int result = Collections.binarySearch(uniqueWords, word);

    if(result<0){
        return false;
    }else{
        return true;
    }
}

这段代码的运行时间约为60秒,但我想知道是否有更好的方法可以做到这一点,因为每次添加一个元素时运行一个排序看起来非常低效(但如果我使用二进制文件则必须使用搜索)。

非常感谢任何形式的反馈。感谢。

4 个答案:

答案 0 :(得分:0)

我不会使用排序数组。我会创建一个Map<String, Integer>,其中键是你的单词,值是单词出现次数的计数。在阅读每个单词时,请执行以下操作:

Integer count = map.get(word);
if (count == null) {
    count = 0;
}
map.put(word, count + 1);

然后只需遍历地图的入口集,并对计数执行任何操作。

如果你知道或者可以估计唯一单词的数量,那么你应该在HashMap构造函数中使用这个数字(所以你不要多次增长地图)。

如果使用排序数组,则运行时间不能比NlogN(其中N是列表中的单词数)成比例。如果使用HashMap,则可以实现与N线性增长的运行时(您自己保存logN的因子)。

使用Map的另一个好处是使用的内存与唯一单词的数量成正比,而不是单词的总数(假设您在阅读单词时构建地图,而不是将所有单词读入集合中然后将它们添加到地图中。)

答案 1 :(得分:0)

因此,您必需使用已排序的数组。没关系,因为你(现在还没有)在现实世界中编程。

我会建议两种选择:

第一个使用二进制搜索(您在当前代码中使用)。

我会创建一个包含两个字段的类:单词(String)和该单词的计数(int)。您将构建这些类的排序数组。

从一个空数组开始,并在读取每个单词时添加到该数组。对于每个单词,请对要构建的数组中的单词执行二进制搜索。搜索将找到包含该单词的条目(并且您将增加计数),或者您将确定该单词尚未在数组中。

当您的二进制搜索结束而没有找到该单词时,您将创建一个新对象来保存单词+ count并将其添加到搜索结束位置的数组中(注意确保您的逻辑真正放置它)在正确的位置保持您的列表排序)。当然,新单词的计数设置为1。

另一种选择:

将所有单词读入列表并对其进行排序。排序后,所有重复项将在列表中彼此相邻。

您将沿着此排序列表向下走,并创建一个单词+计数列表。如果您看到的下一个单词与最后一个单词+ count相同,则递增计数。如果是新单词,请在count = 1的结果列表中添加一个新单词+ count。

答案 2 :(得分:0)

public static int countUnique(array) {
    if(array.length == 0) return 0;
    int count = 1;
    for i from 1 to array.length - 1 {
        if(!array[i].equals(array[i - 1])) count++;
    }
    return count;
}

这是伪代码中的O(N)算法,用于计算排序数组中唯一条目的数量。它背后的想法是我们计算相等元素组之间的转换数。然后,唯一条目的数量是转换数加1(第一个条目)。

希望您看到在对元素进行排序后如何将此算法应用于数组。

答案 3 :(得分:0)

您总是可以使用比较器来获取唯一值。

  List newList = new ArrayList(new Comparator() {
        @Override
        public int compare(words o1, words o2) {
            if(o1.equalsIgnoreCase(o2)){
                return 0;
            }
            return 1;
        }
    });

现在算了:

单词 - newList = no。重复值。

希望这有助于!!!!