在Java中的两个文件中查找通用名称

时间:2012-05-09 20:26:31

标签: java algorithm

首先,我想澄清一下,这个问题的性质与根据我的知识已经发布的其他问题不同。如果不是这样,请告诉我。

鉴于

  1. 我有一个名单~3000。
  2. 有大约2500个文件,其中包含一行名称(取自名称列表)
  3. 每个文件包含~3000个名称(因此~3000行,但平均值为400)
  4. 问题

    在给定时间,我将获得2个文件。我必须创建两个文件中常见的名称列表。

    预处理

    为了减少时间复杂度,我已经完成了预处理并对所有文件中的名称进行了排序。

    我的方法

    1. 在给定列表中对名称进行排序,并将其从0到2999
    2. 编入索引
    3. 在每个名称的每个文件中

      • 计算组号(name_index / 30)
      • 计算组值(对于同一组中的每个名称计算(2 ^(name_index%30))并添加)
      • 以" groupNumber blankSpace groupValue"
      • 的格式创建一个具有相同名称的新文件

      结果

      现在每个文件中最多只有100行,而不是每个文件中有~3000(尽管平均值为400)。现在我将不得不检查公共组号,然后通过位操作的帮助我可以找到常用名称。

      期望

      任何人都可以建议更短更好的问题解决方案。我可以在我的应用程序中进行预处理和存储新文件,以便在查找通用名称时需要最少的处理。

      如果我朝错误的方向解决问题,请告诉我。提前谢谢。

      在我的方法中,总文件的大小为258KB(因为我使用了组名和组值),如果它在每行中按名称保存,则它的大小为573KB。这些文件必须存储在移动设备上。所以我需要尽可能减小尺寸。此外,我期待数据压缩,我不知道如何做到这一点。请注意解释。

4 个答案:

答案 0 :(得分:4)

您是否尝试过以下操作?

  1. 从list1一次读取名称1,将它们添加到哈希集。
  2. 一次从列表2中读取一个名称,在列表一中创建的哈希集中查找它们。如果它们在hashset中,则表示该名称对于两个文件都是通用的。
  3. 如果您想要预处理一些额外的速度,请在每个列表中存储名称,并选择较短的列表作为list1。

答案 1 :(得分:2)

啊哈!鉴于您在编辑中声明的非常低的内存要求,您还可以做其他事情。

虽然我仍然认为你可以寻求其他答案的解决方案。具有3000 HashSet个条目的String不会太大。我对16-char Strings的快速近似提示了低于400 kB的堆内存。试试吧,然后回去吧。这就像整个程序的25行代码。


如果解决方案占用太多内存,那么你可以这样做:

  1. 对文件中的名称进行排序。这总是一件好事。
  2. 打开两个文件。
  3. 从两个文件中读取一行。
    1. 如果line1 < line2,请从line1读取一行,重复。
    2. 如果line1 > line2,请从line2读取一行,重复。
    3. 否则它们是相同的,添加到结果中。重复。
  4. 它几乎不占用任何内存,我认为这是使用compareTo()方法(如果你用它来对名称进行排序)和switch语句的好地方。

    文件的大小根本不会影响内存使用量。


    关于数据压缩 - 您可以使用许多工具和算法,尝试this(也请查看相关问题)或this

答案 2 :(得分:0)

您正在尝试使用列表重新实现Set。不要那样做。使用一组名称,这将自动处理插入的重复。

你需要阅读这两个文件,没有办法做到这一点。

// in pseudo-java
Set<String> names1 = new HashSet<String>();
for (String name : file1.getLine().trim()) {
  names1.put(name);
}

Set<String> names2 = new HashSet<String>();
for (String name : file2.getLine().trim()) {
  names2.put(name);
}

// with this line, names1 will discard any name not in names2
names1.retainAll(names2);

System.out.println(names1);

假设您使用HashSet作为此示例,您将比较字符串的哈希值,这将显着提高性能。

如果您发现性能不足,开始寻找更快的解决方案。其他任何 过早优化,如果你不知道它必须运行多快,那么它是优化而不设定目标。找到“最快”的解决方案需要枚举和耗尽每个可能的解决方案,因为您尚未检查的解决方案可能更快。

答案 3 :(得分:0)

我不确定我是否了解您的要求和情况。

你有大约2.500个文件,每个文件有3000个字(或400个?)。在多个文件中出现了许多重复的单词。

现在有人会问你,哪些单词有文件-345和文件-765的共同点。

您可以创建一个Hashmap,用于存储每个单词,以及一个文件列表,其中包含单词。

如果你得到文件345的3000字(400?),你可以在hashmap中查找,并查看列表中提到的文件765。

然而2 * 3000并不是那么多。如果我在Scala中创建2个字符串列表(在JVM上运行):

val g1 = (1 to 3000).map (x=> "" +  r.nextInt (10000))
val g2 = (1 to 3000).map (x=> "" +  r.nextInt (10000))

并建立交叉点

g1.intersect (g2)

我在8年前的笔记本电脑上几乎没有得到结果(678个元素)。

那么您需要回答多少次请求?文件输入多久更改一次?如果很少,那么读取2个文件可能是关键点。

你有多少独特的单词?也许将它们全部留在记忆中是没有问题的。