代码随想录训练营Day3 | 链表理论基础 | 203.移除链表元素 | 707.设计链表 | 206.反转链表

今天任务:学习链表理论基础                                     
                        链表的类型                                          
                        链表的存储方式                                   
                        链表的定义                                          
                        链表的操作                                          
                        性能分析                                             

学习文档:代码随想录 (programmercarl.com)

链表的类型单链表、双链表、循环链表(区别就在于其结构不同)

 链表是一种常用的数据结构,通过指针串联在一起,相对于数组有以下几方面优点:

  1. 动态大小:链表的大小是动态的,可以在运行时根据需要进行扩展或缩减。而数组的大小在声明时就固定了,不能动态改变。

  2. 内存利用率:链表不需要像数组那样预先分配一块连续的内存空间,因此可以更有效地利用内存,尤其是在内存碎片较多的情况下。

  3. 插入和删除操作搞笑:在链表中,插入和删除节点通常只需要改变指针,而不需要移动其他元素。这使得链表在插入和删除操作上比数组更高效,因为数组需要移动插入点或删除点之后的所有元素。

  4. 不需要初始化大小:在创建链表时,不需要指定链表的大小,可以根据需要逐步构建链表。

  5. 空间分配:链表的节点可以在需要时单独分配,这意味着即使链表很大,也不需要一次性分配大块内存,从而减少了内存的浪费。

  6. 灵活的数据结构:链表可以很容易地构建成其他复杂的数据结构,如双向链表、循环链表
    等,这些结构可以支持更复杂的操作。

链表也有其缺点,比如访问元素时需要从头开始遍历,导致访问时间较长;指针的额外存储空间可能会增加内存的开销;以及由于指针的存在,可能会导致程序的复杂性增加。 

链表的存储方式

数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。链表是通过指针域的指针链接在内存中各个节点。所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

链表的定义

