当前位置: 首页 > news >正文

数据结构----链表头插中插尾插

一、链表的基本概念

链表是一种线性数据结构,它由一系列节点组成。每个节点包含两个主要部分:

  1. 数据域:用于存储数据元素,可以是任何类型的数据,如整数、字符、结构体等。
  2. 指针域:用于存储下一个节点(在单链表中)或前一个节点与下一个节点(在双链表中)的地址。

与数组不同,链表中的节点在内存中不是连续存储的。它们通过指针链接在一起,形成一个链状结构。这种非连续存储方式使得链表在插入和删除操作上具有一定的优势。

二、单链表

  1. 结构
    • 单链表节点的定义(以C语言为例):
typedef struct ListNode {int data;       // 数据域,可以根据需要存储不同类型的数据struct ListNode *next; // 指针域,指向下一个节点
} ListNode;
  • 这里,data用于存储数据,next是一个指向同类型结构体的指针,用于指向下一个节点。
  1. 基本操作
    • 创建节点
      • 函数实现:
ListNode* createNode(int value) {ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));if (newNode == NULL) {// 内存分配失败处理return NULL;}newNode->data = value;newNode->next = NULL;return newNode;
}
 - 解释:- 首先使用`malloc`函数分配足够的内存来存储一个`ListNode`结构体。如果内存分配成功,将传入的值赋给新节点的数据域,并将指针域初始化为`NULL`,表示这是一个孤立的节点,目前没有下一个节点。最后返回新创建的节点。
  • 插入节点
    • 头插法
      • 函数实现:
ListNode* insertAtHead(ListNode* head, int value) {ListNode* newNode = createNode(value);newNode->next = head;return newNode;
}
   - 解释:- 首先调用`createNode`函数创建一个新节点。然后将新节点的`next`指针指向当前的头节点(如果`head`为`NULL`,则新节点成为唯一的节点)。最后,将新节点作为新的头节点返回。这意味着每次插入操作都会使新节点成为链表的第一个节点。- **尾插法**- 函数实现:
ListNode* insertAtTail(ListNode* head, int value) {ListNode* newNode = createNode(value);if (head == NULL) {return newNode;}ListNode* current = head;while (current->next!= NULL) {current = current->next;}current->next = newNode;return head;
}
   - 解释:- 同样先创建新节点。如果链表为空(`head`为`NULL`),则直接返回新节点作为头节点。如果链表不为空,通过一个循环找到链表的最后一个节点(即当前节点的`next`指针为`NULL`的节点)。找到后,将最后一个节点的`next`指针指向新节点,从而将新节点插入到链表的尾部。最后返回原头节点,因为尾插法不会改变头节点。- **中插法(在指定位置插入)**- 函数实现:
ListNode* insertAtPosition(ListNode* head, int value, int position) {if (position == 0) {return insertAtHead(head, value);}ListNode* newNode = createNode(value);ListNode* current = head;for (int i = 0; i < position - 1 && current!= NULL; i++) {current = current->next;}if (current == NULL) {return head;}newNode->next = current->next;current->next = newNode;return head;
}
   - 解释:- 首先判断要插入的位置是否为0,如果是,则调用头插法函数进行插入。如果不是0,先创建新节点。然后通过一个循环找到要插入位置的前一个节点(循环条件确保不会超出链表长度且能找到正确位置)。如果在遍历过程中发现当前节点为`NULL`,说明已经到达链表末尾但还没找到插入位置,此时直接返回原链表。找到插入位置的前一个节点后,将新节点的`next`指针指向当前节点的下一个节点,再将当前节点的`next`指针指向新节点,完成插入操作。最后返回原头节点。
  • 删除节点
    • 函数实现:
ListNode* deleteNode(ListNode* head, int target) {if (head == NULL) {return NULL;}if (head->data == target) {ListNode* temp = head;head = head->next;free(temp);return head;}ListNode* current = head;while (current->next!= NULL && current->next->data!= target) {current = current->next;}if (current->next!= NULL) {ListNode* temp = current->next;current->next = current->next->next;free(temp);}return head;
}
 - 解释:- 首先判断链表是否为空,如果为空则无法删除,直接返回`NULL`。如果头节点的数据就是要删除的数据,那么将头节点的下一个节点作为新的头节点,并释放原来的头节点,然后返回新头节点。如果头节点不是要删除的节点,通过循环找到要删除节点的前一个节点(通过判断当前节点的下一个节点的数据是否为目标数据)。找到后,将前一个节点的`next`指针指向要删除节点的下一个节点,然后释放要删除的节点,最后返回原头节点。
  • 遍历链表
    • 函数实现:
