C ++链接列表递归问题

时间:2011-08-02 01:08:03

标签: c++ recursion linked-list

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

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的调用如何管理将列表的前部连接到新创建的列表。

由于

5 个答案:

答案 0 :(得分:6)

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

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

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

您想插入5

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

InsertSorted(myList, someNode);

该函数内的list引用该函数外的myList ,并将其更改为 更改外部 >。现在,由于list不是NULLnewOne->name不是< list->name,因此未通过if条件。因此,该函数使用list的{​​{1}}指针和next调用自身。这就是我们现在所处的位置:

newOne

在下一个电话中,1 -> 4 -> 6 -> 7 -> 10 -> NULL ^ list refers to this one 5 ^ this is newOne, floating off somewhere by itself 引用上一次通话中的list,这意味着它引用list->next。同样4不满意,所以我们继续if:再次使用else调用该函数(请记住list->next现在引用list,使4引用此调用中的list->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的{​​{1}}指针,代表next。这是列表的样子:

4

这次,6 满意(因为5 <6),所以我们

  1. 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。这使得代表newOne->next的新节点指向其list节点的5

  2. 6设为next。这可能令人困惑,但请记住list引用,这意味着更改它会更改原始内容。当newNode引用list时,原始文件为list->next,因此它与设置指向list的{​​{1}}指向点的节点相同到4

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

    4

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

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

    您需要考虑三个角落案例:

    1. 该列表为空(立即next
    2. 您要插入的元素小于所有现有元素
    3. 您要插入的元素大于所有现有元素
    4. 假设您总是尝试插入newOne作为这些测试的新元素。

      因此,对于第一个,当1 -> 4 -> 5 -> 6 -> 7 -> 10 -> NULL ^ here's newOne 为NULL时 - 也就是说,您的列表看起来像

      list == NULL

      5语句会立即生效,您将list设置为NULL (这意味着ifnewOne->next),{{1}到list。该函数退出,您的列表如下所示:

      newOne->next

      到目前为止,非常好。

      如果要插入的元素小于 比其他所有元素都要小,比如说:

      NULL

      然后立即触发list。您将newOne设置为5 -> NULL ,使其指向7 -> 9 -> NULL 5 ^ newOne ,并将if设置为newOne->next

      list

      这是照顾的。

      最后一个角落的情况是新元素大于所有现有元素。说你有

      7

      作为你的清单。在第一次传递时,list将指向3,newOne将不会被触发。因此,您可以使用5 -> 7 -> 9 -> NULL 调用该函数,该函数指向3 -> NULL 。触发list(因为if)并将list->next设置为NULLif),然后将list == NULL设置为{ {1}},newOne->next指向list,因为在第一次调用中,您通过引用传递了其NULL指针,这意味着更改list会更改它。现在你有:

      newOne

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

      作为旁注,这个函数是尾递归的,但是可以通过迭代而不是递归来使其更快。这是一个很好的学习练习。

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

答案 1 :(得分:0)

这是插入排序,该项目将根据订单插入其放置的列表中。递归将在您到达列表末尾后结束,或者在列表中找到该项目所在的位置。

请注意,对于每个递归调用,您在列表中前进一个链,列表指针的“head”基本上通过列表移动。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

newOne->next = list;

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

list = newOne;

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

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

由于参数是通过引用传递的(如'&amp;'字段所示),因此函数内部所做的更改将在程序中的任何位置持续存在。

答案 4 :(得分:0)

  

我不明白先前对InsertSorted的调用如何管理将列表的前部连接到新创建的列表。

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

算法是:

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

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

当我们结束时,我们执行以下步骤:

newOne->next = list;
list = newOne;

这意味着:

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

这是有效的,因为list对指针的引用

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

list = newOne将指针值从newOne复制到list。这意味着指针list本身 - 它是列表头部的最后一个Entry的一部分 - 现在指向newOne指向的示例位置 - 即新的Entry。因此,我们将列表的头部与新条目相关联。

由于引用,list是列表中Entry节点的一部分的实际指针,而不仅仅是一些恰好指向相同的随机Entry*局部变量的地方。