【问题标题】:How to recursively split a linked list after k nodes in C++?如何在 C++ 中的 k 个节点后递归拆分链表?
【发布时间】:2022-01-18 19:31:53
【问题描述】:

我有一个普通的链表:

struct node{
  int info;
  node* next;
};

我需要编写一个递归函数,将 k 个元素后通过引用传递的给定链表拆分为 2,将前 k 个节点留在此列表中,并返回带有其余节点的第二个列表。

我的迭代解决方案如下所示:

node* split(node*&L, int k){
   node* M;
   node* head = L;
   while(k>1){
      head=head->next;
      k--;
   }
   M = head->next;
   head->next = NULL;
   return M;
}


Output:
L: 1 2 3 4 5 6 
after split with: k = 3
L: 1 2 3 
M: 4 5 6 

这似乎工作得很好。现在我真的想不出一个递归解决方案。我正在尝试:

node* splitL(node*&L, int k){
   if(!L) return 0;
   if(k<=1){
      node* x = L->next;
      L->next =  NULL;
      return x;
   }
   L->next = splitL(L->next, k-1);
   return L;

}

这显然是错误的,因为它将 x 返回到 L->next 所以两个列表都变为 1 2 3 4 5 6。

如何为此编写递归函数?参数和返回类型应该保持不变。如果有人能解释我如何将我的迭代解决方案转换为递归解决方案,那就太好了。

【问题讨论】:

  • 这听起来不像需要递归。是什么让您认为需要它?
  • 请提供minimal reproducible example 以证明递归方法的成功和递归方法的失败。
  • 为什么要修改L->next的值:L-&gt;next = splitL(L-&gt;next, k-1);。我认为调用splitL(L-&gt;next, k-1); 并返回该值就足够了
  • 我没有说需要递归来解决这个问题,我显然是用迭代函数解决的。我正在学习递归,这是我一直坚持的练习。
  • @EduardoPascualAseff:是的,你是对的,这可以解决问题。

标签: c++ function recursion linked-list nodes


【解决方案1】:

你目前有

node* split(node*&L, int k){
   node* M;
   node* head = L;
   while(k>1){
      head=head->next;
      k--;
   }
   M = head->next;
   head->next = NULL;
   return M;
}

你想要类似的东西

node* split(node*&L, int k){
   node* M;
   node* head = splitPoint(L, k);
   M = head->next;
   head->next = NULL;
   return M;
}

node* splitPoint(node*&L, int k){
   if (k <= 0)
     return L;
   return splitPoint(L->next, k - 1);
}

注意这个和你原来的守卫k 大于列表的长度。

单功能版:

node* split(node*&L, int k){
   if (k <= 0)
   {
     node* head = L;
     node* M = head->next;
     head->next = NULL;
     return M;
   }
   return split(L->next, k - 1);
}

【讨论】:

  • 这是有道理的,但问题是我只能使用一个功能而不是两个。
  • @norislav:我添加了单功能版本。
  • 如果我决定使用两个函数,它们都必须是递归的。从您的示例中拆分出来的功能不是。
  • @norislav:见我的最后一个split() - 它独立于其余部分。
  • 抱歉没有看到评论。对,就是那样!应该是 if (k
【解决方案2】:

起初我没有看到通过引用传递列表指针的意义,但后来我发现它是实现的关键。

我认为你可以这样做:

  • 检查空输入列表;可能是您被要求将输入列表拆分到其末尾之外 (k &gt; list size)。
  • 检查k == 0;这是进行拆分的关键,因此 1) 返回当前的 head 和 2) 将前一个节点的 next 指针设置为 null(如果这是第一次调用,则设置为列表指针本身);您只需将head 设置为null,因为head 是对您在调用split_list 时使用的指针的引用。
  • 否则,请递归调用split_list

[Demo]

node* split_list(node*& head, int k)
{
    if (!head) { return nullptr; }
    if (k == 0) { node* ret{head}; head = nullptr; return ret; }
    return split_list(head->next, k-1);
}

【讨论】:

    猜你喜欢
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    相关资源
    最近更新 更多