【问题标题】:Understanding type functions with linked-list用链表理解类型函数
【发布时间】:2019-05-03 22:05:02
【问题描述】:

大家早上好/晚上好, 我想在脑海中澄清以下关于链表函数的概念(在这种情况下是递归的)。

让我们采用以下程序,递归地消除链表中的重复项:

ElementoDiLista* deleteDuplicates(ElementoDiLista* head)
{
    if (head == NULL)
    {
        return NULL;
    }
    if (head->next == NULL)
    {
        return head;
    }
    if (head->info == head->next->info)
    {
        ElementoDiLista *tmp;
        tmp = head->next;
        head->next = head->next->next;
        free(tmp);
        return deleteDuplicates(head);
    }
    else
    {
        head->next = deleteDuplicates(head->next);
        return head;
    }
} 

使用我的结构定义并以这种方式列出:

struct el {int info; struct el *next;};
typedef struct el ElementoDiLista;
typedef ElementoDiLista *ListaDiElementi; 

然后我主要以这种方式调用函数:

Lista1 = deleteDuplicates(Lista1);

Lista1 声明如下:ElementoDiLista Lista1 = NULL

我的问题是,我习惯于声明无效或依赖于单一类型的函数(int、float ecc...) 我想澄清两件事:

  1. 为什么函数被声明为ElementoDiLista* deleteDuplicates(ElementoDiLista* head),因为对我来说它更直观ListaDiElementi deleteDuplicates (ListaDiElementi *head),但不幸的是,它不起作用。

  2. 我不太清楚为什么函数返回 head 或 NULL 值,但这就是我认为为什么在主 Lista1 中取函数值的原因,因为函数会修改列表本身,我我对吗?

很抱歉,如果这些问题不是很令人兴奋,我只是在努力理解一般的列表并且非常困难, 任何帮助或建议将不胜感激,

还是谢谢大家!

【问题讨论】:

  • 该函数修改了列表的头部,所以它需要以某种方式将信息返回给调用者。出错时返回 NULL。可以是void deleteDuplicates(ElementoDiLista **head),您可以在其中修改函数内部的头指针。你想返回指针,而不是数据。
  • ElementoDiLista *等同于ListaDiElementi,因此您可以使用这些声明中的任何一个。
  • ElementoDiLista* deleteDuplicates(ElementoDiLista **head) 有效吗?
  • 注意:不鼓励在 typedefs 中隐藏指针。所以不鼓励typedef ElementoDiLista *ListaDiElementi;(因为现在还不清楚它是否与指针有关)。
  • @PaulOgilvie 很抱歉可以更具体吗?

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


【解决方案1】:

为什么函数被声明为ElementoDiLista* deleteDuplicates(ElementoDiLista* head),因为对我来说这样ListaDiElementi deleteDuplicates (ListaDiElementi *head)更直观

从参数开始,最初它被声明为,

ElementoDiLista* head

所以它需要一个指向头元素的指针。这将等同于(更改变量名),

ListaDiElementi list 

所以我们传递一个“列表”作为参数,它是一个指向头部的指针。该指针未修改。要修改它,我们确实需要按照您的建议使用,

ElementoDiLista** head

或同等地,也许更具可读性,

ListaDiElementi* list 

因此问题是,“我们是否需要修改指向头部的指针”? 或者换句话说,是否需要修改原始列表指针?答案是

如果列表为空,它将保持为空。如果列表不为空,则头部将保持不变。您不会删除头部,只有后面的节点具有与头部相同的值。

我不是很清楚为什么函数返回 head 或 NULL 值,但这就是我认为为什么在主 Lista1 中取函数值的原因,因为函数会修改列表本身,对吗?

我个人不喜欢该函数返回一个指向元素(即列表)的指针。此外,它似乎总是返回head,并以相当模糊的方式实现。

首先关于我不喜欢它。如果您正在更改现有列表的结构,而不是创建一个新列表,您希望初始指针在该过程之后保持有效。因此,您更改该指针(如果需要)而不是返回一个新指针。在这种情况下,它甚至不会改变。所以我要么拥有它void,要么返回一些退出代码。

再看代码,

if (head == NULL)
{
    return NULL;

它返回head,因为它为空。

if (head->next == NULL)
{
    return head;

它又回来了。

if (head->info == head->next->info)
{
    ElementoDiLista *tmp;
    tmp = head->next;
    head->next = head->next->next;
    free(tmp);
    return deleteDuplicates(head);
}

它返回deleteDuplicates(head)head 是没有改变的原始参数。因此,如果所有其他情况都返回头部,那么这个也是。

else
{
    head->next = deleteDuplicates(head->next);
    return head;
}

这也返回head(注意head 没有改变)。所以它的返回值始终是原始参数head。所以这是没有意义的。

另外请注意,在前两种情况下,您什么都不做,只是返回一个无用的值。

if (head == NULL)
{
    return NULL;
}
if (head->next == NULL)
{
    return head;
}

因此,如果您将程序更改为void,此代码就会消失。如果您的列表或其尾部为空,您无需执行任何操作,因为没有重复项。

【讨论】:

    猜你喜欢
    • 2014-05-04
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多