Day3—— 删除链表节点、反转链表、创建链表

简介: Day3—— 删除链表节点、反转链表、创建链表

前言


今日文案

与其背着包袱埋头受罪,不如放下包袱享受生活;与其烦躁地抱怨生活命运不公,还不如从容淡定地笑对人生。

关于为什么我拖更了一天:

image.png

昨天是崩溃的一天(哭泣)

一、反转链表


题目描述:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

题目来源:

https://leetcode.cn/problems/reverse-linked-list/

1、双指针写法:


如图:

image.png

这是最基本的单元,pre在前,cur中间,temp在后面,为什么要这么定义呢。如果我们要反转链表,我们就要改变节点中指针域指向的位置,让它指向前一个,cur代表我们要修改的节点,pre是前一个节点,temp,是给梯子cur过来的,保障运输的

代码如下:

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode*cur=head;
    struct ListNode*pre=0;
    struct ListNode*temp=0;
    while(cur)                        //cur==0,就退出循环
    {
        temp=cur->next;                //temp进入下一个节点待命,准备运输
        cur->next=pre;                //cur指向上一个节点
        pre=cur;                        //pre过来
        cur=temp;                    //运输cur
    }
    return pre;
}

关键点:pre一定要先与cur移动,不然它就找不到位置了

2、递归写法:


我们在双指针写法里面大致分为两个部分:改变节点链接方向,整体前移。那么我们的函数本身就是传值的,只需要在函数里面写出改变方向的代码,然后再利用函数递归来传值就可以实现了。

struct ListNode* reverse(struct ListNode*cur,struct ListNode*pre)
{
    struct ListNode*temp=0;
    if(cur==0)                    //cur==0就返回
    return pre;
    temp=cur->next;            //改变链表值
    cur->next=pre;
    return reverse(temp,cur);        //赋值,把temp赋值给cur,cur赋值给pre,和双指针中类似
}
struct ListNode* reverseList(struct ListNode* head){
    return reverse(head,0);
}

二、移除链表元素


题目来源:

力扣

这题其实并不难,就是找到要移除的节点,然后把它前一个节点链接到它后一个节点,把它架空就行,但我在这里遇到了极其多的空指针异常!!!

代码如下

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode*temp=head;
    while(head&&head->val==val)        //判断头节点是否是空或者是否要删除
    {
        head=head->next;
        free(temp);
        temp=head;
    }
    struct ListNode*p=head;
    while(p&&(temp=p->next))        //temp去到p的下一个节点
    {
        if(temp->val==val)            //要删除temp位置
        {
           p->next=temp->next;  //p(此时在temp也就是要删节点的上一个节点),指向temp下一节点
           temp=temp->next;         //temp往前走
        }
        else
        {
            p=p->next;            //如果没有要删的,整体前移就好,继续寻找
        }
    }
    return head;
}

这里我还是想说一下空指针的问题,我深受其害!!!

借用一下小伙伴的图(反转链表的题):

image.png

image.png

一个是把temp放在while外面定义一个放while里面,为啥会报错一个正常呢!!

首先,指针可以是空的,但不能操控空指针,在外边定义的temp已经是cur->next了,在循环里面cur==0的时候,temp早已经是0,这样操作就会出现空指针异常!!希望对各位有一点帮助。

三、创建链表


题目来源:

力扣

题目分析:

这道题基本包含了链表的所有基础操作,增删改查。

typedef struct {
    int val;
    struct MyLinkedList* next;
} MyLinkedList;
MyLinkedList* myLinkedListCreate() {
    MyLinkedList*head=(MyLinkedList*)malloc(sizeof(MyLinkedList));
    head->next=0;
    return head;
}
int myLinkedListGet(MyLinkedList* obj, int index) {
    MyLinkedList *cur = obj->next;
    for (int i = 0; cur != NULL; i++){
        if (i == index){
            return cur->val;
        }
        else{
            cur = cur->next;
        }
    }
    return -1;
}
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    MyLinkedList*p=(MyLinkedList*)malloc(sizeof(MyLinkedList));
    p->val=val;
    p->next=0;
    p->next=obj->next;
    obj->next=p; 
}
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    MyLinkedList*temp=obj;
    MyLinkedList*p=(MyLinkedList*)malloc(sizeof(MyLinkedList));
    p->val=val;
    p->next=0;
    while(temp->next)
    {
        temp=temp->next;
    }
    temp->next=p;
}
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    MyLinkedList*p=(MyLinkedList*)malloc(sizeof(MyLinkedList));
    p->val=val;
    p->next=0;
    MyLinkedList*temp=obj;
    for(int i=0;i<index;i++)
    {
        temp=temp->next;
        if(temp==0)
        return;
    }
    p->next=temp->next;
    temp->next=p;
}
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    if (index == 0){
        MyLinkedList *tmp = obj->next;
        if (tmp != NULL){
            obj->next = tmp->next;
            free(tmp);     
        }
        return;
    }
    MyLinkedList *cur = obj->next;
    for (int i = 1 ;cur != NULL && cur->next != NULL; i++){
        if (i == index){
            MyLinkedList *tmp = cur->next;
            if (tmp != NULL) {
                cur->next = tmp->next;
                free(tmp);
            }
            return;
        }
        else{
            cur = cur->next;
        }
    }
}
void myLinkedListFree(MyLinkedList* obj) {
   while(obj != NULL){
        MyLinkedList *tmp = obj;
        obj = obj->next;
        free(tmp);
    }
}

下面就总结几个核心的点吧,实在写不动了:

1、注意空指针异常。

2、注意头节点是否需要删除。

3、注意遍历的边界。

总结


算法训练的第三天,好难了,哭泣!

相关文章
|
6天前
|
算法
【优选算法专栏】专题九:链表--------两两交换链表中的节点
【优选算法专栏】专题九:链表--------两两交换链表中的节点
18 0
链表遍历,链表查找和统计节点,链表插入新节点,链表删除节点,链表修改指定节点,链表头插法,尾插法总结
链表遍历,链表查找和统计节点,链表插入新节点,链表删除节点,链表修改指定节点,链表头插法,尾插法总结
|
6天前
|
存储 Java
高效删除链表倒数节点最优实现
要删除链表的倒数第 n 个节点,并返回链表的头节点,我们可以使用一趟扫描的方法来实现。这个方法涉及使用两个指针:快指针和慢指针。
|
6天前
|
存储 算法 编译器
【C/C++ 数据结构 线性表】 数据结构 解析 链表中哨兵节点(伪节点)的作用
【C/C++ 数据结构 线性表】 数据结构 解析 链表中哨兵节点(伪节点)的作用
21 0
|
6天前
leetcode2487.从链表中移除节点
leetcode2487.从链表中移除节点
21 1
|
6天前
|
C语言
【C语言】Leetcode 876. 链表的中间节点
【C语言】Leetcode 876. 链表的中间节点
19 0
|
6天前
|
C语言
反转链表、链表的中间结点、合并两个有序链表【LeetCode刷题日志】
反转链表、链表的中间结点、合并两个有序链表【LeetCode刷题日志】
|
6天前
|
设计模式 测试技术
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
24 1
|
6天前
|
存储 算法 Java
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
43 0
|
6天前
|
Java
LeetCode题解- 两两交换链表中的节点-Java
两两交换链表中的节点-Java
15 0