Java 用于搜索字符串的更快的数据结构

Java 用于搜索字符串的更快的数据结构,java,data-structures,Java,Data Structures,我有一段代码,用于确定单词列表文本文件中是否包含单词(忽略大小写)。但是,wordList文本文件可能有65000++行,使用下面的实现只搜索一个单词几乎需要一分钟。你能想出更好的实施方案吗 谢谢 import java.io.*; import java.util.*; public class WordSearch { LinkedList<String> lxx; FileReader fxx; BufferedReader bxx; pu

我有一段代码,用于确定单词列表文本文件中是否包含单词(忽略大小写)。但是,wordList文本文件可能有65000++行,使用下面的实现只搜索一个单词几乎需要一分钟。你能想出更好的实施方案吗

谢谢

import java.io.*;
import java.util.*;

public class WordSearch 
{
    LinkedList<String> lxx;
    FileReader fxx;
    BufferedReader bxx;

    public WordSearch(String wordlist) 
        throws IOException
    {
        fxx = new FileReader(wordlist);
        bxx = new BufferedReader(fxx);
        lxx = new LinkedList<String>();
        String word;

        while ( (word = bxx.readLine()) != null) 
            {
            lxx.add(word);
        }

        bxx.close();
    }

    public boolean inTheList (String theWord)
    {
        for(int i =0 ; i < lxx.size(); i++)
            {
            if (theWord.compareToIgnoreCase(lxx.get(i)) == 0)
                    {
                return true;
            }
        }

        return false;
    }
}
import java.io.*;
导入java.util.*;
公共类词汇搜索
{
LinkedList lxx;
文件阅读器fxx;
缓冲读取器bxx;
公共词搜索(字符串词列表)
抛出IOException
{
fxx=新文件读取器(单词列表);
bxx=新的缓冲读取器(fxx);
lxx=新链接列表();
字符串字;
while((word=bxx.readLine())!=null)
{
lxx.add(word);
}
bxx.close();
}
公共布尔值列表(字符串单词)
{
对于(int i=0;i<>代码> 因为你在搜索,你可能想考虑在搜索之前对列表进行排序;然后你可以进行二进制搜索,这比线性搜索快得多。如果您要在同一个列表上执行多个搜索,这可能会有所帮助,否则您为对列表进行排序而付出的代价不值得只搜索一次


此外,使用“lxx.get(i)”对链表进行线性搜索也会带来麻烦。get()是O(n)。您可以使用迭代器(简单方式:for(String s:lxx)),也可以切换到具有O(1)个访问时间的列表类型,例如ArrayList。

使用一个哈希集,将每个单词的小写版本放入其中。检查
HashSet
是否包含指定的字符串平均而言是一个固定时间(读取:极快)操作。

在O(n)操作中通过
l
进行每次搜索,因此当有数千个单词时,这将非常昂贵。相反,请使用
哈希集

Set<String> lxx;

...

lxx = new HashSet<String>();
while ( (word = bxx.readLine()) != null) {
        lxx.add(word.toLowerCase());
}
bxx.close();
设置lxx;
...
lxx=新的HashSet();
while((word=bxx.readLine())!=null){
添加(word.toLowerCase());
}
bxx.close();
然后使用
lxx.contains(theWord.toLowerCase())
检查该单词是否在文件中。
HashSet
中的每个查找都是一个O(1)操作,因此所需的时间(几乎)与文件大小无关。

首先,不要将变量声明为LinkedList,将其声明为List(代码中与已删除列表无关的部分:

public class WordSearch 
{
    List<String> lxx;

    public WordSearch(String wordlist) 
        throws IOException
    {
        lxx = new LinkedList<String>();
    }
}
接下来,将新的LinkedList更改为新的ArrayList:

lxx=新的ArrayList()

这段代码应该更快,但您仍然可以做得更好

因为您不关心重复的单词,所以使用Set而不是List,使用HashSet而不是ArrayList

这样做将大大加快程序的速度

使用带有get的LinkedList的原始代码在每次搜索列表中的下一个单词时都必须从列表的开头重新开始。使用迭代器(通过每个循环的新样式)可以阻止这种情况的发生

使用LinkedList意味着每次必须转到列表中的下一个单词时,都会涉及到查找,ArrayList不会有这样的开销


使用HashSet最终(可能)会使用一个具有非常快速查找的树结构。

下面是我在50毫秒以下搜索的实现

首先,您必须加载文件并在内存中对其进行排序

你可以随意加载它,但如果你把它分成大块加载会更容易

我的输入是(下载HTML单文件版本)和(下载HTML并从所有HTML页面中创建一个文件)

为了将列表创建成一个大文件,我使用了相同的程序(参见注释代码)

一旦我有了一个大约30万字的大文件,我就用以下输出运行程序:

C:\Users\oreyes\langs\java\search>dir singlelineInput.txt
 El volumen de la unidad C no tiene etiqueta.
 El número de serie del volumen es: 22A8-203B

 Directorio de C:\Users\oreyes\langs\java\search

04/03/2011  09:37 p.m.         3,898,345 singlelineInput.txt
               1 archivos      3,898,345 bytes

C:\Users\oreyes\langs\java\search>javac WordSearch.java

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt "great"
Loaded 377381 words in 2844 ms
true
in 31 ms

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt "great"
Loaded 377381 words in 2812 ms
true
in 31 ms

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt "awesome"
Loaded 377381 words in 2813 ms
false
in 47 ms

C:\Users\oreyes\langs\java\search>gvim singlelineInput.txt

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt "during"
Loaded 377381 words in 2813 ms
true
in 15 ms

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt "specification"
Loaded 377381 words in 2875 ms
true
in 47 ms

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt "<href"
Loaded 377381 words in 2844 ms
false
in 47 ms

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt "<br>"
Loaded 377381 words in 2829 ms
true
in 15 ms
C:\Users\oreyes\langs\java\search>dir singlelineInput.txt
这本书没有什么特别之处。
埃尔努梅罗系列卷es:22A8-203B
C:\Users\oreyes\langs\java\search目录
2011年3月4日09:37下午3898345 singlelineInput.txt
1 archivos 3898345字节
C:\Users\oreyes\langs\java\search>javac WordSearch.java
C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt“很棒”
在2844毫秒内加载377381个单词
真的
在31毫秒内
C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt“很棒”
在2812毫秒内加载377381个单词
真的
在31毫秒内
C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt“awesome”
在2813毫秒内加载377381个单词
假的
47毫秒
C:\Users\oreyes\langs\java\search>gvim singlelineInput.txt
C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt“在”
在2813毫秒内加载377381个单词
真的
15毫秒后
C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt“规范”
在2875毫秒内加载377381个单词
真的
47毫秒

C:\Users\oreyes\langs\java\search>java WordSearch singlelineInput.txt“猜猜看,使用HashMap立即返回:

这是修改后的版本,它总是在0毫秒内完成

   import java.io.*;
   import java.util.*;

   class WordSearch {
       String inputFile;
       //List<String> words;
       Set<String> words;
       public WordSearch(String file ) { 
           inputFile = file;
       }
       public void initialize() throws IOException { 
           long start = System.currentTimeMillis();
           File file = new File( inputFile );
           ByteArrayOutputStream baos = new ByteArrayOutputStream(( int ) file.length());
           FileInputStream in = new FileInputStream( file );
           copyLarge( in, baos, (int)file.length() );

           Scanner scanner = new Scanner( new ByteArrayInputStream(  baos.toByteArray() ));
           words = new HashSet<String>();
           while( scanner.hasNextLine() ) { 
              String l = scanner.nextLine().trim();
              //for( String s : l.split("\\s+")){
                //System.out.println( s );
                words.add( l.toLowerCase() );
              //}
           }

           //Collections.sort( words );
           for( String s : words ) { 
               System.out.println( s );
           }
           System.out.println("Loaded " + words.size() + " words in "+  ( System.currentTimeMillis() - start ) + " ms"  );
       }

       public boolean contains( String aWord ) { 
           return words.contains( aWord.toLowerCase() );
       }

        public static long copyLarge(InputStream input, OutputStream output, int size )
               throws IOException {
           byte[] buffer = new byte[size];// something biggie 
           long count = 0;
           int n = 0;
           while (-1 != (n = input.read(buffer))) {
               output.write(buffer, 0, n);
               count += n;
           }
           return count;
       }
       public static void main( String ... args ) throws IOException  { 
           WordSearch ws = new WordSearch( args[0] );
           ws.initialize();
           long start = System.currentTimeMillis();
           System.out.println( ws.contains( args[1] ) );
           System.out.println("in "+  ( System.currentTimeMillis() - start ) +" ms ");

       }
    }
import java.io.*;
导入java.util.*;
类词搜索{
字符串输入文件;
//列出单词;
设定词语;
公共字搜索(字符串文件){
inputFile=文件;
}
public void initialize()引发IOException{
长启动=System.currentTimeMillis();
文件文件=新文件(inputFile);
ByteArrayOutputStream=newbytearrayoutputstream((int)file.length());
FileInputStream in=新的FileInputStream(文件);
copyLarge(in,baos,(int)file.length());
Scanner Scanner=new Scanner(new ByteArrayInputStream(baos.toByteArray());
words=新HashSet();
而(scanner.hasNextLine()){
字符串l=scanner.nextLine().trim();
   import java.io.*;
   import java.util.*;

   class WordSearch {
       String inputFile;
       List<String> words;
       public WordSearch(String file ) { 
           inputFile = file;
       }
       public void initialize() throws IOException { 
           long start = System.currentTimeMillis();
           File file = new File( inputFile );
           ByteArrayOutputStream baos = new ByteArrayOutputStream(( int ) file.length());
           FileInputStream in = new FileInputStream( file );
           copyLarge( in, baos, (int)file.length() );

           Scanner scanner = new Scanner( new ByteArrayInputStream(  baos.toByteArray() ));
           words = new LinkedList<String>();
           while( scanner.hasNextLine() ) { 
              String l = scanner.nextLine().trim();
              //for( String s : l.split("\\s+")){
                //System.out.println( s );
                words.add( l.toLowerCase() );
              //}
           }

           Collections.sort( words );
           for( String s : words ) { 
               //System.out.println( s );
           }
           System.out.println("Loaded " + words.size() + " words in "+  ( System.currentTimeMillis() - start ) + " ms"  );
       }

       public boolean contains( String aWord ) { 
           return words.contains( aWord.toLowerCase() );
       }
        // taken from:  http://stackoverflow.com/questions/326390/how-to-create-a-java-string-from-the-contents-of-a-file/326413#326413 
        public static long copyLarge(InputStream input, OutputStream output, int size )
               throws IOException {
           byte[] buffer = new byte[size];// something biggie 
           long count = 0;
           int n = 0;
           while (-1 != (n = input.read(buffer))) {
               output.write(buffer, 0, n);
               count += n;
           }
           return count;
       }
       public static void main( String ... args ) throws IOException  { 
           WordSearch ws = new WordSearch( args[0] );
           ws.initialize();
           long start = System.currentTimeMillis();
           System.out.println( ws.contains( args[1] ) );
           System.out.println("in "+  ( System.currentTimeMillis() - start ) +" ms ");

       }
    }
   import java.io.*;
   import java.util.*;

   class WordSearch {
       String inputFile;
       //List<String> words;
       Set<String> words;
       public WordSearch(String file ) { 
           inputFile = file;
       }
       public void initialize() throws IOException { 
           long start = System.currentTimeMillis();
           File file = new File( inputFile );
           ByteArrayOutputStream baos = new ByteArrayOutputStream(( int ) file.length());
           FileInputStream in = new FileInputStream( file );
           copyLarge( in, baos, (int)file.length() );

           Scanner scanner = new Scanner( new ByteArrayInputStream(  baos.toByteArray() ));
           words = new HashSet<String>();
           while( scanner.hasNextLine() ) { 
              String l = scanner.nextLine().trim();
              //for( String s : l.split("\\s+")){
                //System.out.println( s );
                words.add( l.toLowerCase() );
              //}
           }

           //Collections.sort( words );
           for( String s : words ) { 
               System.out.println( s );
           }
           System.out.println("Loaded " + words.size() + " words in "+  ( System.currentTimeMillis() - start ) + " ms"  );
       }

       public boolean contains( String aWord ) { 
           return words.contains( aWord.toLowerCase() );
       }

        public static long copyLarge(InputStream input, OutputStream output, int size )
               throws IOException {
           byte[] buffer = new byte[size];// something biggie 
           long count = 0;
           int n = 0;
           while (-1 != (n = input.read(buffer))) {
               output.write(buffer, 0, n);
               count += n;
           }
           return count;
       }
       public static void main( String ... args ) throws IOException  { 
           WordSearch ws = new WordSearch( args[0] );
           ws.initialize();
           long start = System.currentTimeMillis();
           System.out.println( ws.contains( args[1] ) );
           System.out.println("in "+  ( System.currentTimeMillis() - start ) +" ms ");

       }
    }