单链表的删除

博客围绕含头节点且元素值递增的单链表展开,介绍函数DeleteList的功能,即删除链表中值大于minK且小于maxK的元素。分析了实现该功能所需的临时指针及操作过程,包括指针移动、节点删除和空间释放等,还提及了具体实现代码和删除过程图。

已知单链表L含有头节点,且节点中的元素值以递增的方式排列。下面的函数DeleteList在L中查找所有值大于mink且小于maxK的元素,若找到,则逐个删除,同时释放被删节点的空间。若链表中不存在满足条件的元素,则返回-1,否则返回0。
例如,某单链表如下图(a)所示。若令minK为20、maxK为50,则删除后的链表如图(b)所示。

在这里插入图片描述

链表节点类型定义如下:
    typedef struct Node{
    int data;
    struct Node *next;
    }Node, *LinkList;
    [C函数]
    int DeleteList (LinkList L, int minK, int maxK)
    {  /*在含头节点的单链表L中删除大于minK且小于maxK的元素*/
      Node   *q=L, *p=L->next;  /*p指向第一个元素节点*/
    int delTag=0;
    while (p)
    if  (P->data <= minK)
    {q=p; 
    p= p->next    ;
      }
    else
    if (p->data < maxK)  {  /*找到删除满足条件的节点*/
    q->next= p->next   ;  
    free(p);
    p=  q->next   ;
     delTag=1;
    }
    else  break;
    if (   delTag=0   )
     return -1;
    return 0;
    }

分析:函数DeleteList(LinkList L, int minK, int maxK)的功能是在L在含头节点的单链表L中删除大于minK且小于maxK的元素,因此除了头指针L以外,至少还需要两个临时指针,一个用于遍历链表中的元素,另外一个用于删除节点时重新链接节点,p和q就起这样的作用。
p指向要被删除的节点、q指向要被删除的节点的前驱节点。
具体过程是:如果删除指针指向的数据不符合删除的条件,那么删除指针和遍历指针向后移动,具体实现的代码是:

q=p; 
 p= p->next ;

含义就是将删除指针的位置”赋值“给遍历指针的位置。然后删除指针指向下一节点。之后在进行节点是否符合条件进行相应的操作判断。
如果符合删除节点的条件,则进行删除操作,具体过程就是:
将遍历指针移动到删除指针前面,然后释放删除指针所指节点的空间。之后再将遍历指针所指像的节点的下一个节点赋值给删除指针。
具体实现代码:

   q->next= p->next   ;  
    free(p);
    p=  q->next   ;

删除过程图:
在这里插入图片描述

