【问题标题】:Recursively delete all occurences of an element in a singly linked list递归删除单链表中所有出现的元素
【发布时间】:2021-05-14 11:41:44
【问题描述】:

我正在学习使用 C 的数据结构和算法,但我不知道如何递归地解决这个问题。

它有简单的迭代解决方案,但我需要一些递归版本的帮助。

这是我的递归版本:

void delAllOcc(node** headRef,int key) {
    node * prev;
    if (*headRef != NULL && (*headRef)->data == key) {
        prev = *headRef;
        *headRef = (*headRef)->next;
        free(prev);
    }
    else {
        if (*headRef != NULL) {
            delAllOcc(&(*headRef)->next,key);
        }
    }
}

【问题讨论】:

  • 请注意,递归解决这个问题是一个非常糟糕的主意,因为它的效率较低,而且对于很长的列表,您可能会遇到堆栈溢出
  • 该代码是 recursive 而不是 iterative - 您声明它是您的 iterative 版本。碰巧的是,您对递归解决方案的诚实尝试对任何回答的人都更有用,您的工作迭代解决方案几乎没有什么相关性。递归是计算机科学课程钟爱的“巧妙技巧”——在现实世界中最好避免使用,因为真正的计算机具有有限的堆栈。在这种情况下,您的列表长度很容易超过最大调用堆栈深度。学习它,通过你的课程,然后知道要谨慎使用,当然不要在这种不受约束的情况下使用。
  • 是的,我应该提到这是我的递归尝试,我写错了,我的错。感谢您的解释,非常感谢。

标签: c recursion linked-list singly-linked-list function-definition


【解决方案1】:

不幸的是,最干净的递归解决方案不使用尾递归:


#include <stdlib.h>

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

struct node *del_recursive (struct node *ptr, int key)
{
if (!ptr) return ptr;

ptr->next = del_recursive(ptr->next, key);
if (ptr->key == key) {
        struct node *del = ptr;
        ptr=ptr->next;
        free(del);
        }
return ptr;
}

这个版本确实使用尾递归,但 gcc -O3 似乎没有吃掉它:


struct node *del_recursive_tail (struct node *ptr, int key)
{
if (!ptr) return ptr;

if (ptr->key == key) {
        struct node *del = ptr;
        ptr=ptr->next;
        free(del);
        }
if (!ptr) return ptr;
ptr->next = del_recursive_tail(ptr->next, key);
return ptr;
}

注意:我用普通指针替换了指向指针的参数,并将返回类型更改为指针。否则,递归就没有意义了。

【讨论】:

  • 谢谢,您的解决方案真的很有帮助。我应该提到它是递归的而不是迭代的。
  • @wildplasser 对于初学者来说,这条语句“我用普通指针替换了指针到指针的参数,并将返回类型更改为指针。否则,递归将毫无意义。”没有意义。其次,您提供的代码有一个错误。
  • @RoyLy :它递归的。没有循环。
  • 你的是递归的,我的也是,但在我的代码上面我说这是一个迭代版本,这是错误的。 @wildplasser
【解决方案2】:

您的函数在删除节点时不会调用自身。

看这段代码sn-p

if (*headRef != NULL && (*headRef)->data == key) {
    prev = *headRef;
    *headRef = (*headRef)->next;
    free(prev);
}

函数本身没有递归调用。

函数可以如下所示

void delAllOcc( node **headRef, int key ) 
{
    if ( *headRef != NULL )
    {
        if ( ( *headRef )->data == key )
        {
            node *tmp = *headRef;
            *headRef = ( *headRef )->next;
            free( tmp );
        }
        else
        {
            headRef = &( *headRef )->next;
        }

        delAllOcc( headRef, key );
    }
}

要获得迭代解决方案,只需将 if 语句替换为 while 语句并删除递归调用。

void delAllOcc( node **headRef, int key ) 
{
    while( *headRef != NULL )
    {
        if ( ( *headRef )->data == key )
        {
            node *tmp = *headRef;
            *headRef = ( *headRef )->next;
            free( tmp );
        }
        else
        {
            headRef = &( *headRef )->next;
        }
    }
}

【讨论】:

  • 感谢您的解决方案。以上是我的递归版本,而不是迭代版本。对不起,我写错了。
猜你喜欢
  • 2017-12-28
  • 1970-01-01
  • 2018-06-04
  • 2020-08-03
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
相关资源
最近更新 更多