目录

一、概念与结构

 二、双向链表的实现

1、初始化

2、尾插 

3、头插

4、尾删 

5、头删 

6、在指定位置之后插入结点 

 7、删除指定位置的结点

三、完整参考代码 

一、概念与结构

        这里的双向链表是指带头的的双向循环链表,这里的“带头”和之前所说的“头结点”是两个概念,带头链表里的头结点,实际是“哨兵位”。哨兵位节点不存储任何有效元素,只是起一个“站岗放哨”的作用。和单链表一样,双向链表也是由一个一个的结点组成,但这里的结点由三个部分组成:保存的数据+指向下一个节点的指针+指向前一个节点的指针。

typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}LTNode;
LTNode* LTBuyNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = newnode->prev = newnode;return newnode;
}

注:当单链表为空时,指向第一个结点的指针为空;当双向链表为空时,链表中只有一个头结点~ 

 二、双向链表的实现

1、初始化

双向链表的初始化有两种方式,这里更推荐使用第二种。

第一种:

void LTInit(LTNode** pphead)
{assert(pphead);*pphead = LTBuyNode(-1);
}

第二种:

LTNode* LTInit()
{LTNode* phead = LTBuyNode(-1);return phead;
}

2、尾插 

 尾插这里的参数要注意传的是一级指针而不是二级指针,因为我们在初始化时给头结点申请了一块空间(假设这块空间的地址是0x339),尾插操作改变的只是头结点的prev指针和next指针的值,并没有修改头结点的地址。那为什么之前的单向链表传的是二级指针呢?单链表的第一个结点phead初始情况下为NULL,现在向单链表中尾插一个结点(假设该结点的地址是0x300)。此时phead的值从NULL变为了0x300,phead的值发生了改变,所以传的是二级指针。

在尾插操作中,需要修改的就是头结点,尾结点和新插入的结点。对于新节点来说,我们需要修改prev和next指针,对于头结点要修改prev,尾结点要修改next。在双向链表中,我们不用遍历整个链表来找到尾结点,因为可以直接通过头结点的prev指针来找到尾结点。

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead   phead->prev(尾结点)   newnodenewnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;phead->prev = newnode;
}

3、头插

头插是在第一个结点之前插入新节点,而不是在头结点之前插入。

void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead  newnode  phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}

4、尾删 

进行删除操作之前,首先要判断双向链表是否为空。

//只有一个头节点的情况下,双向链表为空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}

//尾删
void LTPopBack(LTNode* phead)
{assert(!LTEmpty(phead));LTNode* del = phead->prev;//phead  del->prev  delphead->prev = del->prev;del->prev->next = phead;free(del);del = NULL;
}

5、头删 

//头删
void LTPopFront(LTNode* phead)
{assert(!LTEmpty(phead));LTNode* del = phead->next;//phead  del  del->nextphead->next = del->next;del->next->prev = phead;free(del);del = NULL;
}

6、在指定位置之后插入结点 

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);//pos  newnode  pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}

 7、删除指定位置的结点

//删除pos位置的结点
void Erase(LTNode* pos)
{assert(pos);//pos->prev  pos  pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

三、完整参考代码 

List.h

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>//双向链表的结构
typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}LTNode;void LTPrint(LTNode* phead);bool LTEmpty(LTNode* phead);//双向链表的初始化
//void LTInit(LTNode** pphead);LTNode* LTInit();//尾插
void LTPushBack(LTNode* phead, LTDataType x);//头插
void LTPushFront(LTNode* phead, LTDataType x);//尾删
void LTPopBack(LTNode* phead);//头删
void LTPopFront(LTNode* phead);LTNode* LTFind(LTNode* phead, LTDataType x);//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);//删除pos位置的结点
void LTErase(LTNode* pos);//传二级:违背接口一致性
//void LTDestroy(LTNode** pphead);
//传一级:调用完成之后将实参手动置为NULL(推荐)
void LTDestroy(LTNode* phead);

