如何用binarysearch固定java文本文件?

时间:2018-04-18 17:14:44

标签: java arrays character-encoding binary-search

我正在尝试创建一个小应用程序,它可以在文本文件中进行搜索并识别其中使用的语言(首先是英语和土耳其语之间)。为此我正在搜索字母" k"的字节外观。根据一些研究,这封信广泛用于土耳其语,在英语中使用较少,字节数相同。然而问题是用我的代码在110k字母的文本中找到字母k的外观需要大约20秒(或者可能多一点i7 7700hq comp),所以这对我来说是个大问题,因为我打算在1k文本文件上运行此代码。我应该使用另一种java方法进行搜索,还是以最快的方式进行搜索?

提前致谢

我的代码是:

package deneme;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.stream.IntStream;

public class deneme {
    public static int howmany =0;
    public static double ratio;
    public static void main(String args[]) throws IOException{

        File file = new File("c:\\tr1.srt");
          byte[] bytesArray = new byte[(int) file.length()]; 

          FileInputStream fis = new FileInputStream(file);
          fis.read(bytesArray); //read file into bytes[]
          fis.close();
          byte searchVal = 107; // 'k' letter in byte code

          for(byte textbytes:bytesArray){
              Arrays.sort(bytesArray);
              int retVal = Arrays.binarySearch(bytesArray,0,bytesArray.length,searchVal);
              if(retVal >-1){
                  bytesArray[retVal]=0;
                  howmany++;
              }
          }
          System.out.println("Character \"k\" appears " + howmany +" times in the text");
          ratio = (double)howmany/(double)bytesArray.length;
          System.out.println("How many: "+howmany);
          System.out.println("Length: "+bytesArray.length);
          System.out.println("Ratio: "+ratio);
          if(ratio<0.01){
              System.out.println("Text file is probably not turkish");
          }else{
              System.out.println("Text file is probably turkish");
          }
    }
}

3 个答案:

答案 0 :(得分:2)

排序将访问每个字节,因此您不需要排序,只需访问每个字节一次。

如果你这样做,你实际上可以计算所有字节的频率:

int[] freqs = new int[256];
for(byte b: bytearray)
   freqs[b&0x0ff]++;

然后只需查找你喜欢的字节,如freqs ['k'] + freqs ['K']。

另外,你可以在fileinputstream上打开一个bufferedinputstream,并避免使用巨大的byte [],只需迭代bufferedinputstream.read()(这是一个int 0..255)并在-1时停止。

答案 1 :(得分:1)

排序是一项代价高昂的操作。而且你正在为每个角色排序你的数组,这是低效的。相反,你可以按顺序遍历所有角色,如果那个特定角色是&#39; k&#39;,那么只需递增计数器。这是一个示例代码

for(byte textBytes: bytesArray) {
    if(textBytes == searchVal) {
        howmany++;
    }
}

使用此循环代替您的循环。你应该更快地得到结果。

答案 2 :(得分:1)

首先,如果您使用字母,请使用Reader,而不是InputStream

Reader reader = new BufferedReader(new FileReader(file));

接下来,您实施计数字母的方式&#39; k&#39;是......我应该怎么说......非常有创意。你二元搜索&#39; k&#39;只要找到它就会多次。虽然这有效,但它远非最佳。我认为它是O(n*log n),而O(n)只需一次通过读取字符即可轻松解决。一些事情:

private static final char CHAR_k = 'k';
// ...
int count_k = 0;
int r;
while ((r = reader.read()) != -1) {
    char ch = (char) r;
    if (ch == CHAR_k) {
        count_k++
    }
}