初级数据结构——单向链表

前言

单向链表示最基础的数据结构之一,它也是我们学习开始学习数据结构的第一个必须要掌握的数据结构,学习数据结构一定是由浅到深,所以我们最好是先学习简单的在学习有难度的,因为直接学习难的数据结构很容易劝退,让我们来深入了解单向链表。

目录

  • 前言
  • 一、什么是单向链表
  • 二、链表结构
  • 三、基本操作
  • 四、性能分析
  • 五、优点和缺点
  • 六、删除、插入元素动态图解
  • 七、代码模版
  • 八、经典例题
    • 1.数列有序!
    • 2.二进制链表转整数
    • [3.面试题 02.02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/description/)
    • [4.LCR 140. 训练计划 II](https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/description/)
  • 九、总结
  • 十、结语

一、什么是单向链表

单向链表(Singly Linked List)是一种线性数据结构,由一系列节点组成,每个节点包含数据域和指向下一个节点的指针。

二、链表结构

1. 节点结构
每个节点通常包含两个部分:
数据域:存储节点的值或数据。
指针域(或称为链接域):存储指向下一个节点的指针。如果节点是链表的最后一个节点,则指针通常为空(NULL 或 nullptr)。

2. 链表结构
头节点:链表的第一个节点,通常用于方便地访问链表。有时也使用“哑节点”(dummy node)或“哨兵节点”(sentinel node)作为头节点,以简化边界情况的处理。
尾节点:链表的最后一个节点,其指针域为空

三、基本操作

1.插入操作
头插法:在链表头部插入新节点。新节点的指针指向当前头节点,然后更新头指针指向新节点。
尾插法:在链表尾部插入新节点。需要遍历链表找到尾节点,然后将尾节点的指针指向新节点,并更新尾指针(如果链表有尾指针引用的话)。
中间插入:在链表的中间位置插入新节点。需要找到插入位置的前一个节点,然后调整指针。

2.删除操作
删除头节点:更新头指针指向第二个节点(如果存在),并释放头节点的内存。
删除尾节点:需要遍历链表找到倒数第二个节点,然后将其指针设为空,并释放尾节点的内存。
删除中间节点:找到要删除的节点的前一个节点,然后调整其指针指向要删除节点的下一个节点,并释放要删除节点的内存。

3.查找操作
按值查找:从头节点开始遍历链表,比较每个节点的值,直到找到匹配的节点或遍历到链表末尾。
按位置查找:从头节点开始遍历链表,直到达到指定位置或遍历到链表末尾。
遍历操作
从头节点开始,依次访问每个节点,直到遍历到链表末尾(即遇到空指针)。

四、性能分析

时间复杂度:
插入、删除和查找操作在最坏情况下的时间复杂度为 O(n),其中 n 是链表的长度。因为可能需要遍历整个链表才能找到插入、删除或查找的位置。

空间复杂度:
链表的空间复杂度取决于节点数量和每个节点所需的空间。除了存储数据的空间外,还需要额外的空间来存储指针。

五、优点和缺点

优点
插入和删除操作不需要移动大量数据,只需要调整指针。
不需要预先知道数据的大小。
链表在内存中的分配是动态的,可以灵活地调整大小。

缺点
访问某个节点需要从头节点开始遍历,时间复杂度较高。
需要额外的空间来存储指针。
链表节点的内存分配和释放相对复杂,可能导致内存碎片问题。

六、删除、插入元素动态图解

插入元素
在这里插入图片描述
删除元素
在这里插入图片描述

七、代码模版

