java 链表有效,但在一个实例中除外
java linked list works except in one instance
我正在 Java 中编写一个链接列表,它本质上是 Java 的 String 和 StringBuilder classes 的混合体。我必须用 JUnit 测试它并且所有测试都通过了,除了最后两个,它传递了一个由每个字符组成的字符串。在这种情况下,链接列表仅包含前两个字符,但长度正确。我不确定为什么它在这种情况下不起作用,但在 "abcd"、"xyzzy" 或 "This is a very long string." 的其他情况下有效 我不允许使用字符串方法,除了 charAt( ) 在构造函数中。这是我的代码:
import java.util.Scanner;
public class LString{
private char letter;
private LString next;
private int length;
public LString(){
}
public LString(String original){ //this constructor is where it fails
if (original != ""){
Scanner darkly = new Scanner(original).useDelimiter("");
this.letter = darkly.next().charAt(0);
this.next = new LString();
LString curr = this.next;
this.length++;
while (darkly.hasNext()){
curr.next = new LString();
curr.letter = darkly.next().charAt(0);
curr = curr.next;
this.length++;
}
}
}
public int length(){
return this.length;
}
public String toString(){
StringBuilder temp = new StringBuilder();
if (this.letter != '\u0000'){
temp.append(this.letter);
}
LString curr = next;
for (int j = 0; j < this.length; j++){
if (curr != null && curr.letter != '\u0000'){
temp.append(curr.letter);
curr = curr.next;
}
}
return temp.toString();
}
public int compareTo(LString anotherLString){
LString curr = this;
LString test = anotherLString;
if (this == null || anotherLString == null){
return 0;
}
for (int q = 0; q <= this.length && q <= anotherLString.length; q++){
if (curr.letter != test.letter){
return curr.letter - test.letter;
}
if (curr.next != null && test.next != null){
curr = curr.next;
test = test.next;
}
}
if (this.length != anotherLString.length){
return this.length - anotherLString.length;
}
return 0;
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof LString))
return false;
else {
LString otherLString = (LString)other;
if (compareTo(otherLString) == 0){
return true;
}else{
return false;
}
}
}
public char charAt(int index){
if (index < 0 || index >= this.length){
throw new IndexOutOfBoundsException();
}
LString curr = findIndex(index, this);
return curr.letter;
}
public void setCharAt(int index, char ch){
if (index < 0 || index >= this.length){
throw new IndexOutOfBoundsException();
}
LString curr = findIndex(index, this);
curr.letter = ch;
}
private LString findIndex(int index, LString search){
LString curr = search;
for (int l = 0; l < index; l++){
curr = curr.next;
}
return curr;
}
public LString substring(int start, int end){
if (start > end || start < 0 || end > this.length){
throw new IndexOutOfBoundsException();
}
if (start == end){
return new LString();
}
LString curr = new LString(Character.toString(this.charAt(start)));
int p = start + 1;
while (p < end){
LString pete = new LString(Character.toString(this.charAt(p)));
append(curr, pete);
p++;
}
return curr;
}
public LString replace(int start, int end, LString LStr){
if (start > end || start < 0 || end > this.length){
throw new IndexOutOfBoundsException();
}
LString roger = new LString(LStr.toString());
if (LStr == null || LStr.letter == '\u0000'){
replaceHelper(roger);
return this;
}
if (this == null || this.letter == '\u0000'){
replaceHelper(roger);
return this;
}
if (start == end){
if (this.length == 1 && start == 0){
LString temp = new LString(LStr.toString() + this.letter);
replaceHelper(temp);
return this;
}else if (this.length == 1){
LString temp9 = new LString(this.letter + LStr.toString());
replaceHelper(temp9);
return this;
}
if (end == this.length){
LString karl = new LString(this.toString() + roger.toString());
replaceHelper(karl);
return this;
}
if (end < this.length && start != 0){
LString ned = findIndex(start - 1, this);
LString pup = findIndex(end, this);
String batman = "";
while (pup.letter != '\u0000'){
batman += pup.letter;
pup = pup.next;
}
ned.next = null;
LString miranda = new LString(batman);
LString urkel = new LString(this.toString() + roger.toString() + miranda.toString());
replaceHelper(urkel);
return this;
}
LString jeff = new LString(roger.toString() + this.toString());
replaceHelper(jeff);
return this;
}
if (this.length == 1){
LString temp11 = new LString(LStr.toString());
replaceHelper(temp11);
return this;
}
if (start == 0){
if (end < this.length){
LString patrick = findIndex(end, this);
String themaxxxx = "";
while (patrick.letter != '\u0000'){
themaxxxx += patrick.letter;
patrick = patrick.next;
}
LString boudreau = new LString(themaxxxx);
LString yusef = new LString(roger.toString() + boudreau);
replaceHelper(yusef);
return this;
}
LString irvine = findIndex(end, this);
LString geronimo = new LString(roger.toString() + irvine);
replaceHelper(geronimo);
return this;
}
LString jurgen = findIndex(start - 1, this);
LString howard = findIndex(end, this);
jurgen.next = null;
String spawn = "";
while (howard.letter != '\u0000'){
spawn += howard.letter;
howard = howard.next;
}
LString orion = new LString(spawn);
LString bonnie = new LString(this.toString() + roger.toString() + orion.toString());
replaceHelper(bonnie);
return this;
}
private void append(LString curr, LString pete){
LString yup = curr;
while (yup.next.next != null){
yup = yup.next;
}
yup.next = pete;
curr.length++;
}
private void replaceHelper(LString help){
this.letter = help.charAt(0);
this.length = 1;
this.next = new LString();
LString result = this.next;
for (int t = 1; t < help.length; t++){
result.letter = help.charAt(t);
result.next = new LString();
result = result.next;
this.length++;
}
}
}
这是相关的测试代码:
private String allCharsString;
@Before public void setUp() {
StringBuilder sb = new StringBuilder(((int)Character.MAX_VALUE) + 10);
sb.append("}>");
for (char ch = Character.MIN_VALUE; ch < Character.MIN_SURROGATE; ch++)
sb.append(ch);
sb.append("<{");
allCharsString = sb.toString();
}
@Test public void test81aAllChars() {
LString testLString = new LString(allCharsString);
assertEquals("Problem with representing all chars",
allCharsString, testLString.toString());
}
@Test public void test81bAllCharsLength() {
LString testLString = new LString(allCharsString);
assertEquals("Problem with representing all chars",
allCharsString.length(), testLString.length());
}
@Test public void test81cAllCharReplace() {
LString testLString = new LString(allCharsString);
LString testLString2 = new LString(allCharsString);
int length = allCharsString.length();
assertEquals("Problem with representing all chars",
allCharsString + allCharsString,
testLString.replace(length, length, testLString2).toString());
}
第一次和第三次测试失败,但第二次通过。这是输出:
Running special tests (3 tests)
Starting tests: E.E
Time: 0.131
There were 2 failures:
1) test81aAllChars(LStringTest$LStringSpecialTest)
org.junit.ComparisonFailure: Problem with representing all chars expected:<}>[
!!(everycharacter goes here, in unicode)!! but was:<}>[]>
at org.junit.Assert.assertEquals(Assert.java:115)
at LStringTest$LStringSpecialTest.test81aAllChars(LStringTest.java:764)
... 10 more
2) test81cAllCharReplace(LStringTest$LStringSpecialTest)
org.junit.ComparisonFailure: Problem with representing all chars expected:<}>[
!!(every character goes here, in unicode)!! but was:<}>[]>
at org.junit.Assert.assertEquals(Assert.java:115)
at LStringTest$LStringSpecialTest.test81cAllCharReplace(LStringTest.java:778)
有人能帮忙吗?
我想我找到了真正的问题,它与字符编码有关。创建链表后,我验证了你的构造函数是好的并且length = 55300。然后我进入了您重写的 toString() 方法。 for 循环的第三次迭代失败.....curr.letter 等于 \u0000。这会导致您绕过指向下一个节点的循环内部,因此 curr 的值在第三次迭代后不会改变。您只需在循环中再迭代 55297 次左右,什么也不做。这就是为什么 toString 的 return 值是那个 2 字符的小字符串“}>”。我不是 charAt() 和 unicode 方面的专家,但我猜你的原始字符串中的第三个字母经过编码,使得扫描器识别的第一个完整标记是 '\u1000'。
这就是您的第二个测试通过的原因。您的长度计数器已正确增加,但它实际上只是构造函数循环执行次数的计数器。当您从 toString() 获取长度时,您将获得值 2.
作为友好的设计提示,toString() 应该使用以下循环条件,因为涉及链表:
while(curr != null)
{
//loop body
}
这样,如果在列表创建过程中出现问题,您会更容易发现问题。使用 this.length 作为循环条件假设您的列表长度和计数器相等,这是一个有风险的假设。
这是一个有效的构造函数:
public LString(String original){
StringBuilder sb = new StringBuilder();
if (original != ""){
Scanner darkly = new Scanner(original).useDelimiter("");
LString currNode = this;
while (darkly.hasNext()){
currNode.letter = darkly.next().charAt(0);
this.length++;
if (darkly.hasNext()) { //don't add next node if no more chars
currNode.next = new LString();
currNode = currNode.next;
}
}
}
}
这是一个有效的 toString() 循环链表,同时忽略特定字符值作为退出条件
public String toString(){
StringBuilder temp = new StringBuilder();
temp.append(this.letter); //assumes you always have at least one character to print
LString curr = next;
while (curr != null ){
temp.append(curr.letter);
curr = curr.next;
}
return temp.toString();
}
我确认这将使 JUnit 测试 test81aAllChars 通过。没有时间查看您的替换方法以及失败的原因,但也许我在这里发现的内容也会对您有所帮助。祝你好运。
我正在 Java 中编写一个链接列表,它本质上是 Java 的 String 和 StringBuilder classes 的混合体。我必须用 JUnit 测试它并且所有测试都通过了,除了最后两个,它传递了一个由每个字符组成的字符串。在这种情况下,链接列表仅包含前两个字符,但长度正确。我不确定为什么它在这种情况下不起作用,但在 "abcd"、"xyzzy" 或 "This is a very long string." 的其他情况下有效 我不允许使用字符串方法,除了 charAt( ) 在构造函数中。这是我的代码:
import java.util.Scanner;
public class LString{
private char letter;
private LString next;
private int length;
public LString(){
}
public LString(String original){ //this constructor is where it fails
if (original != ""){
Scanner darkly = new Scanner(original).useDelimiter("");
this.letter = darkly.next().charAt(0);
this.next = new LString();
LString curr = this.next;
this.length++;
while (darkly.hasNext()){
curr.next = new LString();
curr.letter = darkly.next().charAt(0);
curr = curr.next;
this.length++;
}
}
}
public int length(){
return this.length;
}
public String toString(){
StringBuilder temp = new StringBuilder();
if (this.letter != '\u0000'){
temp.append(this.letter);
}
LString curr = next;
for (int j = 0; j < this.length; j++){
if (curr != null && curr.letter != '\u0000'){
temp.append(curr.letter);
curr = curr.next;
}
}
return temp.toString();
}
public int compareTo(LString anotherLString){
LString curr = this;
LString test = anotherLString;
if (this == null || anotherLString == null){
return 0;
}
for (int q = 0; q <= this.length && q <= anotherLString.length; q++){
if (curr.letter != test.letter){
return curr.letter - test.letter;
}
if (curr.next != null && test.next != null){
curr = curr.next;
test = test.next;
}
}
if (this.length != anotherLString.length){
return this.length - anotherLString.length;
}
return 0;
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof LString))
return false;
else {
LString otherLString = (LString)other;
if (compareTo(otherLString) == 0){
return true;
}else{
return false;
}
}
}
public char charAt(int index){
if (index < 0 || index >= this.length){
throw new IndexOutOfBoundsException();
}
LString curr = findIndex(index, this);
return curr.letter;
}
public void setCharAt(int index, char ch){
if (index < 0 || index >= this.length){
throw new IndexOutOfBoundsException();
}
LString curr = findIndex(index, this);
curr.letter = ch;
}
private LString findIndex(int index, LString search){
LString curr = search;
for (int l = 0; l < index; l++){
curr = curr.next;
}
return curr;
}
public LString substring(int start, int end){
if (start > end || start < 0 || end > this.length){
throw new IndexOutOfBoundsException();
}
if (start == end){
return new LString();
}
LString curr = new LString(Character.toString(this.charAt(start)));
int p = start + 1;
while (p < end){
LString pete = new LString(Character.toString(this.charAt(p)));
append(curr, pete);
p++;
}
return curr;
}
public LString replace(int start, int end, LString LStr){
if (start > end || start < 0 || end > this.length){
throw new IndexOutOfBoundsException();
}
LString roger = new LString(LStr.toString());
if (LStr == null || LStr.letter == '\u0000'){
replaceHelper(roger);
return this;
}
if (this == null || this.letter == '\u0000'){
replaceHelper(roger);
return this;
}
if (start == end){
if (this.length == 1 && start == 0){
LString temp = new LString(LStr.toString() + this.letter);
replaceHelper(temp);
return this;
}else if (this.length == 1){
LString temp9 = new LString(this.letter + LStr.toString());
replaceHelper(temp9);
return this;
}
if (end == this.length){
LString karl = new LString(this.toString() + roger.toString());
replaceHelper(karl);
return this;
}
if (end < this.length && start != 0){
LString ned = findIndex(start - 1, this);
LString pup = findIndex(end, this);
String batman = "";
while (pup.letter != '\u0000'){
batman += pup.letter;
pup = pup.next;
}
ned.next = null;
LString miranda = new LString(batman);
LString urkel = new LString(this.toString() + roger.toString() + miranda.toString());
replaceHelper(urkel);
return this;
}
LString jeff = new LString(roger.toString() + this.toString());
replaceHelper(jeff);
return this;
}
if (this.length == 1){
LString temp11 = new LString(LStr.toString());
replaceHelper(temp11);
return this;
}
if (start == 0){
if (end < this.length){
LString patrick = findIndex(end, this);
String themaxxxx = "";
while (patrick.letter != '\u0000'){
themaxxxx += patrick.letter;
patrick = patrick.next;
}
LString boudreau = new LString(themaxxxx);
LString yusef = new LString(roger.toString() + boudreau);
replaceHelper(yusef);
return this;
}
LString irvine = findIndex(end, this);
LString geronimo = new LString(roger.toString() + irvine);
replaceHelper(geronimo);
return this;
}
LString jurgen = findIndex(start - 1, this);
LString howard = findIndex(end, this);
jurgen.next = null;
String spawn = "";
while (howard.letter != '\u0000'){
spawn += howard.letter;
howard = howard.next;
}
LString orion = new LString(spawn);
LString bonnie = new LString(this.toString() + roger.toString() + orion.toString());
replaceHelper(bonnie);
return this;
}
private void append(LString curr, LString pete){
LString yup = curr;
while (yup.next.next != null){
yup = yup.next;
}
yup.next = pete;
curr.length++;
}
private void replaceHelper(LString help){
this.letter = help.charAt(0);
this.length = 1;
this.next = new LString();
LString result = this.next;
for (int t = 1; t < help.length; t++){
result.letter = help.charAt(t);
result.next = new LString();
result = result.next;
this.length++;
}
}
} 这是相关的测试代码:
private String allCharsString;
@Before public void setUp() {
StringBuilder sb = new StringBuilder(((int)Character.MAX_VALUE) + 10);
sb.append("}>");
for (char ch = Character.MIN_VALUE; ch < Character.MIN_SURROGATE; ch++)
sb.append(ch);
sb.append("<{");
allCharsString = sb.toString();
}
@Test public void test81aAllChars() {
LString testLString = new LString(allCharsString);
assertEquals("Problem with representing all chars",
allCharsString, testLString.toString());
}
@Test public void test81bAllCharsLength() {
LString testLString = new LString(allCharsString);
assertEquals("Problem with representing all chars",
allCharsString.length(), testLString.length());
}
@Test public void test81cAllCharReplace() {
LString testLString = new LString(allCharsString);
LString testLString2 = new LString(allCharsString);
int length = allCharsString.length();
assertEquals("Problem with representing all chars",
allCharsString + allCharsString,
testLString.replace(length, length, testLString2).toString());
}
第一次和第三次测试失败,但第二次通过。这是输出:
Running special tests (3 tests)
Starting tests: E.E
Time: 0.131
There were 2 failures:
1) test81aAllChars(LStringTest$LStringSpecialTest)
org.junit.ComparisonFailure: Problem with representing all chars expected:<}>[
!!(everycharacter goes here, in unicode)!! but was:<}>[]>
at org.junit.Assert.assertEquals(Assert.java:115)
at LStringTest$LStringSpecialTest.test81aAllChars(LStringTest.java:764)
... 10 more
2) test81cAllCharReplace(LStringTest$LStringSpecialTest)
org.junit.ComparisonFailure: Problem with representing all chars expected:<}>[
!!(every character goes here, in unicode)!! but was:<}>[]>
at org.junit.Assert.assertEquals(Assert.java:115)
at LStringTest$LStringSpecialTest.test81cAllCharReplace(LStringTest.java:778)
有人能帮忙吗?
我想我找到了真正的问题,它与字符编码有关。创建链表后,我验证了你的构造函数是好的并且length = 55300。然后我进入了您重写的 toString() 方法。 for 循环的第三次迭代失败.....curr.letter 等于 \u0000。这会导致您绕过指向下一个节点的循环内部,因此 curr 的值在第三次迭代后不会改变。您只需在循环中再迭代 55297 次左右,什么也不做。这就是为什么 toString 的 return 值是那个 2 字符的小字符串“}>”。我不是 charAt() 和 unicode 方面的专家,但我猜你的原始字符串中的第三个字母经过编码,使得扫描器识别的第一个完整标记是 '\u1000'。
这就是您的第二个测试通过的原因。您的长度计数器已正确增加,但它实际上只是构造函数循环执行次数的计数器。当您从 toString() 获取长度时,您将获得值 2.
作为友好的设计提示,toString() 应该使用以下循环条件,因为涉及链表:
while(curr != null)
{
//loop body
}
这样,如果在列表创建过程中出现问题,您会更容易发现问题。使用 this.length 作为循环条件假设您的列表长度和计数器相等,这是一个有风险的假设。
这是一个有效的构造函数:
public LString(String original){
StringBuilder sb = new StringBuilder();
if (original != ""){
Scanner darkly = new Scanner(original).useDelimiter("");
LString currNode = this;
while (darkly.hasNext()){
currNode.letter = darkly.next().charAt(0);
this.length++;
if (darkly.hasNext()) { //don't add next node if no more chars
currNode.next = new LString();
currNode = currNode.next;
}
}
}
}
这是一个有效的 toString() 循环链表,同时忽略特定字符值作为退出条件
public String toString(){
StringBuilder temp = new StringBuilder();
temp.append(this.letter); //assumes you always have at least one character to print
LString curr = next;
while (curr != null ){
temp.append(curr.letter);
curr = curr.next;
}
return temp.toString();
}
我确认这将使 JUnit 测试 test81aAllChars 通过。没有时间查看您的替换方法以及失败的原因,但也许我在这里发现的内容也会对您有所帮助。祝你好运。