注意链表的尾部

今天做了Leetcode上面一道题Remove Duplicates from Sorted List II,要去去除链表中重复的节点,代码如下

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode(int x) : val(x), next(NULL) {}
 7  * };
 8  */
 9 class Solution {
10 public:
11     ListNode *deleteDuplicates(ListNode *head) {
12         if(head==NULL||head->next==NULL)
13         {
14             return head;
15         }
16         ListNode *p=head,*prev=new ListNode(0),*head2=prev;
17         int count=0;
18         while(p->next!=NULL)
19         {
20             if(count==0&&p->val!=p->next->val)
21             {
22                 prev->next=p;
23                 prev=p;
24             }
25             else if(p->val==p->next->val)
26             {
27                 count++;
28             }
29             else if(count>0)
30             {
31                 count=0;
32             }
33             p=p->next;
34         }
35         if(count==0)
36         {
37             prev->next=p;
38         }
39        // else
40        //{
41        //     prev->next=NULL;
42        //}
43         head=head2->next;
44         delete head2;
45         return head;
46     }
47 };

注意到39-42行被注释掉的代码,注释掉,会怎么样?

分析一下算法,count表示前面与当前指针val相等的节点个数,对于末尾指针,前面如果没有与其数值相等,则加入链表,否则,则不加入链表,但是,如果末尾指针前面存在与其相等的数,是不是可以不用管它?不是的,因为是原地对链表操作,所以如果不处理的画,那么最后prev的next还是会指向另一个节点,而这个节点并不是我们想要的,所以39-42行必须将prev的next指向空指针。当然对于存在重复的节点,可以直接delete之,如果该节点是分配到堆上的话。

注意链表的尾部

时间: 2024-10-05 14:45:36

注意链表的尾部的相关文章

链表操作法则之逆向遍历与倒置算法

一.创建链表: 对链表进行操作的所有算法的前提,就是我们首先要创建一个链表,我们可以选择正向建链和逆向建链: (一).正向建链: 首先,我们得自定义节点类型: typedef struct Node { int data;//数据域 struct Node * pNext;//指针域 }NODE,*PNODE; 通过数组进行链表数据域的赋值: int main (void) { PNODE pHead;//头指针,接收创建链表时返回的头结点地址 int a[8] = {12,37,49,65,2

剑指Offer之在O(1)时间删除链表节点

题目描述 给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点. 解题思路 在单向链表中删除一个节点,最常规的做法无疑是从链表的头结点开始,顺序的遍历查找要删除的节点,并在链表中删除该节点.这种思路由于需要顺序查找,时间复杂度自然就是$O(n)$了. 之所以需要从头开始查找,是因为我们需要得到将删除的节点的前面一个节点.在单向链表中,节点中没有指向前一个节点的指针,所以只好从链表的头结点开始顺序查找.那是不是一定需要得到被删除的节点的前一个节点呢?答案是否定的.我们可以很方便

【内核数据结构】 内核链表分析

一.简介: Linux中的链表使用两个指针,可以方便的构成双向链表,实际上,通常它都组织成双向循环链表,不同于数据结构书上的链表,这里的节点只有链表指针,没有链表的数据,下边我将对内核中使用的 include/linux/list.h 进行函数说明和生动的图形解释. 二.函数: 我们先来看看 1. 链表数据结构 list_head 的定义: [cpp] view plain copy print? struct list_head { struct list_head *next, *prev;

链表的分化练习题

题目: 对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变. 给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复. 测试样例: {1,4,2,5},3 {1,2,4,5} class Divide {public:    ListNode* listDivide(ListNode* head, int val) { // write

自己用20分钟java实现的单向链表(含有增删改查操作)

package test1; // 建立一个链表结构 public class SingleList { //定义头结点指针 Node head = null; //定义链表的节点数据结构 class Node{ int val; Node next; public Node(int val){ this.val = val; next = null; } } //在链表的尾部增加一个节点 public void add(int num){ Node node = new Node(num);

Linux内核中链表的学习

一.自己学习链表 数组的缺点:(1)数据类型一致:(2)数组的长度事先定好,不能灵活更改. 从而引入了链表来解决数组的这些缺点:(1)结构体解决多数据类型(2)链表的组合使得链表的长度可以灵活设置. 基本概念: 头结点: 这个节点是为了便于管理链表的节点,这个节点并不保存数据:虽然和其他节点一样,但是这个头结点是指向首节点的节点. 首节点: 第一个保存有效数据的节. 尾节点: 最后一个保存有效数据的节点 头指针: 头指针是指向头节点的指针. 单链表: 链表节点的数据结构定义: typedef s

如何在时间复杂度为O(n)空间复杂度为O(1)的情况下完成链表的逆置

问题如题目,首先分析,链表的反转的空间复杂度如果为常数级,那么不可能完成从堆中申请数据来完成链表的反转工作,所以问题就转化为了如何将原链表修改/拆解为逆置的链表: 函数形式假定如下  void Inverse(List*&head)//////修改原链表为逆置 第一种办法最简单,就是在创建一个局部变量 List*tail 作为产生的新链表的“尾部”,再设置一个“游标”指针用于指向当前正在访问的链表单元,然后按顺序循环遍历链表,在遍历的同时将正在访问的链表单元添加到新链表尾部的“tail”指针前面

链表 2.4

编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或者等于x的结点之前. 分析:使用两个链表,若当前结点小于x,则将其插入第一个链表的尾部:否则,将其插入第二个链表的尾部.最后,将两个链表拼接即可. 1 //struct Node { 2 // Node(): val(0), next(0) {} 3 // Node( int value ): val(value), next(0) {} 4 // int val; 5 // Node *next; 6 //}; 7 8 N

java 单链表的实现

package liaobiao;//链表测试public class Node { private int value; private Node next; //存放下一个节点的指针 //构造方法,进行传参 public Node(int value){ this.value = value; } public Node(){ } //像链表的尾部加入元素,需要先找到最后一个节点 public void addNode(Node n ){ //需要先找到最后一个节点 Node node =t