📜  如何编写修改链表头指针的 C 函数?

📅  最后修改于: 2022-05-13 01:57:45.322000             🧑  作者: Mango

如何编写修改链表头指针的 C 函数?

考虑链表的简单表示(没有任何虚拟节点)。对此类链表进行操作的函数可以分为两类:

1) 不修改头指针的函数这些函数的例子包括,打印一个链表,更新节点的数据成员,比如给所有节点添加一个给定的值,或者其他一些访问/更新节点数据的操作
确定此类函数的原型通常很容易。我们总是可以将头指针作为参数传递并遍历/更新列表。例如,以下函数将 x 添加到所有节点的数据成员。

void addXtoList(struct Node *node, int x)
{
    while(node != NULL)
    {
        node->data = node->data + x;
        node = node->next;
    }
}    

2)修改头指针的函数:例子包括,在开头插入一个节点(这个函数总是修改头指针),在末尾插入一个节点(头指针只有在插入第一个节点时才被修改),删除给定节点(当删除的节点是第一个节点时修改头指针)。在这些函数中可能有不同的方法来更新头指针。让我们使用以下简单问题讨论这些方法:

“给定一个链表,编写一个函数deleteFirst() 来删除给定链表的第一个节点。例如,如果列表是1->2->3->4,那么应该修改为2->3->4”

解决问题的算法是一个简单的 3 步过程:(a) 存储头指针 (b) 改变头指针指向下一个节点 (c) 删除前一个头节点。
以下是在 deleteFirst() 中更新头指针的不同方法,以便在任何地方更新列表。




2.1)使头指针全局化:我们可以使头指针全局化,以便可以在我们的函数访问和更新它。以下是使用全局头指针的 C 代码。

// global head pointer 
struct Node *head = NULL;
  
// function to delete first node: uses approach 2.1
// See http://ideone.com/ClfQB for complete program and output
void deleteFirst()
{
    if(head != NULL)
    {
       // store the old value of head pointer    
       struct Node *temp = head;
         
       // Change head pointer to point to next node 
       head = head->next; 
  
       // delete memory allocated for the previous head node
       free(temp);
    }
}

有关使用上述函数的完整运行程序,请参见此处。

这不是推荐的方法,因为它有很多问题,如下所示:
a) head 是全局可访问的,因此可以在项目中的任何地方对其进行修改,并可能导致不可预测的结果。
b) 如果有多个链表,则需要多个不同名称的全局头指针。

请参阅此内容以了解为什么我们应该在项目中避免使用全局变量的所有原因。


2.2)返回头指针:我们可以这样写deleteFirst(),它返回修改后的头指针。无论谁使用这个函数,都必须使用返回值来更新头节点。

// function to delete first node: uses approach 2.2
// See http://ideone.com/P5oLe for complete program and output
struct Node *deleteFirst(struct Node *head)
{
    if(head != NULL)
    {
       // store the old value of head pointer
       struct Node *temp = head;
  
       // Change head pointer to point to next node
       head = head->next;
  
       // delete memory allocated for the previous head node
       free(temp);
    }
  
    return head;
}

有关完整的程序和输出,请参见此处。
这种方法比前一种方法要好得多。只有一个问题,如果用户没有将返回值分配给 head,那么事情就会变得混乱。 C/C++ 编译器允许在不分配返回值的情况下调用函数。

head = deleteFirst(head);  // proper use of deleteFirst()
deleteFirst(head);  // improper use of deleteFirst(), allowed by compiler


2.3)使用双指针:这种方法遵循简单的C规则:如果你想在另一个函数内部修改一个函数的局部变量,传递指向该变量的指针。所以我们可以在我们的 deleteFirst()函数传递指向头指针的指针来修改头指针。

// function to delete first node: uses approach 2.3
// See http://ideone.com/9GwTb for complete program and output
void deleteFirst(struct Node **head_ref)
{
    if(*head_ref != NULL)
    {
       // store the old value of pointer to head pointer
       struct Node *temp = *head_ref;
  
       // Change head pointer to point to next node
       *head_ref = (*head_ref)->next;
  
       // delete memory allocated for the previous head node
       free(temp);
    }
}

有关完整的程序和输出,请参见此处。
这种方法似乎是所有三种方法中最好的,因为出现问题的可能性较小。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程