Day03 链表-移除链表元素+设计链表 +反转链表

PID温控实验平台搭建(二)——PID进阶知识介绍及源码分享 最近,我突发奇想去翻阅了一些我本科期间所做的一些小项目,发现都挺有意思的!希望通过我的讲解文章可以帮助你们少走一些弯路!今天,我要分享的是一个PID温控实验平台的搭建,这是一个系列文章,手把手地教你学习和认识PID算法,了解这种算法在温度控制中的应用。由于我知识有限,如果出现一些错误,希望大家可以帮助我指出来,我们一起学习进步!!! 阅读详情

2.linked list


    2.1 introduction


    A linked list is a linear data structure where elements are not stored contiguously in memory. Instead, they are linked together using pointers. 


    Each node in a linked list consists of two parts: a data field and a pointer field (which holds the address of the next node in the list). The pointer field of the last node in the list points to NULL (indicating that it is the end of the list).
    The first node in a linked list is called the head node, often referred to as 'head' in programming contexts. This head node serves as the entry point to the linked list, allowing traversal of the list starting from the beginning.
    
    The key characteristics of a linked list are:
        Dynamic Size: Linked lists can grow and shrink in size as needed, making them ideal for applications where the number of elements is not known in advance.
        Non-contiguous Memory Allocation: Unlike arrays, linked lists do not require contiguous memory allocation. This makes them more flexible but also slightly slower to access individual elements due to the need to traverse the list.
        Pointer-based Navigation: Navigation through a linked list is achieved by following the pointers from one node to the next. This allows for efficient insertion and deletion of elements without the need to shift other elements in the list.
        Circular and Doubly Linked Variants: Linked lists can be modified to form circular linked lists (where the last node points back to the first node) or doubly linked lists (where each node has two pointers: one to the next node and one to the previous node). These variants offer additional flexibility and capabilities.
        
    In summary, a linked list is a powerful data structure that provides flexibility in managing collections of elements, particularly when the size of the collection is not known in advance or when frequent insertions and deletions are required.
    
  

 Type of linked list


        #Single chain list
            What I just said is a single-linked list.
        #Doubly linked list(where each node has two pointers: one to the next node and one to the previous node)
            The pointer field in a singly linked list can only point to the next node of the node.
            Double-linked list: Each node has two pointer fields, one pointing to the next node and one pointing to the previous node. Double-linked lists can be queried both forward and backward.
        #Circular linked list (where the last node points back to the first node)
            A circular linked list, as the name suggests, is a linked list where the head and tail are connected.
            A circular linked list can be used to solve the Josephus ring problem.
    
  

 Storage method of linked list
      

 Arrays are distributed continuously in memory, but linked lists are not distributed continuously in memory.
        A linked list is a data structure in which nodes are linked together in memory through pointers in a pointer field.
        Therefore, the nodes in the linked list are not distributed continuously in memory, but are scattered at certain addresses in memory. The allocation mechanism depends on the memory management of the operating system.

    

2.2 203. Remove Linked List Elements


        Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val == val, and return the new head.
        key point: decide whether it is the head of the list
        
        class ListNode {
            int val;
            ListNode next;
            ListNode() {}
            ListNode(int val) { this.val = val; }
            ListNode(int val, ListNode next) { this.val = val; this.next = next; }
        }
        class Solution {
            public ListNode removeElements(ListNode head, int val) {
            }
        }
        
        Q:how to make a linked list by ListNode class?
        public static void main(String[] args) {  
            // 创建链表的节点  
            ListNode head = new ListNode(2); // 头节点  
            head.next = new ListNode(3);  
            head.next.next = new ListNode(4);  
            head.next.next.next = new ListNode(5);  
            head.next.next.next.next = new ListNode(6);  
            head.next.next.next.next.next = new ListNode(7);        
            // 打印链表(假设我们有一个打印链表的方法)  
            printList(head);  
        }        
        // 辅助方法,用于打印链表  
        public static void printList(ListNode node) {  
            while (node != null) {  
                System.out.print(node.val + " -> ");  
                node = node.next;  
            }  
            System.out.println("null");  
        }  
        