#include<iostream>
#include<stdexcept>
using namespace std;#define eType intstruct ListNode {eType data;//数据域ListNode* next;//指针域,指向下一个节点ListNode(eType x):data(x),next(NULL){}
};class LinkedList {
private:ListNode* head;int size;
public:LinkedList() :size(0), head(NULL) {}//构造函数~LinkedList();//析构函数void inser(int i, eType x);//元素插入void remove(int i);//删除元素void update(int i, eType x);//更新元素ListNode* find(eType x);//按值查找元素ListNode* get(int i);//按序号查找bool isempty();//判空void print();//打印链表元素void append(eType x);//在链表尾部插入元素void ascInsert(eType x);//顺序插入元素
};LinkedList::~LinkedList() {ListNode* curr = head;//游标节点,表示表里链表到当前节点while (curr) {ListNode* t = curr;curr = curr->next;delete t;}
}void LinkedList::inser(int i, eType x) {if (i<0 || i>size) {throw std::out_of_range("Invalid position");}ListNode* newNode = new ListNode(x);if (!i) {newNode->next = head;head = newNode;}else {ListNode* curr = head;for (int j = 0; j < i - 1; j++) {curr = curr->next;}newNode->next = curr->next;curr->next = newNode;}size++;
}void LinkedList::remove(int i) {if (i<0 || i>=size) {throw std::out_of_range("Invalid position");}if (!i) {ListNode* t = head;head = head->next;delete t;}else {ListNode* curr = head;for (int j = 0; j < i - 1; j++) {curr = curr->next;}ListNode* t = curr->next;curr->next = curr->next->next;delete t;}size--;
}void LinkedList::update(int i, eType x) {get(i)->data = x;
}ListNode* LinkedList::find(eType x) {ListNode* curr = head;while (curr && curr->data != x) {curr = curr->next;}return curr;
}ListNode* LinkedList::get(int i) {if (i < 0 || i >= size) {throw std::out_of_range("Invalid position");}ListNode* curr = head;for (int j = 0; j < i; j++) {curr = curr->next;}return curr;
}void LinkedList::print() {ListNode* curr = head;while (curr) {cout << curr->data << " ";curr = curr->next;}cout << endl;
}void LinkedList::append(eType x) {inser(size, x);
}void LinkedList::ascInsert(eType x) {ListNode* curr = head;if (!size) {//如果链表为空inser(0,x);return;}for (int i = 0; i < size; i++) {if (x <= curr->data) {inser(i, x);return;}curr = curr->next;}inser(size, x);//在链表中找不到比插入的值大
}bool LinkedList::isempty() {return size == 0;
}int main() {return 0;
}

八、经典例题

1.数列有序!

(帅哥们这个蓝色字体可以点进去看原题)

#include<iostream>
#include<stdexcept>
using namespace std;#define eType intstruct ListNode {eType data;//数据域ListNode* next;//指针域,指向下一个节点ListNode(eType x):data(x),next(NULL){}
};class LinkedList {
private:ListNode* head;int size;
public:LinkedList() :size(0), head(NULL) {}//构造函数~LinkedList();//析构函数void inser(int i, eType x);//元素插入void remove(int i);//删除元素void update(int i, eType x);//更新元素ListNode* find(eType x);//按值查找元素ListNode* get(int i);//按序号查找bool isempty();//判空void print();//打印链表元素void append(eType x);//在链表尾部插入元素void ascInsert(eType x);//顺序插入元素
};LinkedList::~LinkedList() {ListNode* curr = head;//游标节点,表示表里链表到当前节点while (curr) {ListNode* t = curr;curr = curr->next;delete t;}
}void LinkedList::inser(int i, eType x) {if (i<0 || i>size) {throw std::out_of_range("Invalid position");}ListNode* newNode = new ListNode(x);if (!i) {newNode->next = head;head = newNode;}else {ListNode* curr = head;for (int j = 0; j < i - 1; j++) {curr = curr->next;}newNode->next = curr->next;curr->next = newNode;}size++;
}void LinkedList::remove(int i) {if (i<0 || i>=size) {throw std::out_of_range("Invalid position");}if (!i) {ListNode* t = head;head = head->next;delete t;}else {ListNode* curr = head;for (int j = 0; j < i - 1; j++) {curr = curr->next;}ListNode* t = curr->next;curr->next = curr->next->next;delete t;}size--;
}void LinkedList::update(int i, eType x) {get(i)->data = x;
}ListNode* LinkedList::find(eType x) {ListNode* curr = head;while (curr && curr->data != x) {curr = curr->next;}return curr;
}ListNode* LinkedList::get(int i) {if (i < 0 || i >= size) {throw std::out_of_range("Invalid position");}ListNode* curr = head;for (int j = 0; j < i; j++) {curr = curr->next;}return curr;
}void LinkedList::print() {ListNode* curr = head;while (curr) {cout << curr->data << " ";curr = curr->next;}cout << endl;
}void LinkedList::append(eType x) {inser(size, x);
}void LinkedList::ascInsert(eType x) {ListNode* curr = head;if (!size) {//如果链表为空inser(0,x);return;}for (int i = 0; i < size; i++) {if (x <= curr->data) {inser(i, x);return;}curr = curr->next;}inser(size, x);//在链表中找不到比插入的值大
}bool LinkedList::isempty() {return size == 0;
}int main() {int n, m;while (cin >> n >> m) {LinkedList l;if (!n && !m) break;for (int i = 0; i < n; i++) {int x;cin >> x;l.inser(i, x);}l.ascInsert(m);l.print();}return 0;
}

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:int getDecimalValue(ListNode* head) {int sum=0;ListNode*curr=head;while(curr){sum=sum*2+curr->val;curr=curr->next;}return sum;}
};

3.面试题 02.02. 返回倒数第 k 个节点