List.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include "List.h"LTNode* LTBuyNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = newnode->prev = newnode;return newnode;
}void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d -> ", pcur->data);pcur = pcur->next;}printf("\n");
}//双向链表的初始化
//void LTInit(LTNode** pphead)
//{
//	assert(pphead);
//	*pphead = LTBuyNode(-1);
//}LTNode* LTInit()
{LTNode* phead = LTBuyNode(-1);return phead;
}//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead   phead->prev(尾结点)   newnodenewnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;phead->prev = newnode;
}//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead  newnode  phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}//只有一个头节点的情况下,双向链表为空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}//尾删
void LTPopBack(LTNode* phead)
{assert(!LTEmpty(phead));LTNode* del = phead->prev;//phead  del->prev  delphead->prev = del->prev;del->prev->next = phead;free(del);del = NULL;
}//头删
void LTPopFront(LTNode* phead)
{assert(!LTEmpty(phead));LTNode* del = phead->next;//phead  del  del->nextphead->next = del->next;del->next->prev = phead;free(del);del = NULL;
}LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}//没找到return NULL;
}//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);//pos  newnode  pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}//删除pos位置的结点
void LTErase(LTNode* pos)
{assert(pos);//pos->prev  pos  pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}void LTDestroy(LTNode* phead)
{LTNode* pcur = phead->next;while(pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}free(phead);phead = NULL;
}

test.c 

#define  _CRT_SECURE_NO_WARNINGS 1
#include "List.h"void test01()
{LTNode* plist = LTInit();LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPrint(plist);//LTPushFront(plist, 1);//LTPushFront(plist, 2);//LTPopBack(plist);//LTPrint(plist);//LTPopFront(plist);//LTPrint(plist);LTNode* find = LTFind(plist, 3);LTErase(find);LTPrint(plist);LTDestroy(plist);plist = NULL;
}int main()
{test01();return 0;
}

 

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

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

相关文章

【DeepSeek-R1 】分词系统架构解析

文章目录 🧩前言 🔍 1. SentencePiece Unigram 的核心原理 1.1 算法基础框架 1.2 核心数学原理 1.3 与BPE/WordPiece的对比 ⚙️ 2. DeepSeek-R1 分词器实现细节 2.1 词表结构设计 2.2 关键特性实现 📊 3. 性能优化关键技术 3.1 加速策略对比 3.2 编码过程伪代码 🔬 4.…

Linux自主实现shell

以下是在Linux操作系统 centos7版本下实现的shell &#xff0c;该shell具备bash的基础功能&#xff0c;无上下键输入历史命令功能&#xff0c;删除字符或命令时按住Ctrl Back #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.…

vue+elementUI上传图片至七牛云组件封装及循环使用

1.效果&#xff08;解决循环组件赋值问题&#xff09; 废话不多说直接上代码 2.下载七牛云依赖 npm install qiniu-js # 或者使用 yarn yarn add qiniu-js3.在vue组件中引入 import * as qiniu from qiniu-js4.在components文件夹下创建UploadImg1/uploadImg.vue组件 <templ…

2025年6月电子学会青少年软件编程(C语言)等级考试试卷(一级)

答案和更多内容请查看网站&#xff1a;【试卷中心 -----> 电子学会 ----> C/C ----> 一级】 网站链接 青少年软件编程历年真题模拟题实时更新 一、编程题 第 1 题 希望如光 题目描述 在充满挑战的生活中&#xff0c;希望往往是支撑人们穿越黑暗的核心力量。这…

拒绝复杂,AI图表制作简单化

在信息爆炸的时代&#xff0c;数据可视化已成为传递信息的核心手段。无论是职场汇报中的业绩分析&#xff0c;还是学术研究里的实验数据呈现&#xff0c;一张清晰直观的图表往往能胜过千言万语。而 AI 技术的介入&#xff0c;彻底改变了图表制作的传统模式 —— 它不仅让零基础…

easypoi生成多个sheet的动态表头的实现

在使用 EasyPOI 导出 Excel 时&#xff0c;生成多个 Sheet 且每个 Sheet 的表头是动态的&#xff08;即每个 Sheet 的列数和列名可能不同&#xff09;&#xff0c;可以通过如下方式实现&#xff1a;✅ 实现原理简述 使用 Workbook workbook ExcelExportUtil.exportExcel(expor…

移除链表元素+反转链表+链表的中间节点+合并两个有序链表+环形链表约瑟夫问题+分割链表

一、移除链表元素 给你一个链表的头节点 phead 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 (列表中的节点数目在范围 [0, 104] 内) 示例&#xff1a;输入&#xff1a;head [1,2,6,3,4,5,6], val 6 …

vue3+arcgisAPI4示例:轨迹点模拟移动(附源码下载)

demo源码运行环境以及配置运行环境&#xff1a;依赖Node安装环境&#xff0c;需要安装Node。 运行工具&#xff1a;vscode或者其他工具。 配置方式&#xff1a;下载demo源码&#xff0c;vscode打开&#xff0c;然后顺序执行以下命令&#xff1a; &#xff08;1&#xff09;下载…

Design Compiler:Milkyway库的创建与使用

相关阅读 Design Compilerhttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 DC Ultra推出了拓扑模式&#xff0c;在综合时会对标准单元进行粗布局(Coarse Placement)并使用虚拟布线(Virtual Routing)技术计算互联延迟&#xff0c;关于拓…

嵌入式教学的云端革命:高精度仿真如何重塑倒车雷达实验与工程教育——深圳航天科技创新研究院赋能新一代虚实融合实训平台

一、嵌入式教学的困境与破局之道 在传统嵌入式系统教学中&#xff0c;硬件依赖始终是核心痛点。以“倒车雷达实验”为例&#xff0c;学生需操作STM32开发板、超声波传感器、蜂鸣器等硬件&#xff0c;面临设备损耗、接线错误、调试效率低等问题。更关键的是&#xff0c;物理硬件…

flutter-boilerplate-project 学习笔记

项目地址&#xff1a; https://github.com/zubairehman/flutter_boilerplate_project/tree/master 样板包含创建新库或项目所需的最小实现。存储库代码预加载了一些基本组件&#xff0c;例如基本应用程序架构、应用程序主题、常量和创建新项目所需的依赖项。通过使用样板代码…

集成电路学习:什么是CMSIS微控制器软件接口标准

CMSIS,即Cortex Microcontroller Software Interface Standard(Cortex微控制器软件接口标准),是由ARM公司与多家不同的芯片和软件供应商紧密合作定义的一个标准。该标准旨在为基于ARM Cortex处理器的微控制器提供一套与供应商无关的硬件抽象层,从而简化软件的开发、重用,…

由浅入深使用LangGraph创建一个Agent工作流

创建一个简单的工作流&#xff1a;Start ——> 节点1(固定输入输出) ——> Endfrom langchain_core.messages import SystemMessage, HumanMessage, AIMessage from langgraph.graph import StateGraph, START, END from typing_extensions import TypedDict from typing…

PL-0功能拓展及基于VSCode的IDE配置

title: PL/0功能拓展及基于VSCode的IDE配置 date: 2024-08-06 22:46:38 tags: 做过的实验||项目复盘 top: true 概述PL/0语言可以看成PASCAL语言的子集,它的编译程序是由C语言编写的编译解释执行系统。PL/0能充分展示高级语言的最基本成分。拓展了pl0语言的基础功能&#xff08…

【低空经济】大型露天矿区安全生产无人机巡查与管理系统设计

1. 引言 大型露天矿区因其广阔的作业区域和复杂的环境条件&#xff0c;安全生产管理面临着严峻的挑战。随着科技的进步&#xff0c;无人机作为一种现代化的巡查工具&#xff0c;逐渐被应用于矿区的安全生产管理中。无人机具备高效、灵活、成本相对低廉等优点&#xff0c;可以在…

SpringCloud学习第一季-3

目录 11.服务网关-Gateway新一代网关 一、Gateway概述 1、Gateway是什么 1.1 概述 2、 能干嘛 3、微服务架构中网关在哪里 4、为什么选择gateway? 4.1 SpringCloud Gateway具有如下特性 4.2 SpringCloud Gateway 与 Zuul的区别 5、Zuul1.x模型 6、gateway模型 二、…

超越边界:MongoDB 16MB 文档限制的 pragmatic 解决方案

在软件开发中&#xff0c;我们选择的技术栈往往带有一些固有的设计边界。对于 MongoDB 而言&#xff0c;其最著名的边界之一便是 BSON 文档最大 16MB 的大小限制。在大多数场景下&#xff0c;这个限制是绰绰有余的&#xff0c;它鼓励开发者设计更为精简和规范的数据模型。然而&…

深入探讨:PostgreSQL正则表达式中的邮政编码匹配

引言 在处理大量数据时,如何高效地从字符串中提取特定模式的文本,如邮政编码,是一个常见且具有挑战性的任务。本文将通过一个具体实例,探讨在PostgreSQL中使用正则表达式匹配加拿大邮政编码的问题,并提供解决方案。 问题描述 我们希望能够从字符串中提取所有符合加拿大…

集合框架(重点)

第十五天集合框架1.什么是集合 Collections集合Collection&#xff0c;也是一个数据容器&#xff0c;类似于数组&#xff0c;但是和数组是不一样的。集合是一个可变的容器&#xff0c;可以随时向集合中添加元素&#xff0c;也可以随时从集合中删除元素。另外&#xff0c;集合还…

深度学习核心:神经网络-激活函数 - 原理、实现及在医学影像领域的应用

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#,Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开发…