代码随想录 | Day3(01) 移除链表中的元素(上) c语言

前言:致力于转行的在读建筑硕士,在代码随想录及csdn见证自己在c语言道路上的成长,每一道题目尽可能通过一下顺序:自我编写-问题分析-学习代码-改进方案-知识总结~

题目:力扣203 移除链表元素

https://leetcode.cn/problems/remove-linked-list-elements/submissions/423873813/

方法一:不设置虚拟头节点

一、独立解题

1.1 解题思路

1)判断该链表是否为空链表,如果是,返回NULL

2)创建一个结构体指针cur,指向head

3)构建循环,当cur存在下一个节点时,判断下一个节点是否为val值,如果是,将当前节点的next指向下下个节点;如果不是,将当前指针指向下一个节点。

4)经过上述操作,还剩下一个首元节点没有进行判断。进而判断首元节点是否为val,如果是则将head指向head->next,即NULL。

1.2 要点记录

1)当移除一个不是头节点的元素时,涉及到三个元素:指针当前指向的位置、下一个位置的元素及下下个位置的元素,如图所示:

 相当于删除的是cur指针指向的下一个元素,这是因为单向链表无法找到指针的上一个元素。

2)关于为什么不处理尾节点?

while(cur->next) 当前指针是否有下一个节点进行判断,即相当于判断当前节点是否为尾部节点。

1.3 代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* removeElements(struct ListNode* head, int val){
    if(!head) return NULL;
    struct ListNode* cur = head;
    while(cur->next){
        if(cur->next->val == val){
            cur->next = cur->next->next;
        }
        else{
            cur = cur->next;
        }
    }
    if(head->val == val) head = head->next;
    return head;
}

1.4 代码效果

1.5 存在问题

1) 未考虑内存释放的问题

2) 未能实现动态删除头节点

二、学习过程

2.1参考答案

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* temp;
    // 当头结点存在并且头结点的值等于val时
    while(head && head->val == val) {
        temp = head;
        // 将新的头结点设置为head->next并删除原来的头结点
        head = head->next;
        free(temp);
    }

    struct ListNode *cur = head;
    // 当cur存在并且cur->next存在时
    // 此解法需要判断cur存在因为cur指向head。若head本身为NULL或者原链表中元素都为val的话,cur也会为NULL
    while(cur && (temp = cur->next)) {
        // 若cur->next的值等于val
        if(temp->val == val) {
            // 将cur->next设置为cur->next->next并删除cur->next
            cur->next = temp->next;
            free(temp);
        }
        // 若cur->next不等于val,则将cur后移一位
        else
            cur = cur->next;
    }

    // 返回头结点
    return head;
}

2.2 对比反思

1)关于while(head&&head->val == val)

不可以直接写while(head->val == val) 或者是(head->next),个人理解:如果当前头节点已经指向NULL,就不能对NULL进行val以及next操作;

按照编程语言的逻辑顺序,while(head&&head->val == val)中如果head为空,语句值返回0,并不会运行至下一个语句。

一定要先判断当前节点是否存在

2) 释放内存

注意需要通过设置临时指针变量,将cur指针指向正确位置后,再通过临时指针将要删除的节点进行内存释放。

三、总结反思

3.1 代码修改

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* tmp;
    while(head&&head->val == val){
        tmp = head;
        head = head->next;
        free(tmp);
    }
    struct ListNode* cur = head;
    while(cur && cur->next){
        if(cur->next->val == val){
            tmp = cur->next;
            cur->next = cur->next->next;
            free(tmp);
        }
        else{
            cur = cur->next;
        }
    }
    return head;
}

3.2 细节总结

1)有指向的指针被释放后不能再进行取值或者再指向下一个操作,不能写成如下代码:

 因为如果头节点被删除,cur指针就变成了NULL

注意定义变量的位置,防止这样的现象产生

后记:“慢也好,步子小也好,是在往前走就好了”

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C语言删除链表重复元素,可以采用双重循环的方式,对链表进行遍历,每当遇到重复的元素,就将其删除即可。具体实现步骤如下: 1. 定义一个指针p1,指向链表的第一个节点。 2. 对链表进行遍历,遍历过程使用指针p2指向当前节点的下一个节点。 3. 在p2指向的节点后面进行另一次循环,如果发现p2指向的节点与当前节点p1指向的节点相同,则将p2所指向的节点删除。 4. 将p2指向下一个节点,继续进行循环操作,直到p2指向链表末尾。 5. 将p1指向下一个节点,重复以上操作,直到遍历到链表末尾。 以下是一段示例代码: ```c #include <stdio.h> #include <stdlib.h> typedef struct node { int data; struct node *next; } Node; Node* deleteDuplicates(Node* head) { if (head == NULL) { return NULL; } Node *p1 = head; while (p1 != NULL) { Node *p2 = p1; while (p2->next != NULL) { if (p1->data == p2->next->data) { Node *tmp = p2->next; p2->next = tmp->next; free(tmp); } else { p2 = p2->next; } } p1 = p1->next; } return head; } int main() { // 创建链表 Node *head = (Node*)malloc(sizeof(Node)); head->data = 1; head->next = NULL; Node *p = head; for (int i = 2; i <= 5; i++) { Node *newNode = (Node*)malloc(sizeof(Node)); newNode->data = i % 3 + 1; newNode->next = NULL; p->next = newNode; p = newNode; } // 删除重复元素 head = deleteDuplicates(head); // 输出链表 p = head; while (p != NULL) { printf("%d ", p->data); p = p->next; } printf("\n"); // 释放内存 p = head; while (p != NULL) { Node *tmp = p; p = p->next; free(tmp); } return 0; }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值