(帅哥们这个蓝色字体可以点进去看原题)

这个就是经典双指针快慢指针的链表题

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:int kthToLast(ListNode* head, int k) {ListNode*fast=head;while(k--){fast=fast->next;}ListNode*slow=head;while(fast){slow=slow->next;fast=fast->next;}return slow->val;}
};

4.LCR 140. 训练计划 II

/*** 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* trainingPlan(ListNode* head, int cnt) {ListNode*fast=head;while(cnt--){fast=fast->next;}ListNode*slow=head;while(fast){slow=slow->next;fast=fast->next;}return slow;}
};

九、总结

单向链表是数据结构中的基础内容,理解其工作原理和基本操作对于进一步学习更高级的数据结构(如双向链表、循环链表、栈、队列等)非常重要

十、结语

我发的这些题目都是很简单很基础的题目,我不想一上来就发难题,先做简单题,后续我会整理题库,每个板块都会发有难度的题。学习编程是一个很艰难,漫长的过程,我们要克服一切困难,学习算法本就是由易到难,不会的地方就问,我相信通过我们坚持不懈的努力一定能理解并熟练掌握其中细节,加油,我相信你一定能行。
在这里插入图片描述
想看更多内容可以关注我,看我作品,关注我让我们一起学习编程,希望大家能点赞关注支持一下,让我有持续更新的动力,谢谢大家。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

RTMP推流H264和AAC

使用 librtmp 库实现推流h264和aac文件&#xff0c;rtmp服务器使用SRS搭建&#xff0c;拉流端使用VLC。其中用到的h264和aac文件解析部分代码在我其它博客中有写&#xff1a;C/C AAC文件解析-CSDN博客、C/C H264文件解析-CSDN博客。 推流部分源码&#xff08;C&#xff09;如下…

中国药品注册审批数据库- 药品注册信息查询与审评进度查询方法

药品的注册、审评审批进度信息是医药研发相关人员每天都会关注的信息&#xff0c;为了保证药品注册申请受理及审评审批进度信息的公开透明&#xff0c;CDE药审中心提供药品不同注册分类序列及药品注册申请受理的审评审批进度信息查询服务。但因CDE官网的改版导致很大一部分人不…

代数插值实验

实验类型&#xff1a;●验证性实验 ○综合性实验 ○设计性实验 实验目的&#xff1a;进一步熟练掌握Lagrange插值算法、Newton插值算法&#xff0c;提高编程能力和解决插值问题的实践技能。 实验报告&#xff1a;根据实验情况和结果撰写并递交实验报告。 实验报告打印和装…

物联网智能技术的深入探讨与案例分析

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

点云配准之点到点,点到面,点到线ICP,NDT算法介绍

点云配准&#xff08;Point Cloud Registration&#xff09;即求一个位姿变换 x [ R , t ] \mathbf{x}[\mathbf{R},\mathbf{t}] x[R,t]&#xff0c;将源点云 Q { q 1 , ⋯ , q m } Q\{\mathbf{q}_{1},\cdots,\mathbf{q}_{m}\} Q{q1​,⋯,qm​}变换到与目标点云 P { p 1 , ⋯…

Html5详解

目录 一、浏览器相关知识 二、html简介 (一)超文本标记语言 (二)HTML基础结构 (三)HTML概念词汇解释 (四)HTML的语法规则 (五)前端开发工具VS Code与插件 1.VS Code的安装 2.安装插件&#xff1a; 3.通过live Server 小型服务器运行项目 4.其他常见设置 5.在线帮…

实现 think/queue 日志分离

当我们使用think/queue包含了比较多的不同队列,日志会写到runtime/log目录下,合并写入的,不好排查问题,我们遇到一个比较严重的就是用了不同用户来执行,权限冲突了,导致部分队列执行不了. 为了解决以上问题,本来希望通过Log::init设置不同日志路径的,但是本地测试没生效,于是用…

创新不设限,灵码赋新能:通义灵码新功能深度评测

引言 自从2023年通义灵码发布以来&#xff0c;这款基于阿里云通义大模型的AI编码助手便迅速成为了开发者们心中的“明星产品”&#xff0c;受到了广大开发者的关注与好评。它不仅为个人开发者提供了强大的支持&#xff0c;帮助企业团队提升了研发效率&#xff0c;同时也推动了…

道品科技智慧农业中的物联网技术:生产与溯源系统的结合

随着全球人口的不断增长和城市化进程的加快&#xff0c;农业面临着巨大的挑战&#xff0c;包括资源短缺、环境污染和食品安全等问题。为了解决这些问题&#xff0c;智慧农业应运而生&#xff0c;其中物联网&#xff08;IoT&#xff09;技术的应用为农业的现代化提供了强有力的支…

【MPC-Simulink】EX03 基于非线性系统线性化模型MPC仿真(MIMO)

【MPC-Simulink】EX03 基于非线性系统线性化模型MPC仿真&#xff08;MIMO&#xff09; 参考 Matlab 官网提供的 Model Predictive Control Toolbox - Getting Started Guide&#xff0c;以零初始状态条件下的非线性系统在线性化后得到的多输入多输出&#xff08;MIMO&#xff…

期权开户难不难?期权开户成功后当天是否能交易

期权开户难不难&#xff1f;这取决于投资者的准备情况和所选的开户途径。对于满足一定资金和经验要求的投资者来说&#xff0c;通过正规期货公司或期权交易平台进行开户&#xff0c;虽然流程相对复杂&#xff0c;但只要遵循步骤&#xff0c;仍然可以顺利完成&#xff0c;下文为…

沈阳乐晟睿浩科技有限公司引领新潮流

在当今数字化浪潮汹涌的时代&#xff0c;电子商务以其独特的魅力和无限潜力&#xff0c;正深刻改变着人们的消费习惯与商业模式。沈阳乐晟睿浩科技有限公司&#xff08;以下简称“乐晟睿浩”&#xff09;&#xff0c;作为电商领域的一颗璀璨新星&#xff0c;凭借其深厚的技术实…

【一步步开发AI运动小程序】二十一、如果将AI运动项目配置持久化到后端?

**说明&#xff1a;**本文所涉及的AI运动识别、计时、计数能力&#xff0c;都是基于云智「Ai运动识别引擎」实现。云智「Ai运动识别」插件识别引擎&#xff0c;可以为您的小程序或Uni APP赋于原生、本地、广覆盖、高性能的人体识别、姿态识别、10余种常见的运动计时、计数识别及…

Python栈--深度优先搜索(迷宫问题)

给一个二维列表&#xff0c;表示迷宫(0表示给出算法&#xff0c;求通道&#xff0c;1表示围墙)。 给出算法&#xff0c;求一条走出迷宫的路径。 maze [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 0, 0, 0, 1, 0, 1], [1, 0, 0, 1, 0, 0, 0, 1, 0, 1], […

安卓主板_基于联发科MTK MT8788平台平板电脑方案_安卓核心板开发板定制

联发科MT8788安卓核心板平台介绍&#xff1a; MTK8788设备具有集成的蓝牙、fm、wlan和gps模块&#xff0c;是一个高度集成的基带平台&#xff0c;包括调制解调器和应用处理子系统&#xff0c;启用LTE/LTE-A和C2K智能设备应用程序。该芯片集成了工作在2.0GHz的ARM Cortex-A73、最…

LabVIEW 版本控制

在软件开发中&#xff0c;版本控制系统&#xff08;VCS&#xff09; 是管理代码版本变化的核心工具。对于 LabVIEW 用户&#xff0c;虽然图形化编程带来高效开发体验&#xff0c;但由于其特有的二进制 VI 文件格式&#xff0c;传统文本比较工具无法直接用于 LabVIEW 项目。这时…

centos7.9部署oracle19c教程

1.安装前准备 1.1关闭防火墙和selinux systemctl stop firewalld systemctl disable firewalldvi /etc/selinux/config1.2 安装依赖 yum install -y unzip compat-libcap1 compat-libstdc-33 gcc-c ksh libaio-devel libstdc-devel elfutils-libelf-devel fontconfig-devel …

034集——JIG效果实现(橡皮筋效果)(CAD—C#二次开发入门)

可实现效果如下&#xff08;对象捕捉F3需打开&#xff0c;否则效果不好&#xff09;&#xff1a; public class CircleJig : EntityJig{public static void DraCJig(){PromptPointResult ppr Z.ed.GetPoint("a");if (ppr.Value null) return;Point3d pt ppr.Value…

Softing工业将在纽伦堡SPS 2024上展示Ethernet-APL现场交换机

今年&#xff0c;Softing工业将在纽伦堡SPS贸易展览会上展示aplSwitch Field —— 一款先进的过程自动化解决方案。这款16端口以太网高级物理层&#xff08;APL&#xff09;现场交换机的防护等级高达IP30&#xff0c;可提供从应用到现场级别的无缝以太网连接&#xff0c;专为Ex…

鸿蒙UI开发——小图标的使用

1、前 言 鸿蒙SDK中为我们提供了大量的高质量内置图标&#xff0c;图标详见(https://developer.huawei.com/consumer/cn/design/harmonyos-symbol/) 图标资源一览&#xff1a; 除了基本的图标图形外&#xff0c;我们还可以支持图标的多种填充模式&#xff08;单色、多色、分层…