【问题标题】:How do I recursively append two linked lists in Java? [closed]如何在 Java 中递归地追加两个链表? [关闭]
【发布时间】:2021-02-10 02:19:25
【问题描述】:

所以基本上我的代码遍历列表,原始方法应该返回链接列表,但是它似乎没有添加我在递归方法中链接的节点,我对为什么感到困惑。谁能帮帮我?

    // Append MyStringBuilder2 b to the end of the current MyStringBuilder2, and
    // return the current MyStringBuilder2.  Be careful for special cases!
    public MyStringBuilder2 append(MyStringBuilder2 b)
    {
        //Test if Invalid
        if(b.firstC==null){
            
            return this;
        }
        //Test if condition is met
        else {
            CNode lastNode =firstC;
            recurseAppendBuild(lastNode, b);
            
            return this;
            
        }
    }
    private void recurseAppendBuild(CNode lastNode, MyStringBuilder2 BPoint) {
        //Test if all nodes have been added
        if(lastNode.next==null&&BPoint.firstC==null) {
            System.out.println("finished");
        }
        //Tests if all nodes in the original linked list have been passed through
        else if(lastNode.next==null) {
            
            lastNode.next= new CNode(BPoint.firstC.data);
            BPoint.firstC=BPoint.firstC.next;
            recurseAppendBuild(lastNode.next, BPoint);
        }
        //Recurse until condition is met
        else {
            
            recurseAppendBuild(lastNode.next, BPoint);
        }
    }
    ```

【问题讨论】:

  • 你不需要递归,你只需要遍历每个元素。递归执行此操作似乎更难,我不知道该怎么做。
  • 你的导师规定了递归吗?
  • @NomadMaker 是的,不幸的是,递归是必需的。
  • 当您询问学校作业时,请告诉我们。请阅读论坛规则。
  • 是的,这是一个学校作业,很抱歉我一定错过了。

标签: java recursion append pass-by-reference singly-linked-list


【解决方案1】:

好的,您的代码需要一些工作。让我们看看你的第一种方法。我要重写它。

public MyStringBuilder2 append(MyStringBuilder2 fromBuilder)
{
    if (fromBuilder.firstC != null) {
        recurseAppendBuild(fromBuilder.firstC);
    }

    return this;
}

我改变了很多东西。

  1. 我在参数上使用了一个更有意义的名称。给变量起有意义的名称是个好主意,而不仅仅是“b”。请注意,我从不使用单字符名称。如果没有别的,那就很难搜索了。如果你执行“int i”然后搜索 i,你会得到很多根本不是 i 的命中。

这是一件很琐碎的事情,不会影响你代码的质量。

  1. 在所有情况下,你总是返回自己,所以return语句可以在if-else结构之后,这样更容易看出是一样的。

  2. 这完全消除了顶部的 if 块,所以我颠倒了逻辑。

  3. 我更改了递归方法的方法签名,原因我将在下面描述。

最终的结果简短而甜美,易于理解。


现在,让我们看看您的第二种方法:
private void recurseAppendBuild(CNode lastNode, MyStringBuilder2 BPoint) {
    //Test if all nodes have been added
    if(lastNode.next==null&&BPoint.firstC==null) {
        System.out.println("finished");
    }
    //Tests if all nodes in the original linked list have been passed through
    else if(lastNode.next==null) {
        
        lastNode.next= new CNode(BPoint.firstC.data);
        BPoint.firstC=BPoint.firstC.next;
        recurseAppendBuild(lastNode.next, BPoint);
    }
    //Recurse until condition is met
    else {
        
        recurseAppendBuild(lastNode.next, BPoint);
    }
}
  1. 您的名为 BPoint 的变量违反了 JAVA 命名标准。它应该以小写字母开头。

  2. 如果您传入 MyStringBuilder2 作为第二个参数,那么当您将事物从 BPoint 移动到列表的末尾并递归时,您必须将它们从 BPoint 中删除,这很麻烦。所以相反,我没有指向包装器。在上面的代码中,我传入了列表的头部(fromBuilder.firstC)。

  3. 当你的 list-to-append-from (BPoint) 为空而不是 lastNode 为空时,你就完成了。你的第一个 if 有缺陷。

  4. 您不是递归添加项目。您正在递归地寻找列表的结尾。我不认为那是你真正想要的。

  5. 您正在破坏 BPoint 的完整性。添加节点时,您正在制作节点的副本,但随后您会从 BPoint 中删除旧节点,但根本不维护 lastC。

  6. 如果你的列表开始为空,你就会遇到一个严重的问题,因为 firstC 和 lastNode 都将为空。


所以让我们这样想。首先,递归执行此操作很愚蠢,但这是任务,因此我们将使用它。

递归定义是:

AppendedList = OriginalList + firstItem + 追加列表尾部。

private void recurseAppendBuild(CNode headToAppend) { 如果(headToAppend == NULL){ // 全做完了。 返回; }

   CNode nodeToAppend = new CNode(headToAppend.data);
   if (lastC == nullptr) {
       // Original list is empty.
       firstC = lastC = nodeToAppend;
   else {
       lastC.next = nodeToAppend;
       lastC = nodeToAppend;  // Point the tail at the new tail
   }

   // And here you recurse, always.
   recurseAppendBuild(headToAppend.next);

}

让我们看看这个。

  1. 我假设您在构建器中同时保留了 firstC 和 lastC。否则效率会非常低。所以你只需要传入节点链,而不是周围的包装器。

  2. 通过在此方法的顶部放置一个空检查,您可以消除其他空检查。注意——这意味着我们可以消除第一种方法中的空检查。

  3. 立即创建新副本。那部分很简单,对吧?

  4. 如果 lastC 为空,则您有一个空列表,因此您只需将列表的前面和后面都指向您的新节点。

  5. 否则,您将旧尾部的 next 指针指向您的新节点并更新尾部指针以保持指向尾部。

  6. 无论哪种方式,您都可以安全地递归原始列表中的下一个对象。

这种方法的优点是,除了工作之外,不会破坏原始列表,而且阅读起来非常清晰。

【讨论】:

  • 我需要一些时间来实现它,但这真的很详细而且很有帮助。感谢您抽出宝贵时间! @约瑟夫·拉尔森
  • @JavaLava 对最佳答案感到满意后,您可以将问题标记为已回答。一旦你给了其他人一个参与的机会,你也可以投票给最佳答案。
猜你喜欢
  • 2021-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-15
  • 1970-01-01
  • 1970-01-01
  • 2010-09-26
相关资源
最近更新 更多