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 通过。没有时间查看您的替换方法以及失败的原因,但也许我在这里发现的内容也会对您有所帮助。祝你好运。