【问题标题】:C++ Linked List Recursion QuestionC++ 链表递归问题
【发布时间】:2011-08-02 01:08:02
【问题描述】:

我在理解以下代码块时遇到了一些麻烦:

void InsertSorted(Entry * & list, Entry * newOne) {
    if (list == NULL || newOne->name < list->name) {
        newOne->next = list;
        list = newOne;
    } else {
        InsertSorted(list->next, newOne);
    }
}

我尝试跟踪代码,但只设法到达第一个 if 语句的位置。一旦我执行了第一个 if 语句,我就不明白之前对 InsertSorted 的调用是如何将列表的前面部分连接到新创建的列表的。

谢谢

【问题讨论】:

  • 顺便说一句:如果是作业 - 将其标记为作业。

标签: c++ recursion linked-list


【解决方案1】:

要理解这个函数,只需绘制它每次调用获得的数据。

假设您有一个这样的列表(假设名称是int):

1 -> 4 -> 6 -> 7 -> 10 -> NULL

你想插入5

在第一次调用时,list 通过原始调用者指针引用1。也就是说,如果你这样做:

InsertSorted(myList, someNode);

函数内部的list 指的是函数外部myList,更改它内部会改变它外部。现在,if 条件没有通过,因为list 不是NULL 并且newOne-&gt;name 不是&lt; list-&gt;name。所以函数调用自己,使用listnext 指针和newOne。这是我们现在的位置:

1 -> 4 -> 6 -> 7 -> 10 -> NULL
^ list refers to this one

5
^ this is newOne, floating off somewhere by itself

在下一次调用中,list 引用上次调用中的list-&gt;next,这意味着它引用了4。再次对if 不满意,所以我们继续else:再次使用list-&gt;next 调用该函数(记住list 现在指的是4,这使得list-&gt;next 指的是6在这个电话中)。这是我们现在的位置:

1 -> 4 -> 6 -> 7 -> 10 -> NULL
     ^ list refers to this one through 1's next pointer

5
^ this is newOne, floating off somewhere by itself

在下一次调用中,list引用4next指针,代表6。列表如下所示:

1 -> 4 -> 6 -> 7 -> 10 -> NULL
          ^ list refers to this one through 4's next pointer

5
^ this is newOne, floating off somewhere by itself

这一次,if满意的(因为 5

  1. 使newOne-&gt;next 指向list。这使得代表5 的新节点指向6,因为它是next 节点。

  2. list 设置为newNode。这可能令人困惑,但请记住list 是一个引用,这意味着更改它会更改原始文件。原来是list-&gt;nextlist引用4,所以和设置指向4next指针的节点指向newOne是一样的。

这意味着列表现在看起来像这样:

1 -> 4 -> 5 -> 6 -> 7 -> 10 -> NULL
          ^ here's newOne

并且该函数不进行任何调用,因此该函数终止,并且控制权返回到最初调用它的函数。

您刚刚按排序顺序插入了新元素。

您需要考虑三种极端情况:

  1. 列表为空(立即list == NULL
  2. 您要插入的元素小于所有现有元素
  3. 您要插入的元素大于所有现有元素

假设您总是尝试插入 5 作为这些测试的新元素。

所以对于第一个,当 list 为 NULL 时 - 也就是说,您的列表看起来像

NULL

if 语句将立即为真,您将newOne-&gt;next 设置为list(这意味着newOne-&gt;nextNULL),并将list 设置为newOne。函数退出,您的列表如下所示:

5 -> NULL

到目前为止,一切都很好。

如果您要插入的元素比所有其他元素,例如:

7 -> 9 -> NULL

5
^ newOne

然后if 也会立即触发。您将newOne-&gt;next 设置为list,使其指向7,并将list 设置为newOne

5 -> 7 -> 9 -> NULL

这已经处理好了。

最后一个极端情况是新元素大于所有现有元素。说你有

3 -> NULL

作为您的清单。在第一次通过时,list 将指向 3,并且不会触发 if。因此,您将使用指向NULLlist-&gt;next 调用该函数。 if 被触发(因为list == NULL)并且您将newOne-&gt;next 设置为list(即NULL)然后您将list 设置为newOne,这使得3-&gt;next 指向@987654402 @,因为在第一次调用中,您通过引用传递了它的next 指针,这意味着更改list 会更改它。现在你有:

3 -> 5 -> NULL

这一切都很好。所以这个函数似乎可以为任何列表产生所需的结果。

附带说明,此函数是尾递归的,但可以通过使其迭代而不是递归来加快速度。这是一个很好的学习练习。

另请注意,这 不是 插入排序,因为您没有获取未排序的列表并对其进行排序,您只是以类似于插入排序的方式在现有列表中插入新数据.

【讨论】:

    【解决方案2】:

    即插入排序,项目将根据其放置的顺序插入到列表中。一旦您到达列表的末尾,或在列表中找到项目应该所在的位置,递归将结束。

    请注意,对于每次递归调用,您都会在列表中前进一个链,列表指针的“头”本质上会在列表中移动。

    【讨论】:

      【解决方案3】:

      基本上,如果新元素的位置正确,则此代码会在列表的开头插入新元素 - 否则,它会向下移动并将下一个元素视为“开始”。

      关键是列表指针是通过引用传递的,所以当我们说“list = newOne;”时它实际上对调用者的范围有影响。所以当我们调用“InsertSorted(list->next, newOne)”时,它实际上可以更新我们的列表。

      【讨论】:

        【解决方案4】:
        newOne->next = list;
        

        将 newOne 列表节点的下一个字段设置为当前列表的前面。

        list = newOne;
        

        将跟踪列表(称为“列表”)前面的指针设置为指向列表中新的第一个节点newOne。

        上述情况仅在列表为空的情况下发生。 else 条件在列表中向下遍历一个节点,直到找到列表中的最后一个节点,由 if 语句条件控制。

        由于参数是通过引用传递的(如“&”字段所示),因此函数内部所做的更改在程序中的任何地方都会持续存在。

        【讨论】:

          【解决方案5】:

          我不明白之前对 InsertSorted 的调用如何将列表的前面部分连接到新创建的列表。

          “列表的前面部分”已经与自身完全连接 - 这就是使它成为列表的原因。

          算法是:

          1) 找到插入点。 2) 将新条目连接到位。现在一切都已连接。

          我们通过递归找到当前列表的结尾:如果我们在那里,那么我们就在那里;否则,我们检查下一个链接。我们以相同的方式“检查下一个链接”,所以如果这是结束,那么我们就完成了,否则我们继续下一个,等等。

          当我们到达终点时,我们执行以下步骤:

          newOne->next = list;
          list = newOne;
          

          这意味着:

          1) 告诉新条目链接到列表的尾部。 2) 告诉列表的头部链接到新条目。

          这是因为list对指针的引用

          newOne-&gt;next = list 将指针值从list 复制到newOne-&gt;next。这意味着newOne 指向的Entry 现在有一个next 字段,该字段指向list 指向的同一位置——即列表中的下一个元素。所以我们将新条目链接到列表的尾部。

          list = newOne 将指针值从newOne 复制到list。这意味着指针list 本身——它是列表头部最后一个Entry 的一部分——现在指向newOne 指向的样本位置——即新的Entry。所以我们将列表的头部链接到新条目。

          由于引用,list 是实际指针,它是列表中 Entry 节点的一部分,而不仅仅是一些碰巧指向同一个位置的随机 Entry* 局部变量。

          【讨论】:

            猜你喜欢
            • 2017-08-18
            • 1970-01-01
            • 2021-05-29
            • 2021-05-03
            • 2019-01-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-07
            相关资源
            最近更新 更多