为什么我的代码在使用文本文件时打印空数组([])?
Why does my code print empty array([]) when I use text files?
当我以这种方式定义数组字符串时:
String[] X = {"X","M","J","Y","A","U","Z"};
String[] Y = {"M","Z","J","A","W","X","U"};
我的代码有效,它打印 [M, J, A, U]
这是 X
和 Y
的最长公共子序列但是当我为字符串数组定义文本文件时,它们具有相同的输入,然后我的代码打印一个空数组 []
。我该如何解决?
public class LCS {
// Function to find LCS of String X[0..m-1] and Y[0..n-1]
public static String A(String[] x, String[] y, int m, int n, int[][] T)
{
// return empty string if we have reached the end of
// either sequence
if (m == 0 || n == 0) {
return new String();
}
// if last character of X and Y matches
if (x[m - 1] == y[n - 1])
{
// append current character (X[m-1] or Y[n-1]) to LCS of
// substring X[0..m-2] and Y[0..n-2]
return A(x, y, m - 1, n - 1, T) + x[m - 1];
}
// else when the last character of X and Y are different
// if top cell of current cell has more value than the left
// cell, then drop current character of String X and find LCS
// of substring X[0..m-2], Y[0..n-1]
if (T[m - 1][n] > T[m][n - 1]) {
return A(x, y, m - 1, n, T);
}
else {
// if left cell of current cell has more value than the top
// cell, then drop current character of String Y and find LCS
// of substring X[0..m-1], Y[0..n-2]
return A(x, y, m, n - 1, T);
}
}
// Function to fill lookup table by finding the length of LCS
// of substring X[0..m-1] and Y[0..n-1]
public static void LCSLength(String[] x, String[] y, int m, int n, int[][] T)
{
// fill the lookup table in bottom-up manner
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
// if current character of X and Y matches
if (x[i - 1] == y[j - 1]) {
T[i][j] = T[i - 1][j - 1] + 1;
}
// else if current character of X and Y don't match
else {
T[i][j] = Integer.max(T[i - 1][j], T[i][j - 1]);
}
}
}
}
// main function
public static void main(String[] args) throws IOException
{
String[] X = read("C:\Users\fener\Desktop\producerconsumer\Yeni Metin Belgesi.txt");
String[] Y = read("C:\Users\fener\Desktop\producerconsumer\Yeni Metin Belgesi (2).txt");
//String[] X = {"X","M","J","Y","A","U","Z"}, Y = {"M","Z","J","A","W","X","U"};
int m = X.length, n = Y.length;
// T[i][j] stores the length of LCS of substring
// X[0..i-1], Y[0..j-1]
int[][] T = new int[m + 1][n + 1];
// fill lookup table
LCSLength(X, Y, m, n, T);
String[] arr = A(X, Y, m, n, T).split("");
// find longest common sequence
System.out.print(Arrays.toString(arr));
System.exit(0);
}
private static String[] read(String location) throws IOException {
BufferedReader reader1 = new BufferedReader(new FileReader(location));
String line;
ArrayList<String> lines = new ArrayList<String>();
while ((line = reader1.readLine()) != null) {
lines.add(line);
}
reader1.close();
String[] result = new String[lines.size()];
for(int i=0; i<lines.size(); i++) {
result[i] = lines.get(i);
}
return result;
}
}
您应该使用 Object#equals(Object anotherObject)
方法来比较字符串,或者通常是每个对象。
在您的代码中,您使用的是 ==
运算符,它将比较字符串引用(如果它们是相同的 String
实例)而不是它们的值。
您的代码有效(使用数组初始值设定项时),因为您使用文字初始化了 String
数组,并且两个相同的文字将是相同的实例。
当您读取包含 readLine()
的文件中的一行时,它会创建一个新的 String
,因此具有相同内容的两行将导致具有相同值但实例不同的两个字符串。
因此,在比较字符串时,使用 equals
并且您的代码将起作用。
另见:What is the difference between == and equals() in Java?
这里有一些建议:
在 Java 中,使用 ""
和使用 new String()
构造函数实例化字符串是有区别的。
例如:
// Example 1
String a = "Y";
String b = "Y";
boolean result1 = a == b; // true
// Example 2
String c = new String("Y");
String d = new String("Y");
boolean result2 = c == d; // false
发生这种情况是因为当您使用 "Y"
创建字符串时,实际对象分配在堆中一个名为字符串常量池的单独位置。 "Y"
的任何后续分配都将 return 引用字符串常量池中的同一对象。
当您使用 new String("Y")
时,您是说您想要在公共堆中分配一个全新的 String 对象实例。
==
运算符比较 2 个对象以确定它们是否引用相同的对象实例,在这种情况下将与示例 2 所演示的不同。
对于提供的代码,必要的更改是:
在一个方法中
// return empty string if we have reached the end of
// either sequence
if (m == 0 || n == 0) {
return "";
}
...
// if last character of X and Y matches
if (Objects.equals(x[m - 1], y[n - 1])) {
...
在 LCSLength 方法中
// if current character of X and Y matches
if (Objects.equals(x[i - 1], y[j - 1])) {
...
此处 java.util.Objects.equals
安全地与 ==
进行比较,然后 equals()
。
通过应用这些更改,结果是:
[M, J, A, U]
最后 read
方法不需要更改,但可以使用 java.nio
API:
进行简化
private static String[] read(String folder, String filename) throws IOException {
Path path = Paths.get(folder, filename);
List<String> lines = Files.readAllLines(path);
return lines.toArray(new String[0]);
}
当我以这种方式定义数组字符串时:
String[] X = {"X","M","J","Y","A","U","Z"};
String[] Y = {"M","Z","J","A","W","X","U"};
我的代码有效,它打印 [M, J, A, U]
这是 X
和 Y
的最长公共子序列但是当我为字符串数组定义文本文件时,它们具有相同的输入,然后我的代码打印一个空数组 []
。我该如何解决?
public class LCS {
// Function to find LCS of String X[0..m-1] and Y[0..n-1]
public static String A(String[] x, String[] y, int m, int n, int[][] T)
{
// return empty string if we have reached the end of
// either sequence
if (m == 0 || n == 0) {
return new String();
}
// if last character of X and Y matches
if (x[m - 1] == y[n - 1])
{
// append current character (X[m-1] or Y[n-1]) to LCS of
// substring X[0..m-2] and Y[0..n-2]
return A(x, y, m - 1, n - 1, T) + x[m - 1];
}
// else when the last character of X and Y are different
// if top cell of current cell has more value than the left
// cell, then drop current character of String X and find LCS
// of substring X[0..m-2], Y[0..n-1]
if (T[m - 1][n] > T[m][n - 1]) {
return A(x, y, m - 1, n, T);
}
else {
// if left cell of current cell has more value than the top
// cell, then drop current character of String Y and find LCS
// of substring X[0..m-1], Y[0..n-2]
return A(x, y, m, n - 1, T);
}
}
// Function to fill lookup table by finding the length of LCS
// of substring X[0..m-1] and Y[0..n-1]
public static void LCSLength(String[] x, String[] y, int m, int n, int[][] T)
{
// fill the lookup table in bottom-up manner
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
// if current character of X and Y matches
if (x[i - 1] == y[j - 1]) {
T[i][j] = T[i - 1][j - 1] + 1;
}
// else if current character of X and Y don't match
else {
T[i][j] = Integer.max(T[i - 1][j], T[i][j - 1]);
}
}
}
}
// main function
public static void main(String[] args) throws IOException
{
String[] X = read("C:\Users\fener\Desktop\producerconsumer\Yeni Metin Belgesi.txt");
String[] Y = read("C:\Users\fener\Desktop\producerconsumer\Yeni Metin Belgesi (2).txt");
//String[] X = {"X","M","J","Y","A","U","Z"}, Y = {"M","Z","J","A","W","X","U"};
int m = X.length, n = Y.length;
// T[i][j] stores the length of LCS of substring
// X[0..i-1], Y[0..j-1]
int[][] T = new int[m + 1][n + 1];
// fill lookup table
LCSLength(X, Y, m, n, T);
String[] arr = A(X, Y, m, n, T).split("");
// find longest common sequence
System.out.print(Arrays.toString(arr));
System.exit(0);
}
private static String[] read(String location) throws IOException {
BufferedReader reader1 = new BufferedReader(new FileReader(location));
String line;
ArrayList<String> lines = new ArrayList<String>();
while ((line = reader1.readLine()) != null) {
lines.add(line);
}
reader1.close();
String[] result = new String[lines.size()];
for(int i=0; i<lines.size(); i++) {
result[i] = lines.get(i);
}
return result;
}
}
您应该使用 Object#equals(Object anotherObject)
方法来比较字符串,或者通常是每个对象。
在您的代码中,您使用的是 ==
运算符,它将比较字符串引用(如果它们是相同的 String
实例)而不是它们的值。
您的代码有效(使用数组初始值设定项时),因为您使用文字初始化了 String
数组,并且两个相同的文字将是相同的实例。
当您读取包含 readLine()
的文件中的一行时,它会创建一个新的 String
,因此具有相同内容的两行将导致具有相同值但实例不同的两个字符串。
因此,在比较字符串时,使用 equals
并且您的代码将起作用。
另见:What is the difference between == and equals() in Java?
这里有一些建议:
在 Java 中,使用 ""
和使用 new String()
构造函数实例化字符串是有区别的。
例如:
// Example 1
String a = "Y";
String b = "Y";
boolean result1 = a == b; // true
// Example 2
String c = new String("Y");
String d = new String("Y");
boolean result2 = c == d; // false
发生这种情况是因为当您使用 "Y"
创建字符串时,实际对象分配在堆中一个名为字符串常量池的单独位置。 "Y"
的任何后续分配都将 return 引用字符串常量池中的同一对象。
当您使用 new String("Y")
时,您是说您想要在公共堆中分配一个全新的 String 对象实例。
==
运算符比较 2 个对象以确定它们是否引用相同的对象实例,在这种情况下将与示例 2 所演示的不同。
对于提供的代码,必要的更改是:
在一个方法中
// return empty string if we have reached the end of
// either sequence
if (m == 0 || n == 0) {
return "";
}
...
// if last character of X and Y matches
if (Objects.equals(x[m - 1], y[n - 1])) {
...
在 LCSLength 方法中
// if current character of X and Y matches
if (Objects.equals(x[i - 1], y[j - 1])) {
...
此处 java.util.Objects.equals
安全地与 ==
进行比较,然后 equals()
。
通过应用这些更改,结果是:
[M, J, A, U]
最后 read
方法不需要更改,但可以使用 java.nio
API:
private static String[] read(String folder, String filename) throws IOException {
Path path = Paths.get(folder, filename);
List<String> lines = Files.readAllLines(path);
return lines.toArray(new String[0]);
}