<think>首先,用户询问的是单链表删除表头和表尾的实现方法。我需要参考提供的引用内容。 回顾引用: - 引用[1]提到了"删除第i个节点",这可能包括表头和表尾。 - 引用[2]讨论了单链表的创建(头插法和尾插法)、打印及删除,但具体代码是创建表头。 - 引用[3]展示了单向链表的初始化和增删节点。 - 引用[4]讨论了单链表的插入和删除,特别是针对位置i的删除。 用户的问题聚焦在删除表头和表尾。表头通常是第一个节点,表尾是最后一个节点。 在单链表中: - 删除表头:由于链表有头节点或无头节点,实现可能不同。引用中提到的链表似乎有头节点。 - 删除表尾:需要遍历到倒数第二个节点,因为它指向最后一个节点。 从引用[2]中,代码显示创建了一个带头节点的链表: ```c struct Node* createList() { struct Node* headNode = (struct Node*)malloc(sizeof(struct Node)); headNode->next = NULL; return headNode; } ``` 这表示头节点是不存储数据的,真正的数据节点从headNode->next开始。 同样,引用[3]中的初始化代码也创建了一个带头节点的链表。 所以,我假链表是带头节点的结构。这样,删除操作会更简单。 关键点: - **删除表头**:假表头是第一个数据节点(即头节点的下一个节点)。删除头节点的第一个数据节点。 步骤: 1. 检查链表是否为空。 2. 如果要删除头节点的下一个节点。 3. 更新头节点的指针。 - **删除表尾**:需要找到倒数第二个节点(tail的前驱),然后删除最后一个节点。 步骤: 1. 遍历链表,直到current->next->next != NULL,这样current是倒数第二个节点。 2. 删除current->next(即最后一个节点)。 3. 置current->next = NULL。 用户指定了"删除表头和表尾",所以我需要提供代码示例。引用提供了C语言的示例,所以我应该用C语言实现。 现在,构建我的回答: - 回答结构清晰,逐步解释。 - 使用中文,因为系统指令要求中文回答。 - 生成相关问题。 - 在引用末尾添加引用标识。 首先,解释删除表头和表尾的方法。 **删除表头(带头节点单链表)**: - 表头是第一个数据节点,即head->next。 - 实现: 1. 如果链表为空(head->next == NULL),则无法删除,返回错误。 2. 否则,保存要删除的节点temp = head->next。 3. 置head->next = head->next->next。 4. 释放temp的内存。 **删除表尾(带头节点单链表)**: - 表尾是最后一个节点。 - 实现: 1. 如果链表为空,无法删除2. 如果只有一个节点(head->next->next == NULL),直接删除它。 3. 否则,遍历链表,找到倒数第二个节点(current->next->next != NULL时停止)。 4. 保存最后一个节点temp = current->next。 5. 置current->next = NULL。 6. 释放temp。 提供代码示例: - 基于引用[2]和[3],使用似的结构。 代码格式:由于是代码块,使用```c```格式。 最后,生成相关问题。 引用相关部分: - 引用[1]提到"删除第i个节点",这与删除特定位置相关。 - 引用[2]提到删除。 - 引用[4]提到插入和删除。 在回答中,自然地添加引用标识,例如在解释后添加。[^1], [^2]等。 完整回答结构: 1. 介绍单链表删除表头和表尾的重要性。 2. 解释删除表头的方法和代码。 3. 解释删除表尾的方法和代码。 4. 生成相关问题。 </think>### 单链表删除表头和表尾的实现方法 单链表是一种常见的数据结构,删除表头(首节点)和表尾(尾节点)是基本操作。链表通常采用带头节点(dummy node)的结构,头节点不存储数据,仅指向第一个数据节点(表头)。以下基于引用内容,逐步解释实现方法(假链表带头节点)。文中使用 C 语言代码示例,确保清晰易懂。 #### 1. **删除表头(删除链表第一个数据节点)** - **方法**:表头是头节点的下一个节点(`head->next`)。删除时需: - 检查链表是否为空(防止空指针错误)。 - 保存待删除节点,更新头节点的指针指向下一个节点。 - 释放被删除节点的内存。 - **时间复杂度**:$O(1)$,因只需常数操作。 - **代码示例**(基于引用[2]和引用[3]的链表结构): ```c #include <stdlib.h> // 定义链表节点结构(引用[3]) typedef struct Node { int data; // 节点数据 struct Node* next; // 指向下一个节点的指针 } Node; // 删除表头函数 void deleteHead(Node* head) { if (head == NULL || head->next == NULL) { return; // 链表为空或无数据节点,无需删除[^1][^2] } Node* temp = head->next; // 保存待删除节点(表头) head->next = temp->next; // 头节点指向新表头 free(temp); // 释放内存 } ``` #### 2. **删除表尾(删除链表最后一个数据节点)** - **方法**:表尾无后继节点(`next = NULL`)。删除时需: - 检查链表是否为空。 - 遍历链表找到倒数第二个节点(表尾的前驱)。 - 更新其指针为 `NULL`,并释放表尾节点。 - **时间复杂度**:$O(n)$,其中 $n$ 为链表长度,因需遍历整个链表。 - **代码示例**(参考引用[4]的遍历逻辑): ```c // 删除表尾函数 void deleteTail(Node* head) { if (head == NULL || head->next == NULL) { return; // 链表为空,无需删除[^1][^3] } Node* current = head; // 遍历至倒数第二个节点(current->next->next == NULL) while (current->next->next != NULL) { current = current->next; } Node* temp = current->next; // 保存待删除节点(表尾) current->next = NULL; // 倒数第二个节点成为新表尾 free(temp); // 释放内存 } ``` #### 关键注意事项 - **链表带头节点**:上述代码假链表有头节点(如引用[2]和[3]所示),头节点本身不存储数据,简化操作逻辑。 - **边界处理**: - 空链表:需检查 `head->next == NULL`,避免运行时错误。 - 单节点链表:删除表尾时,`current` 直接指向头节点,逻辑一致[^4]。 - **内存管理**:C 语言中必须手动释放内存(`free` 调用),防止内存泄漏。 - **时间复杂度分析**:删除表头高效($O(1)$),删除表尾较低效($O(n)$),因单链表无法直接访问尾节点前驱[^1][^4]。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值