答案:


        有两个方法可以解决从链表中删除元素(两个方法中的cur都是用于遍历列表的临时指针,不可以更改头节点):
        方法1:原链表删除元素。


            public ListNode removeElements(ListNode head, int val) {
                while (head != null && head.val == val) {
                    head = head.next;
                }
                // 已经为null,提前退出
                if (head == null) {
                    return head;
                }
                // 已确定当前head.val != val
                ListNode pre = head;
                ListNode cur = head.next;
                while (cur != null) {
                    if (cur.val == val) {
                        pre.next = cur.next;
                    } else {
                        pre = cur;
                    }
                    cur = cur.next;
                }
                return head;
            }
        ====================================================================
            public ListNode removeElements(ListNode head, int val) {
                while(head!=null && head.val==val){
                    head = head.next;
                }
                ListNode curr = head;
                while(curr!=null){
                    while(curr.next!=null && curr.next.val == val){
                        curr.next = curr.next.next;
                    }
                    curr = curr.next;
                }
                return head;
            }
        方法2:使用虚拟头节点


            public ListNode removeElements(ListNode head, int val) {
                if(head == null) return head;
                //因为删除可能涉及到头节点,所以设置一个val=-1,next=head的虚拟头节点,统一操作
                ListNode dummy = new ListNode(-1,head);
                ListNode cur = dummy;
                while (cur.next != null){
                    if(cur.next.val == val){
                        cur.next = cur.next.next;
                    }else{
                        cur = cur.next;
                    }
                }
                return dummy.next;
            }
    