void traverseList(ListNode* head) {ListNode* current = head;while (current!= NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}
 - 解释:- 从链表的头节点开始,通过循环依次访问每个节点的数据域,并将其打印出来。每次循环将当前节点更新为下一个节点,直到当前节点为`NULL`,表示已经遍历完整个链表。

在这里插入图片描述

三、双链表

  1. 结构
    • 双链表节点的定义(以C语言为例):
typedef struct DoubleListNode {int data;struct DoubleListNode *prev;struct DoubleListNode *next;
} DoubleListNode;
  • 这里,data用于存储数据,prev是指向前一个节点的指针,next是指向后一个节点的指针。
  1. 基本操作
    • 创建节点
      • 函数实现:
DoubleListNode* createDoubleNode(int value) {DoubleListNode* newNode = (DoubleListNode*)malloc(sizeof(DoubleListNode));if (newNode == NULL) {return NULL;}newNode->data = value;newNode->prev = NULL;newNode->next = NULL;return newNode;
}
 - 解释:- 与单链表创建节点类似,使用`malloc`分配内存。成功分配后,将数据赋给新节点的数据域,并将`prev`和`next`指针都初始化为`NULL`,因为新创建的节点暂时没有前后连接的节点。最后返回新节点。
  • 插入节点
    • 例如,在双链表头部插入节点:
      • 函数实现:
DoubleListNode* insertAtHeadDouble(DoubleListNode* head, int value) {DoubleListNode* newNode = createDoubleNode(value);if (head == NULL) {return newNode;}newNode->next = head;head->prev = newNode;return newNode;
}
   - 解释:- 先创建新节点。如果链表为空,直接返回新节点作为头节点。如果链表不为空,将新节点的`next`指针指向当前头节点,同时将当前头节点的`prev`指针指向新节点,最后将新节点作为新的头节点返回。
  • 删除节点
    • 例如,删除双链表中值为target的节点:
      • 函数实现:
DoubleListNode* deleteDoubleNode(DoubleListNode* head, int target) {if (head == NULL) {return NULL;}if (head->data == target) {DoubleListNode* temp = head;if (head->next!= NULL) {head->next->prev = NULL;}head = head->next;free(temp);return head;}DoubleListNode* current = head;while (current->next!= NULL && current->next->data!= target) {current = current->next;}if (current->next!= NULL) {DoubleListNode* temp = current->next;if (temp->next!= NULL) {temp->next->prev = current;}current->next = temp->next;free(temp);}return head;
}
   - 解释:- 首先判断链表是否为空,为空则无法删除,返回`NULL`。如果头节点的数据是要删除的数据,判断头节点的下一个节点是否存在,如果存在则将其`prev`指针置为`NULL`,然后将头节点更新为下一个节点,并释放原来的头节点,最后返回新头节点。如果头节点不是要删除的节点,通过循环找到要删除节点的前一个节点(通过判断当前节点的下一个节点的数据是否为目标数据)。找到后,如果要删除的节点的下一个节点存在,则将其下一个节点的`prev`指针指向当前节点,然后将当前节点的`next`指针指向要删除节点的下一个节点,最后释放要删除的节点,返回原头节点。
  • 遍历链表
    • 例如,从头部开始向前遍历:
      • 函数实现:
void traverseDoubleListForward(DoubleListNode* head) {DoubleListNode* current = head;while (current!= NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}
   - 解释:- 与单链表的遍历类似,从头节点开始,通过循环依次访问每个节点的数据域并打印,每次将当前节点更新为下一个节点,直到当前节点为`NULL`。双链表还可以从尾部开始向后遍历,原理类似,只是使用`prev`指针。

四、循环链表

  1. 结构

    • 循环链表分为循环单链表和循环双链表。
    • 循环单链表是最后一个节点的next指针指向头节点,形成一个环。
    • 循环双链表是最后一个节点的next指针指向头节点,头节点的prev指针指向最后一个节点,形成一个双向的环。
  2. 基本操作

    • 创建循环单链表
      • 例如,通过尾插法创建循环单链表:
        • 函数实现:
ListNode* createCircularList(int values[], int size) {if (size == 0) {return NULL;}ListNode* head = createNode(values[0]);ListNode* current = head;for (int i = 1; i < size; i++) {ListNode* newNode = createNode(values[i]);current->next = newNode;current = newNode;}current->next = head;return head;
}
   - 解释:- 首先判断数组大小是否为0,如果是则返回`NULL`。如果不为0,先创建头节点,然后通过循环依次创建新节点并将其插入到链表尾部。最后将最后一个节点的`next`指针指向头节点,形成循环链表,并返回头节点。
  • 遍历循环单链表
    • 例如:
      • 函数实现:
void traverseCircularList(ListNode* head) {if (head == NULL) {return;}ListNode* current = head;do {printf("%d ", current->data);current = current->next;} while (current!= head);printf("\n");
}
   - 解释:- 首先判断链表是否为空,如果为空则直接返回。如果不为空,从头节点开始遍历,通过`do - while`循环依次访问每个节点的数据域并打印。循环条件是当前节点不等于头节点,因为是循环链表,当再次回到头节点时表示遍历结束。最后换行。

循环链表在一些特定的应用场景中非常有用,例如操作系统中的资源分配循环队列等。双链表在需要双向访问数据的场景下有优势,而单链表则在空间利用和简单操作场景下较为常用。在这里插入图片描述

相关文章:

数据结构----链表头插中插尾插

一、链表的基本概念 链表是一种线性数据结构&#xff0c;它由一系列节点组成。每个节点包含两个主要部分&#xff1a; 数据域&#xff1a;用于存储数据元素&#xff0c;可以是任何类型的数据&#xff0c;如整数、字符、结构体等。指针域&#xff1a;用于存储下一个节点&#…...

设计模式-读书笔记

确认好&#xff1a; 模式名称 问题&#xff1a;在何时使用模式&#xff0c;包含设计中存在的问题以及问题存在的原因 解决方案&#xff1a;设计模式的组成部分&#xff0c;以及这些组成部分之间的相互关系&#xff0c;各自的职责和协作方式&#xff0c;用uml类图和核心代码描…...

c语言----选择结构

基本概念 选择结构是C语言中用于根据条件判断来执行不同代码块的结构。它允许程序在不同的条件下执行不同的操作&#xff0c;使程序具有决策能力。 if语句 单分支if语句 语法格式&#xff1a; if (条件表达式) { 执行语句块; } 功能&#xff1a; 当条件表达式的值为真&#…...

KS曲线python实现

目录 实战 实战 # 导入第三方模块 import pandas as pd import numpy as np import matplotlib.pyplot as plt# 自定义绘制ks曲线的函数 def plot_ks(y_test, y_score, positive_flag):# 对y_test重新设置索引y_test.index np.arange(len(y_test))# 构建目标数据集target_dat…...

解决matplotlib中文乱码问题

进入python&#xff0c;查看缓存 import matplotlib as mpl print(mpl.get_cachedir())如果结果为/Users/xxx/.matplotlib 那么就rm -rf /Users/xxx/.matplotlib 然后 mkdir ~/.fonts cd ~/.fonts wget http://129.204.205.246/downloads/SimHei.ttfsudo apt-get install fo…...

实操给桌面机器人加上超拟人音色

前面我们讲了怎么用CSK6大模型开发板做一个桌面机器人充当AI语音助理&#xff0c;近期上线超拟人方案&#xff0c;不仅大模型语音最快可以1秒内回复&#xff0c;还可以让我们的桌面机器人使用超拟人音色、具备声纹识别等能力&#xff0c;本文以csk6大模型开发板为例实操怎么把超…...

git stash 的文件如何找回

在Git中&#xff0c;如果你使用了git stash命令来保存你的工作进度&#xff0c;但之后想要找回这些被stash的文件&#xff0c;你可以按照以下步骤进行操作&#xff1a; 1. 查看stash列表 首先&#xff0c;使用git stash list命令来查看当前保存的所有stash记录。这个命令会列出…...

皮肤伤口分割数据集labelme格式248张5类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;284 标注数量(json文件个数)&#xff1a;284 标注类别数&#xff1a;5 标注类别名称:["bruises","burns","cu…...

uni-app开发AI康复锻炼小程序,帮助肢体受伤患者康复!

**提要&#xff1a;**近段时间我们收到多个康复机构用户&#xff0c;咨询AI运动识别插件是否可以应用于肢力运动受限患者的康复锻炼中来&#xff0c;插件是可以应用到AI康复锻炼中的&#xff0c;今天小编就为您介绍一下AI运动识别插件在康腹锻炼中的应用场景。 一、康复机构的应…...

双内核架构 Xenomai 4 安装教程

Xenomai 4是一种双内核架构, 继承了Xenomai系列的特点&#xff0c;通过在Linux内核中嵌入一个辅助核心&#xff08;companion core&#xff09;&#xff0c;来提供实时能力。这个辅助核心专门处理那些需要极低且有界响应时间的任务。 本文将在官网教程(https://evlproject.org/…...

【redis的使用、账号流程、游戏服Handler的反射调用】1.自增id 2.全局用户名这样子名字唯一 3.

一、web服 1)账号注册 // 用于唯一命名服务 com.xinyue.game.center.business.account.logic.AccountRegisterService#accountRegister public void accountRegister(AccountEntity account) {accountManager.checkUsername(account.getUsername());accountManager.checkPass…...

neo4j 图表数据导入到 TuGraph

neo4j 图表数据导入到 TuGraph 代码文件说明后文 前言:近期在引入阿里的 TuGraph 图数据库&#xff0c;需要将 原 neo4j 数据导入到新的 tugraph 数据库中。预期走csv文件导入导出&#xff0c;但因为格式和数据库设计问题&#xff0c;操作起来比较麻烦&#xff08;可能是个人没…...

启动报错java.lang.NoClassDefFoundError: ch/qos/logback/core/status/WarnStatus

报错信息图片 日志&#xff1a; Exception in thread "Quartz Scheduler [scheduler]" java.lang.NoClassDefFoundError: ch/qos/logback/core/status/WarnStatus先说我自己遇到的问题&#xff0c;我们项目在web设置了自定义的log输出路径&#xff0c;多了一个 / 去…...

【ubuntu18.04】ubuntu18.04挂在硬盘出现 Wrong diagnostic page; asked for 1 got 8解决方案

错误日志 [ 8754.700227] usb 2-3: new full-speed USB device number 3 using xhci_hcd [ 8754.867389] usb 2-3: New USB device found, idVendor0e0f, idProduct0002, bcdDevice 1.00 [ 8754.867421] usb 2-3: New USB device strings: Mfr1, Product2, SerialNumber0 [ 87…...

kubeadm安装K8s高可用集群之集群初始化及master/node节点加入calico网络插件安装

系列文章目录 1.kubeadm安装K8s高可用集群之基础环境配置 2.kubeadm安装K8s集群之高可用组件keepalivednginx及kubeadm部署 3.kubeadm安装K8s高可用集群之集群初始化及master/node节点加入集群calico网络插件安装 kubeadm安装K8s高可用集群之集群初始化及master/node节点加入ca…...

游戏何如防抓包

游戏抓包是指在游戏中&#xff0c;通过抓包工具捕获和分析游戏客户端与服务器之间传输的封包数据的过程。抓包工具可实现拦截、篡改、重发、丢弃游戏的上下行数据包&#xff0c;市面上常见的抓包工具有WPE、Fiddler和Charles Proxy等。 抓包工具有两种实现方式&#xff0c;一类…...

【LeetCode】每日一题 2024_12_19 找到稳定山的下标(模拟)

前言 每天和你一起刷 LeetCode 每日一题~ 最近力扣的每日一题出的比较烂&#xff0c;难度过山车&#xff0c;导致近期的更新都三天打鱼&#xff0c;两天断更了 . . . LeetCode 启动&#xff01; 题目&#xff1a;找到稳定山的下标 代码与解题思路 先读题&#xff1a;最重要…...

运维 mysql、redis 、RocketMQ性能排查

MySQL查看数据库连接数 1. SHOW STATUS命令-查询当前的连接数 MySQL 提供了一个 SHOW STATUS 命令&#xff0c;可以用来查看服务器的状态信息&#xff0c;包括当前的连接数。 SHOW STATUS LIKE Threads_connected;这个命令会返回当前连接到服务器的线程数&#xff0c;即当前…...

[SAP ABAP] 将内表数据转换为HTML格式

从sflight数据库表中检索航班信息&#xff0c;并将这些信息转换成HTML格式&#xff0c;然后下载或显示在前端 开发步骤 ① 自定义一个数据类型 ty_sflight 来存储航班信息 ② 声明内表和工作区变量&#xff0c;用于存储表头、字段、HTML内容和航班详细信息以及创建字段目录lt…...

LLM大语言模型私有化部署-使用Dify与Qwen2.5打造专属知识库

背景 Dify 是一款开源的大语言模型(LLM) 应用开发平台。其直观的界面结合了 AI 工作流、 RAG 管道、 Agent 、模型管理、可观测性功能等&#xff0c;让您可以快速从原型到生产。相比 LangChain 这类有着锤子、钉子的工具箱开发库&#xff0c; Dify 提供了更接近生产需要的完整…...

使用C语言连接MySQL

在C语言中连接MySQL数据库&#xff0c;通常需要使用MySQL提供的C API。以下是使用C语言连接MySQL数据库的基本步骤和示例代码&#xff1a; 步骤 1: 安装MySQL C API 首先&#xff0c;确保你的系统上安装了MySQL数据库&#xff0c;并且安装了MySQL C API库。在大多数Linux发行版…...

PyTorch 2.0 以下版本中设置默认使用 GPU 的方法

PyTorch 2.0 以下版本中设置默认使用 GPU 的方法 在 PyTorch 2.0以下版本中&#xff0c;默认情况下仍然是使用 CPU 进行计算&#xff0c;除非明确指定使用 GPU。在 PyTorch 2.0 以下版本中&#xff0c;虽然没有 torch.set_default_device 的便捷方法&#xff0c;但可以通过显式…...

信号槽【QT】

文章目录 对象树字符集信号槽QT坐标系信号与槽connect自定义槽自定义信号disconnect 对象树 #ifndef MYLABEL_H #define MYLABEL_H#include<QLabel> class MyLabel : public QLabel { public:// 构造函数使用带 QWidget* 版本的.// 确保对象能够加到对象树上MyLabel(QWi…...

【UE5 C++课程系列笔记】10——动态单播/多播的基本使用

目录 概念 申明动态委托 一、DECLARE_DYNAMIC_DELEGATE 二、DECLARE_DYNAMIC_MULTICAST_DELEGATE 绑定动态委托 一、BindDynamic 二、AddDynamic 三、RemoveDynamic 执行动态委托 ​一、Execute 二、ExecuteIfBound 三、IsBound 四、Broadcast 动态单播使用示…...

点击展示大图预览

原文链接在table表格里能够实现&#xff0c;点击里面的图片实现大图预览的效果&#xff1b; 一、先安装viewer — 使用npm安装 npm install v-viewer --save二、在main.js中引入 import Viewer from v-viewer //点击图片大图预览 import viewerjs/dist/viewer.css Vue.use(…...

【C++】分书问题:深入解析、回溯法高级应用与理论拓展

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;思路与算法回溯法理论基础 &#x1f4af;代码实现与解析完整代码代码关键步骤解析 &#x1f4af;时间复杂度与空间复杂度分析&#x1f4af;理论拓展&…...

java开发入门学习五-流程控制

流程控制语句 if&#xff0c; if...else&#xff0c; if..else if..else 与前端相同 略 switch case 与前端不同的是case不能使用表达式&#xff0c;使用表达式会报错 class TestSwitch {public static void main(String[] args) {// switch 表达式只能是特定的数据类型…...

【FFmpeg 教程 一】截图

本章使用 ffmpeg 实现观影中经常会用到的功能&#xff0c;截图。 以下给出两种方式。 课程需具备的基础能力&#xff1a;Python 1. 使用 subprocess 调用 FFmpeg 命令 import subprocess def extract_frame(video_path, output_image_path, timestamp"00:00:05")&qu…...

北邮,成电计算机考研怎么选?

#总结结论&#xff1a; 基于当前提供的24考研复录数据&#xff0c;从报考性价比角度&#xff0c;建议25考研的同学优先选择北邮计算机学硕。主要原因是:相比成电&#xff0c;北邮计算机学硕的目标分数更低&#xff0c;录取率更高&#xff0c;而且北邮的地理位置优势明显。对于…...

深入了解京东API接口:如何高效获取商品详情与SKU信息

在当今数字化时代&#xff0c;电商平台的数据接口成为了连接商家与消费者的桥梁。京东作为国内领先的电商平台&#xff0c;其API接口为开发者提供了丰富的商品信息获取途径。本文将深入探讨如何使用京东API接口高效获取商品详情与SKU信息&#xff0c;并附上简短而实用的代码示例…...