学习+刷题:移除链表元素

题目描述:

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

 首先节点的结构体

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
创建节点的时候可以直接ListNode* node=new ListNode(0, head);

意思是node这个节点值是0,指针域里的指针指向的下一个节点是head;

这个题要考虑头节点的值等于目标值时也是需要被删除的。

但是需要注意在链表里面做删除节点的操作时,这个节点必须有前驱。所以需要对头节点做特殊处理。

方法一:

单独判断头节点的值是否需要删除

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
    //必须判断head是否为空,为空的话直接返回head,不再进入循环
         while(head!=NULL&&head->val==val)
         {
             ListNode* temp=head;
             head=head->next;
             delete temp;
         }
         ListNode* cur=head;
         while(cur!=NULL&&cur->next!=NULL)
         {
             if(cur->next->val==val)
             {
                 cur->next=cur->next->next;
             }
             cur=cur->next;
         }
         return head;
    }
};

方法二:

设置虚拟节点,一开始这块我一直不太理解。现在按照自己的想法将链表这块说一下,只是这种说话方便我自己记忆,不一定正确。

无论链表是否为空,头指针都不为空,头指针是链表的必要元素。

一个链表相当于一串珠子,当我拆除某个珠子的时候我需要用到一个工具将这个珠子拿走,并将这个柱子原来两侧的珠子用线穿起来,这个工具相当于一个临时指针或者临时节点,它在不停的干活(去掉珠子),所以它的位置不停变化,由它来引起链表的变化。

前面已经说了,删除链表节点必须有前驱,所以在原链表的基础上再加一个节点,这个节点指向的下一个节点是原来的头节点,那么这个时候我就可以搬出我的工具来对我的链表珠子随意删除。相当于链表是链表,工具是游离在链表外的一个东西。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
         ListNode* dummyhead=new ListNode(0, head);
         ListNode* cur=dummyhead;
         while(cur->next!=NULL)
         {
             if(cur->next->val==val)
             {
                 ListNode* temp =cur->next;
                 cur->next=cur->next->next;
                 delete temp;
             }
             else 
             {
                 cur=cur->next;
             }
         }
         return dummyhead->next;
    }
};

妈呀,这是我自己的故事,我之所以这么来“说服”我自己,是因为我一开始认为dummyhead 和 cur这两个指针在最初指向同一个空间,即head,那么当head->val==val时,这时我们将cur指针指向的空间地址变到了head->next;

但是原来的指针dummyhead指向的地址还是一开始的head啊,没有变化,这是我原来一直不能理解的地方,同样现在我也觉得这种想法好像没错。。。

所以只能用上面的故事来说服自己

在b站上看到了这个视频,还有下面的评论,我觉得对理解链表有很大的用处

【C++链表】这可能是你能在网上找到最详细的C++链表实例讲解。_哔哩哔哩_bilibili

这里再说一下我自己的理解

创建链表的节点的时候跟创建指针的语法差不多ListNode* dummyhead=new ListNode(0)

节点本身就是一种数据结构,而我们最常用的int,一般说成数据类型,但是我觉得他俩本质上是一样的,都是用来定义数据,只不过int更简单一些而已

所以对于节点的数据类型,本身他的数据struct里面就包括了两个(val,next),所以对于node->next改变时,跟我们常说的

“当两个指针在最初指向同一个空间地址时,对其中一个指针指向的数值变化时,另一个指针指向的数值也跟着变化”是同一个意思

所以

 ListNode* dummyhead=new ListNode(0, head);
         ListNode* cur=dummyhead;

这两句代表dummyhead,cur指向同一个节点,那当cur->next 做改变时,dummyhead->next也跟着改变

但是当cur=cur->next;,这时的cur节点就跟一开始的 ListNode* cur=dummyhead;不是同一个节点了,这时候再对cur做改变,dummyhead也不会跟着变了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值