tips:

    /*
        当你执行 curr.next = curr.next.next; 时,你实际上是在修改链表的结构,即删除了 curr.next 所指向的节点(这个节点的值等于 val)。
        这个操作是通过改变 curr 引用所指向的节点的 next 指针来实现的,而不是通过删除 curr 引用本身。

        curr = curr.next; 这行代码的作用是将 curr 引用移动到链表的下一个节点。这并不会删除任何节点,只是改变了 curr 引用所指向的对象。
        在这个上下文中,一旦 curr.next 被设置为 curr.next.next(即删除了一个节点),curr 就需要移动到下一个有效的节点上,以便继续检查链表中的剩余部分。

        这部分难以理解的问题:
        在cur = cur.next中,cur属性val和next为什么不会变成cur.next的val和next?
        解答:
        在 cur = cur.next; 这行代码中,cur 是一个变量,它持有对链表中某个节点的引用。当你执行这行代码时,你并没有改变 cur 之前所引用的节点的任何属性(如 val 或 next),你只是改变了 cur 变量本身所持有的引用,使其指向链表中的下一个节点。
        这里有几个关键点需要理解:
        变量与引用:在Java中,变量(如 cur)不是对象本身,而是对对象在内存中位置的引用(或者说是指针)。当你将 cur 设置为 cur.next 时,你实际上是在改变 cur 变量所持有的引用,使其指向 cur.next 所引用的对象。
        对象不变性:链表中的节点(即 ListNode 对象)一旦创建,它们的 val 和 next 属性(除非在代码中显式修改)就不会因为某个变量引用的改变而改变。这是因为 val 和 next 是节点对象的属性,而不是变量的属性。
        操作结果:执行 cur = cur.next; 后,cur 现在引用的是链表中的下一个节点。但是,之前的节点(即 cur.next 之前所引用的节点)仍然存在于内存中,除非没有其他引用指向它(这时它可能会被垃圾回收器回收)。然而,这个节点的 val 和 next 属性保持不变,因为它们与 cur 变量的变化无关。
        链表结构的变化:虽然 cur 变量的引用改变了,但如果你之前通过 cur 修改了链表的结构(比如通过 cur.next = cur.next.next; 删除了一个节点),那么这种修改是持久的,并且会影响到链表的其余部分。但是,这种修改是通过操作 cur 所引用的节点的 next 属性来实现的,而不是通过改变 cur 变量本身来实现的。
        综上所述,cur = cur.next; 这行代码只会改变 cur 变量所持有的引用,而不会改变链表中任何节点的 val 或 next 属性。如果你想要修改节点的属性,你需要直接操作该节点的属性(如 cur.val = newValue; 或 cur.next = newNextNode;),而不是改变引用变量的值。
         */
    


    2.3 707. Design Linked List


    Design your implementation of the linked list. You can choose to use a singly or doubly linked list.
    A node in a singly linked list should have two attributes: val and next. val is the value of the current node, and next is a pointer/reference to the next node.
    If you want to use the doubly linked list, you will need one more attribute prev to indicate the previous node in the linked list. Assume all nodes in the linked list are 0-indexed.
    Implement the MyLinkedList class:
    MyLinkedList() Initializes the MyLinkedList object.
    int get(int index) Get the value of the indexth node in the linked list. If the index is invalid, return -1.
    void addAtHead(int val) Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
    void addAtTail(int val) Append a node of value val as the last element of the linked list.
    void addAtIndex(int index, int val) Add a node of value val before the indexth node in the linked list. If index equals the length of the linked list, the node will be appended to the end of the linked list. If index is greater than the length, the node will not be inserted.
    void deleteAtIndex(int index) Delete the indexth node in the linked list, if the index is valid.
    
    class MyLinkedList {
        public MyLinkedList() {        }        
        public int get(int index) {        }        
        public void addAtHead(int val) {        }        
        public void addAtTail(int val) {        }        
        public void addAtIndex(int index, int val) {        }        
        public void deleteAtIndex(int index) {        }
    }    
    
    /*
    Your MyLinkedList object will be instantiated and called as such:
        MyLinkedList obj = new MyLinkedList();
        int param_1 = obj.get(index);
        obj.addAtHead(val);
        obj.addAtTail(val);
        obj.addAtIndex(index,val);
        obj.deleteAtIndex(index);
     */
    
        public void addAtHead(int val) {
            ListNode dummy = new ListNode(-1,head);
            ListNode cur = dummy;
            ListNode node = new ListNode(val);
            node.next = cur.next;
            cur.next = node;
            size++;
            this.head = dummy.next;        
        }
  

 答案:


    class ListNode {
        int val;
        ListNode next;
        ListNode(){}
        ListNode(int val) {
            this.val=val;
        }
    }
    class MyLinkedList {
        //size存储链表元素的个数
        int size;
        //虚拟头结点
        ListNode head;
        //初始化链表
        public MyLinkedList() {
            size = 0;
            head = new ListNode(100);
        }

        //获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
        public int get(int index) {
            //如果index非法,返回-1
            if (index < 0 || index >= size) {
                return -1;
            }
            ListNode currentNode = head;
            //包含一个虚拟头节点,所以查找第 index+1 个节点
            for (int i = 0; i <= index; i++) {
                currentNode = currentNode.next;
            }
            return currentNode.val;
        }

        //在链表最前面插入一个节点,等价于在第0个元素前添加
        public void addAtHead(int val) {
            addAtIndex(0, val);
        }

        //在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
        public void addAtTail(int val) {
            addAtIndex(size, val);
        }

        // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
        // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
        // 如果 index 大于链表的长度,则返回空
        public void addAtIndex(int index, int val) {


            if (index > size) {
                return;
            }
            if (index < 0) {
                index = 0;
            }
            size++;
            //找到要插入节点的前驱
            ListNode pred = head;
            for (int i = 0; i < index; i++) {
                pred = pred.next;
            }
            ListNode toAdd = new ListNode(val);
            toAdd.next = pred.next;
            pred.next = toAdd;
        }

        //删除第index个节点
        public void deleteAtIndex(int index) {
            if (index < 0 || index >= size) {
                return;
            }
            size--;
            if (index == 0) {
                head = head.next;
            return;
            }
            ListNode pred = head;
            for (int i = 0; i < index ; i++) {
                pred = pred.next;
            }
            pred.next = pred.next.next;
        }
    } 

tips:

