如何使用 binarysearch 加强 java 文本文件搜索?
How can i fasten java text file search with binarysearch?
我正在尝试制作一个小应用程序,它可以在文本文件中进行搜索并识别其中使用的语言(首先是英语和土耳其语)。为此,我正在搜索字母 "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");
}
}
}
排序是一项代价高昂的操作。而且您正在为每个字符对数组进行排序,这是低效的。相反,您可以按顺序遍历所有字符一次,如果该特定字符是 'k',则只需递增计数器。这是一个示例代码
for(byte textBytes: bytesArray) {
if(textBytes == searchVal) {
howmany++;
}
}
用这个 for 循环代替你的。你应该更快地得到结果。
排序会访问每个字节,因此您不需要排序,只需访问每个字节一次。
如果你这样做,你实际上可以计算所有字节的频率:
int[] freqs = new int[256];
for(byte b: bytearray)
freqs[b&0x0ff]++;
然后只需查找您喜欢的字节,如 freqs['k']+freqs['K'].
此外,您可以只在文件输入流上打开一个缓冲输入流,并避免使用巨大的字节 [],只需遍历 bufferedinputstream.read()(这是一个 int 0..255)并在 -1 时停止.
首先,如果您使用字母,请使用 Reader
,而不是 InputStream
:
Reader reader = new BufferedReader(new FileReader(file));
接下来,你实现的计算字母'k'的方法是……怎么说呢……很有创意。只要找到,您就可以多次二进制搜索 'k' 。虽然这有效,但远非最佳。我认为它是 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++
}
}
我正在尝试制作一个小应用程序,它可以在文本文件中进行搜索并识别其中使用的语言(首先是英语和土耳其语)。为此,我正在搜索字母 "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");
}
}
}
排序是一项代价高昂的操作。而且您正在为每个字符对数组进行排序,这是低效的。相反,您可以按顺序遍历所有字符一次,如果该特定字符是 'k',则只需递增计数器。这是一个示例代码
for(byte textBytes: bytesArray) {
if(textBytes == searchVal) {
howmany++;
}
}
用这个 for 循环代替你的。你应该更快地得到结果。
排序会访问每个字节,因此您不需要排序,只需访问每个字节一次。
如果你这样做,你实际上可以计算所有字节的频率:
int[] freqs = new int[256];
for(byte b: bytearray)
freqs[b&0x0ff]++;
然后只需查找您喜欢的字节,如 freqs['k']+freqs['K'].
此外,您可以只在文件输入流上打开一个缓冲输入流,并避免使用巨大的字节 [],只需遍历 bufferedinputstream.read()(这是一个 int 0..255)并在 -1 时停止.
首先,如果您使用字母,请使用 Reader
,而不是 InputStream
:
Reader reader = new BufferedReader(new FileReader(file));
接下来,你实现的计算字母'k'的方法是……怎么说呢……很有创意。只要找到,您就可以多次二进制搜索 'k' 。虽然这有效,但远非最佳。我认为它是 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++
}
}