单链表的定义 (特别注意,在面试中可能需要自己定义链表

// 单链表
struct ListNode {int val;  // 节点上存储的元素ListNode *next;  // 指向下一个节点的指针ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

 链表的基本操作:删除、添加

删除节点

删除D节点,如图所示:

只要将C节点的next指针 指向E节点就可以了。注意此时D节点依旧留在内存中,只不过是没有在这个链表中而已,在使用C++最好手动释放这个D节点,释放这块内除。

添加节点

可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点。但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)

性能分析

Leetcode: 203.移除链表元素

题目描述:

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

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

解题思路:

这题就是简单的删除链表元素,但是要注意区分两种删除方式
1.删除头节点
2.删除非头节点 

完整代码:

/*** 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) {}* };*/
class Solution {
public:ListNode* removeElements(ListNode* head, int val) {// 这里需要时while 因为删除有可能需要一直删 不止一个val// 如果val是头节点 直接将head = head->next;即可while(head!=NULL && head->val == val) {ListNode* tmp = head;head = head->next;delete tmp;}ListNode* cur = head;// 如果不是头节点,需要cur->next = cur->next->next; 这样就删除了cur->next这个节点while(cur != NULL && cur->next != NULL) {if(cur->next->val == val) {ListNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;}else {cur = cur->next;}}return head;}
};

 使用虚拟头节点:

使用一个虚拟头节点,可以统一逻辑来删除链表节点 

/*** 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) {}* };*/
class Solution {
public:ListNode* removeElements(ListNode* head, int val) {// 设置一个虚拟头节点ListNode* dummyHead = new ListNode(0);// 将虚拟头节点设置为这个链表的头节点dummyHead->next = head;// 从虚拟头节点开始遍历ListNode*cur = dummyHead;// 统一删除节点逻辑 都是删除非头节点while(cur!=NULL && cur->next!=NULL) {if(cur->next->val == val) {ListNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;}else {cur = cur->next;}}// 重新设置头节点head = dummyHead->next;delete dummyHead;return head;}
};

Leetcode: 707.设计链表

 题目描述

你可以选择使用单链表或者双链表,设计并实现自己的链表。单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

 解题思路

这道题目设计链表的五个接口:

  • 获取链表第index个节点的数值
  • 在链表的最前面插入一个节点
  • 在链表的最后面插入一个节点
  • 在链表第index个节点前面插入一个节点
  • 删除链表的第index个节点

可以说这五个接口,已经覆盖了链表的常见操作,是练习链表操作非常好的一道题目

可以继续使用上面的操作,使用虚拟头节点来操作

class MyLinkedList {
public:// 定义链表节点的结构体struct LinkedNode {int val;LinkedNode* next;LinkedNode(int val) : val(val), next(nullptr){}};// 初始化链表 这里定义的头节点是一个虚拟头节点 而不是真正的链表头节点MyLinkedList() {_dummyhead = new LinkedNode(0);// 一个整型变量,用于存储链表中实际节点的数量_size = 0;}// 获取链表第index个节点的数值int get(int index) {// 如果索引无效(即超出链表范围),返回 -1if(index > (_size - 1) || index < 0) {return -1;}// 从虚拟头节点的下一个节点开始遍历,直到到达指定索引的节点,然后返回该节点的值LinkedNode* cur = _dummyhead->next;while(index--) {cur = cur->next;}return cur->val;}// 在链表最前面插入一个节点 ,插入完成后,新插入的节点为链表新的头节点void addAtHead(int val) {LinkedNode* newnode = new LinkedNode(val);// 注意这里的顺序不能改变 统一插入的赋值顺序 先将新头节点插入在head之前 然后将虚拟头节点依旧放在最前面newnode->next = _dummyhead->next;_dummyhead->next = newnode;_size++;}// 在链表最末尾插入节点void addAtTail(int val) {LinkedNode* newnode = new LinkedNode(val);LinkedNode* cur = _dummyhead;// 先将cur指向最后一个节点 判断条件cur->next != NULLwhile(cur->next != NULL) {cur = cur->next;}cur->next = newnode;_size++;}// 在第index个节点之前插入一个新节点 使用虚拟头节点就可以方便处理index为0 插入头节点的情况void addAtIndex(int index, int val) {if(index > _size) {return;}LinkedNode* newnode = new LinkedNode(val);LinkedNode* cur = _dummyhead;while(index--) {cur = cur->next;}newnode->next = cur->next;cur->next = newnode;_size++;}//删除第index个节点void deleteAtIndex(int index) {//当 index 等于链表长度时,cur->next 将为 nullptr,因此不能访问 cur->next->nextif(index >= _size || index < 0) {return;}LinkedNode* cur = _dummyhead;// 注意index是从0开始的 这样刚好指向index前一个节点while(index--) {cur = cur->next;}LinkedNode* tmp = cur->next;// 删除index节点cur->next = cur->next->next;delete tmp;_size--;}private:int _size;LinkedNode* _dummyhead;
};

 总结:要用意识去使用虚拟头节点,对于一些边界条件判断不到位!

Leetcode: 206.反转链表

题目描述

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

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

 解题思路

1.依次遍历链表 依次反转次序

/*** 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) {}* };*/
class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* former = NULL;ListNode* mid    = head;ListNode* latter = NULL;while(mid != NULL) {// 保存mid的下一个节点,因为接下来要改变mid->next的指向了latter = mid->next;mid->next = former;former = mid;mid = latter;}// 注意最后一次while循环 将latter赋给了mid 所以former是反转链表后的头节点return former;}
};

2.递归法

递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。

关键是初始化的地方, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。

具体可以看代码(已经详细注释),双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。

class Solution {
public:ListNode* reverse(ListNode* pre,ListNode* cur){if(cur == NULL) return pre;ListNode* temp = cur->next;cur->next = pre;// 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步// pre = cur;// cur = temp;return reverse(cur,temp);}ListNode* reverseList(ListNode* head) {// 和双指针法初始化是一样的逻辑// ListNode* cur = head;// ListNode* pre = NULL;return reverse(NULL, head);}};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/53983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发一款通过蓝牙连接控制水电表的微信小程序

增强软硬件交互 为了更好的解决师生生活中的实际问题&#xff0c;开发蓝牙小程序加强了和校区硬件的交互。 比如通过蓝牙连接控制水电表&#xff0c;减少实体卡片的使用。添加人脸活体检测功能&#xff0c;提高本人认证效率&#xff0c;减少师生等待时间。 蓝牙水电控展示 蓝…

HashMap常用方法及底层原理

目录 一、什么是HashMap二、HashMap的链表与红黑树1、数据结构2、链表转为红黑树3、红黑树退化为链表 三、存储&#xff08;put&#xff09;操作四、读取&#xff08;get&#xff09;操作五、扩容&#xff08;resize&#xff09;操作六、HashMap的线程安全与顺序1、线程安全2、…

【LeetCode每日一题】2024年9月第二周(上)

2024.9.9 中等 难度评分 1333 链接&#xff1a;2181. 合并零之间的节点 &#xff08;1&#xff09;题目描述&#xff1a; &#xff08;2&#xff09;示例 &#xff08;3&#xff09;分析 整体来说&#xff0c;描述还算清晰的题目&#xff0c;找到0节点所框定的区域&#xff0c…

Pandas读取某列、某行数据——loc、iloc区别

loc&#xff1a;通过行、列的名称或标签来索引 iloc&#xff1a;通过行、列的索引位置来寻找数据 首先&#xff0c;我们先创建一个DataFrame生成数据 import pandas as pddata {a:[1,2,3,4,5],b:[6,7,8,9,10],c:[11,12,13,14,15] } data pd.DataFrame(data) print(data) 运行…

工具、环境等其他小问题归纳

此篇文章内容会不定期更新&#xff0c;仅作为学习过程中的笔记记录 一、查询Windows 10环境下python版本与安装路径 若电脑成功安装了python环境&#xff0c;不小心忘了版本。 I、查询版本 1、cmd窗口快捷查询 Win R 输入cmd 进入窗口&#xff1b; 直接输入 python --version …

[数据集][目标检测]血细胞检测数据集VOC+YOLO格式2757张4类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2757 标注数量(xml文件个数)&#xff1a;2757 标注数量(txt文件个数)&#xff1a;2757 标注…

关于武汉芯景科技有限公司的IIC电平转换芯片XJ9517开发指南(兼容PCF9517)

一、芯片引脚介绍 1.芯片引脚 2.引脚描述 二、系统结构图 三、功能描述 1.电平转换 2.芯片使能/失能 EN 引脚为高电平有效&#xff0c;内部上拉至 VCC&#xff08;B&#xff09;&#xff0c;允许用户选择中继器何时有效。这可用于在上电时隔离行为不良的从机&#xff0c;直到…

4052A/4052B/4052C/4052D/4052E/4052F/4052G /4052H信号/频谱分析仪

4052A/4052B/4052C/4052D/4052E/4052F/4052G /4052H信号/频谱分析仪 苏州新利通 Ceyear 4052具备出色的测试动态范围、相位噪声、幅度精度和测试速度&#xff0c;具备频谱分析、I/Q分析、实时频谱分析、瞬态分析、矢量信号分析、脉冲分析、音频分析等丰富的测试功能。 Ceyear…

OpenAI发布o1预览模型:推理能力更强可达理科博士生水准

近日OpenAI宣布推出了新一代 AI 模型系列 OpenAI o1&#xff0c;按照官方技术博客说法&#xff0c;o1 在推理能力上代表了人工智能最强的水平。 那究竟是怎么一回事呢&#xff1f; OpenAI CEO Sam Altman 表示&#xff1a;o1 系列的推出代表了 AI 能力的新起点&#xff0c;能…

240909-ChuanhuChatGPT集成Ollama的环境配置

A. 最终效果 B. 需求文件 requirements.txt (至少需要安装这个&#xff0c;具体参见官网)requirements_advanced.txt &#xff08;如果安装了Ollama&#xff0c;并且可以进行对话&#xff0c;可以不需要安装&#xff0c;具体参见官网&#xff09;requirements_succcess.txt&am…

gin配置swagger文档

一、基本准备工作 1、安装依赖包 go get -u github.com/swaggo/swag/cmd/swag go get -u github.com/swaggo/gin-swagger go get -u github.com/swaggo/files2、在根目录上配置swagger的路由文件 //2.初始化路由router : initialize.Routers()// 配置swaggerdocs.SwaggerInfo…

微服务杂谈

几个概念 还是第一次听说Spring Cloud Alibaba &#xff0c;真是孤陋寡闻了&#xff0c;以前只知道 SpringCloud 是为了搭建微服务的&#xff0c;spring boot 则是快速创建一个项目&#xff0c;也可以是一个微服务 。那么SpringCloud 和 Spring boot 有什么区别呢&#xff1f;S…

Unity for Android使用蓝牙低功耗Bluetooth LE

Unity2021.3.35f1 插件&#xff1a;Bluetooth LE for iOS and Android v2.3.unitypackage 1、将插件资源包导入unity中 2.修改插件中的AndroidManifest文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schem…

系统优化工具 | PC Cleaner v9.7.0.3 绿色版

PC Cleaner是一款功能强大的电脑清理和优化工具&#xff0c;旨在通过清理系统垃圾文件、解除恶意软件和优化系统性能来提高计算机的运行效率。该软件提供了多种功能&#xff0c;可以帮助用户维护和提升计算机的整体表现。 PC Cleaner 支持 Windows 7 及以上操作系统&#xff0…

Qt使用绿色pdf阅读器打开文件

1.下载SumatraPDF 2.设置 3.代码 void MainWindow::on_pushButton_clicked() {QProcess *process new QProcess();QString filePath "C:\\Users\\jude\\Desktop\\su\\11.pdf";QString sumatraPath "C:\\Users\\jude\\Desktop\\su\\SumatraPDF-3.5.2-64.exe&q…

电瓶车火灾频发背后的隐忧

近年来&#xff0c;电瓶车火灾事件频发&#xff0c;不仅严重威胁着人民群众的生命财产安全&#xff0c;也给社会带来了极大的安全隐患。从城市街道到居民小区&#xff0c;电瓶车火灾的阴影无处不在&#xff0c;如何有效防范与自救成为了全社会关注的焦点。 一、电瓶车火灾频发…

linux_L1_linux重启服务器

使用putty登录到linux服务器切换到管理员账号 sudo -s重启命令 reboot

钾盐矿开采与加工过程中的机电设备选型及管理指南

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 在钾盐矿的开采和加工过程中&#xff0c;需要使用多种机电设备以确保生产的顺利进行。这些设备主要用于矿石开采、破碎、运输、选矿以及矿物产品的深加工等过程。以下是钾盐矿常用的一些机…

Leetcode 字母异位词分组

这道题目的意思就是&#xff1a;把包含字母字符相同的单词分到同一组。 算法思路&#xff1a; 使用哈希表来解决。 首先将每个字符串进行排序&#xff0c;将排序之后的字符串作为 key&#xff0c;然后将用 key 所对应的异位词组 作为value。然后我们使用 std::pair 来遍历 键…

AI prompt(提示词)

# 好用的用于学习的AI提示词 ## 费曼学习法 请使用费曼学习法&#xff0c;用简单的语言解释&#xff08;量子力学&#xff09;是什么&#xff0c;并提供一个简单的例子来说明它如何应用 ## 帕累托法则&#xff08;80/20原则&#xff09; 将&#xff08;量子力学&#xff09;最…