重点:需要知道第n个节点的前一个节点的指针,才可以对第n个节点做操作。    
    //假如要删除第0个节点,那么第0个节点就是cur.next,无需对cur做操作,即无需进入循环。
    卡住的地方:
    初始化链表:head = new ListNode(100);此处的head就是之前的dummy。head实际的第0个值是100。所以在get(index)方法中,for循环i需要<=index,即index=0时也要循环一次。
    之前错误出在addAtHead,在最后未给实例的head属性赋值。那head就一直是null,所以出现了空指针。


    2.4 206. Reverse Linked List


    Given the head of a singly linked list, reverse the list, and return the reversed list.
    1.dual pointer


        public ListNode reverseList(ListNode head) {
            ListNode cur = head;
            ListNode pre = null;
            while(cur != null){
                ListNode temp = cur.next;
                cur.next = pre;
                pre = cur;
                cur = temp;
            }
            return pre;
        }
    2.recursion
        public ListNode reverseList(ListNode head) {
            return reverse(head,null);
        }        
        public ListNode reverse(ListNode cur, ListNode pre){
            if(cur == null)return pre;
            ListNode temp = cur.next;
            cur.next = pre;
            return reverse(temp,cur);
        }

算法巡练day03Leetcode203移除链表元素707设计链表206反转链表 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点。为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。, 这才是新的头结点。变量在删除链表节点的过程中发挥着重要的作用,既确保了链表结构的完整性,又避免了潜在的内存泄漏问题。 阅读详情

相关推荐

【考试大纲】中级多媒体应用设计师考试大纲

中级多媒体应用设计师考试大纲

邓邓子的博客 333

算法Day03链表–203. 移除链表元素,707. 设计链表,206. 反转链表

Day03--链表--203. 移除链表元素,707. 设计链表,206. 反转链表

m0_60740070的博客 330

RTL8309M-RTL8201F DEMO评估板参考设计CADENCE原理图+RTL8309M-CG-Datasheet文件.zip

RTL8309M_RTL8201F DEMO评估板参考设计CADENCE原理图+RTL8309M-CG_Datasheet文件,可供学习及设计参考。

day03 移除链表元素 设计链表 反转链表

②获取链表的某个节点值 (index从0开始,head的index为0)删除链表中所有满足Node.val==val的节点 返回新的头节点。如果想要使用这个量用于while循环的条件判定,根据链表的头节点head 返回反转后的链表。,代码如下,这时,代码就是正确的了。⑤在第n个节点处插入一个节点。③在头节点前面插入一个节点。④在尾节点后面插入一个节点。

qq_43773652的博客 972

代码随想录Day03移除链表元素 设计链表 反转链表

链表基础题目

smile_Lululu7777的博客 997

day03 移除链表元素设计链表反转链表

移除链表元素设计链表反转链表

mqy224512的博客 499

Day03 链表理论基础,203移除链表元素,707.设计链表,206.反转链表

示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]示例 3: 输入:head = [7,7,7,7], val = 7 输出:[]修改前一个节点的指针,使其指向要移除节点的下一个节点,从而“跳过”要移除的节点。修改前一个节点的指针,使其指向要移除节点的下一个节点,从而“跳过”要移除的节点。1.链表是一种线性数据结构,但与数组不同,链表中的元素在内存中不是连续存储的。如果移除的是头节点,通常需要特殊处理,因为头节点没有前一个节点。

luo_12230527的博客 1716

算法学习day03移除链表元素设计链表反转链表(Java)

链表是一种存储数据的方法,由一个个节点组成,每一个节点包括自身的值和下一个节点的地址(单向链表),最后一个节点指向的地址为nullJava中没有单向链表,需要自己手搓一个出来以下代码为单向链表ListNode。

2301_80840872的博客 1469

day03链表基础_移除链表元素_设计链表_反转链表

力扣移除链表元素设计链表反转链表

m0_59684747的博客 3499

day03 链表部分 203移除链表元素 707设计链表 206反转链表

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。链表的入口节点称为链表的头结点也就是head。数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。各个节点分布在内存的不同地址空间上,通过指针串联在一起。:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。(如上图所示):单链表中的指针域只能指向节点的下一个节点。,将原链表的所有节点按照统一的方式进行移除

qq_51761883的博客 1058

day03| 203.移除链表元素 707.设计链表 206.反转链表

1、注意while与if的顺序2、注意while(head!=null&&head.val == val)与if(head==null)顺序不可变,万一为【7,7,7,7,7】,head节点就变成了null,无法执行之后的代码// 定义单链表int val;// 链表元素的个数int size;size = 0;return -1;// 包含一个虚拟头结点i<=index;return;

m0_65709641的博客 1078

Day03 | 203.移除链表元素 707.设计链表 206.反转链表

第五个类void addAtIndex(int index, int val)先定义值为val的新节点,判断index的长度,如果是0放在头节点,遍历到index的前一个节点进行插入。第三个类void addAtHead(int val) 插入一个元素之前,虚拟头节点派上用处了,定义一个新的节点,然虚拟头节点的next指向新节点。第四个类void addAtTail(int val) 追加最后一个节点,遍历到最后一个节点,定义一个新节点,让最后一个节点的next等于新节点。如果下标无效,则返回 -1。

q864508127的博客 887

Day03.链表/203.移除链表元素 707.设计链表 206.反转链表

203能够独立完成707没有办法独立完成,基础不扎实206思路想到了,但是反转的逻辑有点不对日期:2024.4.23。

m0_65529181的博客 1945

DAY03|203.移除链表元素、707.设计链表、206.反转链表

鸡皮题:地址指向的修改是影响的,但是在你的代码中,你只是通过改变pre->next指针的指向来实现删除节点的操作,并没有改变head指针本身的值。卡哥说:还要说明一下,就算使用C++来做leetcode,如果移除一个节点之后,没有手动在内存中删除这个节点,leetcode依然也是可以通过的,只不过,内存使用的空间大一些而已,但建议依然要养成手动清理内存的习惯。如果你希望返回的是修改后的链表头节点,你可以在函数内部维护一个新的指针变量来记录新的头节点,然后在操作结束后返回这个新的头节点。

weixin_49795728的博客 1243

【python算法打卡Day03】0816:LeetCode 203 移除链表元素、707 设计链表、206 反转链表

算法练习

huayaomi2370的博客 1488

day03 203-移除链表元素 707-设计链表 206-反转链表

移除链表元素题干:给你一个链表的头节点head和一个整数val,请你删除链表中所有满足的节点,并返回。[][][0, 104]因为大一刚学完还是对链表有不少印象的。这题可以有俩种思路去考虑,一种是使用原指针去删除节点;另一种是添加虚拟头结点来删除。前者必须考虑删除的是头节点位置还是非头结点位置的值(二者删除方式不同)需要使用俩个while循环处理;后者的删除方式一直 只需要一个while循环即可。接下来给出俩个方式的代码。

2401_87983916的博客 1144

力扣打卡Day03 移除链表元素+设计链表+反转链表

这个题还是挺有必要细看的,难度不大,主要是在于链表类的构建,一些公共类、私密类的变量和函数。对链表还是挺熟的,基本没有不理解的地方,大二的时候也设计链表了,不过不太懂力扣上的链表怎么设计的,看了题解也会了。除了递归,很难想,没脑子想,之前看过别人写的,递归只有几个条件的,改天看看。考完试真的好困,写完博客去睡觉了zzz已经没脑子接着看了,水一天博客了,不过我告诉自己能写就是胜利。用的迭代,还是那经典四步,pre、cur、temp三个节点的next连来连去的。要注意循环的条件以及返回的值!

Lumory的博客 788

day03 代码随想录算法训练营 (移除链表元素设计链表反转链表

链表的基本操作,反转链表。内容基础但是很重要。

I_CLK的博客 852

day03 ​ 203. 移除链表元素​ 707. 设计链表 206. 反转链表

文档讲解:代码随想录(完成状态: true。

qq_45340829的博客 655

代码随想录Day03:203.移除链表元素、707.设计链表、206.反转链表

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

Qlq0075的博客 1761

GXF 3.2.0 to 4.0 CUDA 12 路径 API 与数据结构增量分析

分析范围:以仓库中与分支对比为基础,聚焦)可用的公共 API 与数据结构变化。由于 GXF 核心头文件在各 CUDA 版本间共享,下列新增/修改的接口在 CUDA 12 构建上同样生效。对比链接:https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_nitros/compare/release-3.2…release-4.0。

eloudy的专栏 257
上一篇: Day02 数组-双指针+spiralMatrix
下一篇: Day04 链表-交换元素+移除特定元素+查交界点 +循环链表
just_sleeeeep
博客等级 码龄2年 270粉丝 35原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值