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

数据结构学习笔记 双向链表

……接上文

6.  双向链表

6.1 特性

逻辑结构:线性结构

存储结构:链式结构

操作:增删改查

建立双向链表结构体:

	//双向链表的节点定义 	typedef int datatype;
	typedef struct node_t
	{
		datatype data;//数据域 
		struct node_t *next;//指向下一个节点的指针 next 先前的
		struct node_t *prior;//指向前一个节点的指针 prior 下一个
	}link_node_t,*link_node_p;	//将双向链表的头指针和尾指针封装到一个结构体里 
	//思想上有点像学的链式队列
	typedef struct doublelinklist
	{
		link_node_p head; //指向双向链表的头指针
		link_node_p tail; //指向双向链表的尾指针
		int len; //用来保存当前双向链表的长度
	}double_list_t,*double_list_p;

6.2 双向链表相关操作

需要注意的是,与单链表不同,双链表创建过程中,每创建一个新节点都要与其前驱节点建立两次联系,分别是:

(1)  将新节点的 prior 指针指向直接前驱节点。

(2)  将直接前驱节点的 next 指针指向新节点。

1)  创建空的双向链表

//1.创建一个空的双向链表
double_list_p createEmptyDoubleLinkList()
{// 1. 申请空间存放头尾指针结构体
    double_list_p p = (double_list_p)malloc(sizeof(double_list_t));if(NULL == p){perror("createEmptyDoubleLinkList");return NULL;}
    p->len = 0;//2.初始化,头尾指针分别指向开辟头节点,因为当前链表为空
    p->head = p->tail = (link_node_p)malloc(sizeof(link_node_t));if(p->head == NULL){perror("p->head malloc failed!");return NULL;}    p->head->next = NULL;
    p->head->prior = NULL;return p;
}

2)  指定位置插入

// 2.向双向链表的指定位置插入数据 post位置, data数据
int insertIntoDoubleLinkList(double_list_p p, int post, datatype data)
{
    link_node_p temp = NULL; // 用来临时保存head或者tail的位置if (post < 0 || post > p->len){perror("insertIntoDoubleLinkList err");return -1;}    link_node_p pnew = (link_node_p)malloc(sizeof(link_node_t));if (pnew == NULL){perror("pnew malloc err");return -1;}// 初始化新节点
    pnew->data = data;
    pnew->prior = NULL;
    pnew->next = NULL;// 插入链表的尾巴if (post == p->len){
        p->tail->next = pnew;
        pnew->prior = p->tail;
        p->tail = pnew; // 移动尾指针}// 中间差else{if (post < p->len / 2) // 前半段{// temp移动到插入位置
            temp = p->head;for (int i = 0; i <= post; i++)
                temp = temp->next;}else // 后半段{
            temp = p->tail;for (int i = p->len - 1; i > post; i--)
                temp = temp->prior;}// 2) 进行插入操作(先连前面,再练后面)
        pnew->prior = temp->prior;
        temp->prior->next = pnew;
        pnew->next = temp;
        temp->prior = pnew;}
    p->len++;  // 插入完成,链表长度+1return 0;
}

3)  双向链表遍历

// 3.遍历双向链表
void showDoubleLinkList(double_list_p p)
{
    link_node_p temp = NULL;printf("正向遍历\n");
    temp = p->head;while (temp->next != NULL){
        temp = temp->next;printf("%d ", temp->data);}printf("\n");printf("反向遍历\n");
    temp = p->tail;while (temp != p->head){printf("%d ", temp->data);
        temp = temp->prior;}printf("\n----------------\n");
}

4)  判断双向链表是否为空

//4.判断双向链表是否为空
int isEmptyDoubleLinkList(double_list_p p)
{return p->len == 0;
}

5)  删除双向链表指定位置

//5.删除双向链表指定位置数据
int deletePostDoubleLinkList(double_list_p p,int post)
{
    link_node_p temp = NULL;// 1. 容错判断if(isEmptyDoubleLinkList(p) || post >= p->len || post < 0){error("deletePostDoubleLinkList err\n");return -1;}//2.对删除位置进行分析,分为两种情况if(post == p->len-1) // //删除的是链表最后一个节点{// 1)将尾指针向前移动一个位置
        p->tail = p->tail->prior;// 2)释放被删除节点,也就是最后一个节点free(p->tail->next);// 3)将最后一个节点与链表断开
        p->tail->next = NULL;}else    // 中间删除{if(post < p->len/2)  // 说明在前半段{
            temp = p->head;for (int i = 0; i <= post; i++)
                temp = temp->next;}else    // 说明在后半段{
            temp = p->tail;for (int i = p->len-1; i > post; i--){
                temp = temp->prior;}}// 进行删除操作
        temp->prior->next = temp->next;
        temp->next->prior = temp->prior;free(temp);
        temp = NULL;}// 3. 双向链表的长度-1
    p->len--;return 0;
}

6)  求双向链表的长度

//6.求双向链表的长度
int lengthDoubleLinkList(double_list_p p)
{return p->len;
}

7)  查找指定数据出现的位置

//7.查找指定数据出现的位置 data被查找的数据
int searchPostDoubleLinkList(double_list_p p,datatype data)
{
    link_node_p temp = p->head;int post =0;  // 保存位置while(temp->next != NULL){
        temp = temp->next;if(temp->data == data){return post;}
        post++;}return -1;
}

8)  修改指定位置的数据

//8.修改指定位置的数据,post修改的位置 data被修改的数据
int changeDataDoubleLinkList(double_list_p p,int post, datatype data)
{if(isEmptyDoubleLinkList(p) || post >= p->len || post < 0){perror("changeDataDoubleLinkList err");return -1;}
    link_node_p temp = NULL;if(post < p->len/2) // 说明在前半段{
        temp = p->head;for (int i = 0; i <= post; i++)
            temp = temp->next;}else{
        temp = p->tail;for (int i = p->len-1; i > post; i--)
            temp = temp->prior;}
    temp->data = data;return 0;
}

9)  删除双向链表中指定数据

// 9.删除双向链表中的指定数据 data代表删除所有出现的data数据
/*
    思想:从头节点后节点开始用指针h遍历,相当于遍历无头链表,遇到需要删除节点的就用h指向它然后删除,如果不需要删除则h继续往后走一个。这里因为是双向链表可以找到前驱,所以不需要每次指向被删除节点的前一个然后跨过了。
*/
void deleteDataDoubleLinkList(double_list_p p, datatype data)
{
    link_node_p h = p->head->next;
    link_node_p pdel = NULL;while (h != NULL) // 遍历双向链表(相当于遍历无头单向链表){if (h->data == data) // 相等{if (h == p->tail)  // 尾节点{
                p->tail = p->tail->prior;free(p->tail->next);
                p->tail->next = NULL;
                h = NULL;}else // 中间节点{
                h->prior->next = h->next;
                h->next->prior = h->prior;
                pdel = h;
                h = h->next;free(pdel);
                pdel = NULL;}
            p->len--;}else{
            h = h->next;}}
}

main函数代码

int main(int argc, char const *argv[])
{// int i;
    double_list_p p = createEmptyDoubleLinkList();for (int i = 0; i < 5; i++){insertIntoDoubleLinkList(p, i, i);}showDoubleLinkList(p);deletePostDoubleLinkList(p, 2);printf("len is %d\n", lengthDoubleLinkList(p));showDoubleLinkList(p);deletePostDoubleLinkList(p, 3);showDoubleLinkList(p);printf("1 post is: %d\n", searchPostDoubleLinkList(p, 1));int len = lengthDoubleLinkList(p);for (int i = 0; i < len; i++){deletePostDoubleLinkList(p, 0);}printf("len is %d\n", lengthDoubleLinkList(p));showDoubleLinkList(p);printf("is Empty? %d\n", isEmptyDoubleLinkList(p));free(p);
    p = NULL;return 0;
}

                                                                                                                                 未完待续……

相关文章:

数据结构学习笔记 双向链表

……接上文 6. 双向链表 6.1 特性 逻辑结构&#xff1a;线性结构 存储结构&#xff1a;链式结构 操作&#xff1a;增删改查 建立双向链表结构体&#xff1a; //双向链表的节点定义 typedef int datatype;typedef struct node_t{datatype data;//数据域 struct node_t *next;//…...

深度学习作业十 BPTT

目录 习题6-1P 推导RNN反向传播算法BPTT. 习题6-2 推导公式(6.40)和公式(6.41)中的梯度&#xff0e; 习题6-3 当使用公式(6.50)作为循环神经网络的状态更新公式时&#xff0c; 分析其可能存在梯度爆炸的原因并给出解决方法&#xff0e; 习题6-2P 设计简单RNN模型&#xff0…...

html+css+JavaScript实现轮播图

html+css+JavaScript实现轮播图 实现思路 要实现一个轮播图功能,我们需要HTML来构建结构,CSS来设计样式,以及JavaScript来添加交互功能。下面我将分别分析这三个部分是如何协同工作来实现轮播图的。 HTML - 结构 HTML部分定义了轮播图的基本结构,包括图片列表、指示器和…...

Python+onlyoffice 实现在线word编辑

onlyoffice部署 version: "3" services:onlyoffice:image: onlyoffice/documentserver:7.5.1container_name: onlyofficerestart: alwaysenvironment:- JWT_ENABLEDfalse#- USE_UNAUTHORIZED_STORAGEtrue#- ONLYOFFICE_HTTPS_HSTS_ENABLEDfalseports:- "8080:8…...

PostgreSQLt二进制安装-contos7

1、安装依赖 yum install -y gcc readline readline-devel zlib-devel net-tools perl wget numactl libicu-devel bison flex openssl-devel pam pam-devel libxml2 libxml2-devel libxslt libxslt-devel openldap openldap-devel 2、创建目录 mkdir -p /data/postgresql/{…...

Neo4j启动时指定JDK版本

项目使用jdk1.8&#xff0c;同时需要安装neo4j5.15版本&#xff0c;使用jdk17. 1.mac或者liunx&#xff0c;找到neo4j目录bin的下neo4j文件 设置JAVA_HOME: 2.windows,找到bin下面的neo4j.bat文件 set "JAVA_HOME{JDK文件目录}" 重启后生效。...

kanzi3.6.10 窗口插件-美化绑定内容

文章目录 1. 创建kanzi窗口插件2. 业务逻辑3. 关键代码3.1 获取绑定信息3.2 解析绑定3.3 动态生成富文本控件 4. 安装 背景&#xff1a;kanzi的节点绑定信息是黑色的&#xff0c;看起来非常费劲&#xff0c;如果能代码高亮显示&#xff0c;对开发会很有帮助。 美化前 美化后 …...

利用tablesaw库简化表格数据分析

tableaw是处理表格数据的优秀工具。它提供了一组强大而灵活的功能&#xff0c;使操作、分析和可视化数据表变得容易。在这篇博文中&#xff0c;我们将介绍tableaw的主要特性、如何使用这些特性&#xff0c;以及如何使用tableaw处理表格数据的一些示例。 tablesaw简介 tableaw…...

记录一下,解决js内存溢出npm ERR! code ELIFECYCLEnpm ERR! errno 134 以及 errno 9009

项目是个老项目&#xff0c;依赖包也比较大&#xff0c;咱就按正常流程走一遍来详细解决这个问题&#xff0c;先看一下node版本&#xff0c;我用的是nvm管理的&#xff0c;详细可以看我的其他文章 友情提醒&#xff1a;如果项目比较老&#xff0c;包又大&#xff0c;又有一些需…...

【JavaWeb后端学习笔记】MySQL的数据查询语言(Data Query Language,DQL)

MySQL DQL 1、DQL语法与数据准备1.1 DQL语法1.2 数据准备 2、基础查询2.1 查询指定字段2.2 查询返回所有字段2.3 给查询结果起别名2.4 去除重复记录 3、条件查询3.1 条件查询语法3.2 条件查询案例分析 4、分组查询4.1 分组查询语法4.2 分组查询案例分析 5、排序查询5.1 排序查询…...

360 最新Android面试题及参考答案

一个 activity 只能有一个进程么【对进程的理解】 在 Android 中,一个 Activity 并不只能有一个进程。进程是操作系统进行资源分配和调度的一个独立单位。 从原理上来说,Android 系统允许开发者通过在 AndroidManifest.xml 文件中的<activity>标签设置 android:process…...

《操作系统 - 清华大学》6 -3:局部页面置换算法:最近最久未使用算法 (LRU, Least Recently Used)

文章目录 1. 最近最久未使用算法的工作原理2. 最近最久未使用算法示例3.LRU算法实现3.1 LRU的页面链表实现3.2 LRU的活动页面栈实现3.3 链表实现 VS 堆栈实现 1. 最近最久未使用算法的工作原理 最近最久未使用页面置换算法&#xff0c;简称 LRU&#xff0c; 算法思路&#xff…...

ES6新增了哪些特性(待更新)

1.let&#xff0c;const 1.1.var&#xff0c;let&#xff0c;const的区别 1.1.1 var存在变量提升&#xff0c;let和const不存在。 1.1.2 let和const只能在块作用域里访问。 1.1.3 同一作用域下let和const不能声明同名变量&#xff0c;而var可以。 1.1.4 const定义常量&am…...

剖析一下自己的简历第二条

剖析一下自己的简历第二条 背景前置说明可能会被问到的问题 背景 剖析一下自己简历, 增加对一些专业知识的掌握. 我的简历第二条是这样写的: “2. 熟悉JVM、JMM&#xff0c;包括内存模型&#xff0c;垃圾回收机制&#xff0c;了解其基本调优技巧并具备线上调优经验。”. 前置…...

威联通-001 手机相册备份

文章目录 前言1.Qfile Pro2.Qsync Pro总结 前言 威联通有两种数据备份手段&#xff1a;1.Qfile Pro和2.Qsync Pro&#xff0c;实践使用中存在一些区别&#xff0c;针对不同备份环境选择是不同。 1.Qfile Pro 用来备份制定目录内容的。 2.Qsync Pro 主要用来查看和操作文…...

性能测试基础知识jmeter使用

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;测试_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 性能指标 1. 并发数 (Con…...

Ceph文件存储

Ceph文件存储1.概念:数据以文件的形式存储在存储介质上&#xff0c;每个文件都有一个唯一的文件名并存储在一个目录结构中。提供方便的文件访问接口&#xff0c;支持多种文件操作&#xff0c;如创建、删除、读取、写入、复制等。用于存储和管理个人文件&#xff0c;如文档、图片…...

Hive分区表新增字段并指定位置

Hive分区表新增字段并指定位置 1、Hive分区表新增字段2、CASCADE关键字3、历史分区新增列为NULL问题 1、Hive分区表新增字段 Hive分区表新增字段并指定位置主要分为两步&#xff1a;新增字段和移动字段 1&#xff09;新增字段 ALTER TABLE table_name ADD COLUMNS (col_name …...

关系型数据库(RDBMS)与非关系型数据库(NoSQL)应用场景

关系型数据库适用于事务性、强一致性和结构化数据场景&#xff1b;非关系型数据库则在高并发、大数据、非结构化数据场景中表现更优&#xff1b;数据量和并发量增加时&#xff0c;应通过分库分表、缓存、集群扩展等手段进行优化。 1. 在什么样的业务场景下&#xff0c;你会优先…...

浅谈CI持续集成

1.什么是持续集成 持续集成&#xff08;Continuous Integration&#xff09;&#xff08;CI&#xff09;是一种软件开发实践&#xff0c;团队成员频繁地将他们的工作成果集成到一起(通常每人每天至少提交一次&#xff0c;这样每天就会有多次集成)&#xff0c;并且在每次提交后…...

华为新手机和支付宝碰一下 带来更便捷支付体验

支付正在变的更简单。 11月26日&#xff0c;华为新品发布会引起众多关注。发布会上&#xff0c;华为常务董事余承东专门提到&#xff0c;华为Mate 70和Mate X6折叠屏手机的“独门支付秘技”——“碰一下”&#xff0c;并且表示经过华为和支付宝的共同优化&#xff0c;使用“碰…...

shell编程基础笔记

目录 echo改字体颜色和字体背景颜色 bash基本功能&#xff1a; 运行方式&#xff1a;推荐使用第二种方法 变量类型 字符串处理&#xff1a; 条件判断&#xff1a;&#xff08;使用echo $?来判断条件结果&#xff0c;0为true&#xff0c;1为false&#xff09; 条件语句&a…...

VS Code配置Lua调试环境

我这里选用Emmylua进行Lua代码调试&#xff0c;调试环境配置如下: 一、安装Emmylua 在VS Code扩展里搜索emmylua&#xff0c;然后进行安装, 如下 二、配置launch.json 在Run and Debug里生成launch.json文件 点击以上菜单后&#xff0c;生成launch.json文件如下: 三、配置.e…...

FPGA(一)Quartus II 13.1及modelsim与modelsim-altera安装教程及可能遇到的相关问题

零.前言 在学习FPGA课程时&#xff0c;感觉学校机房电脑用起来不是很方便&#xff0c;想着在自己电脑上下载一个Quartus II 来进行 基于 vhdl 语言的FPGA开发。原以为是一件很简单的事情&#xff0c;没想到搜了全网文章发现几乎没有一个完整且详细的流程教学安装&#xff08;也…...

【单片机】ESP32-S3+多TMC2209控制步进电机系列1 UART通信及无传感回零 硬件部分

目录 1. 硬件选型1.1 esp32硬件型号1.2 TMC2209 硬件型号 2 原理接线图2.1 esp32接线2.2 TMC2209接线2.2.1 单向通讯 不配置地址2.2.2 单向通讯 配置地址2.2.3 双向通讯 单UART 【本文采用】2.2.4 双向通讯 多UART 3. 成品效果 1. 硬件选型 1.1 esp32硬件型号 采用的是微雪ES…...

Django之ORM

1.ORM介绍 ORM概念 对象关系映射&#xff08;Object Relational Mapping&#xff0c;简称ORM&#xff09;模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。 简单的说&#xff0c;ORM是通过使用描述对象和数据库之间映射的元数据&#xff0c;将程序中的对…...

html css 图片背景透明

html css图标背景透明 css属性&#xff1a; background-color:transparent; mix-blend-mode: multiply; 完整HTML代码&#xff1a; <html><head><title>Test</title></head><body><div id"test" style"background-col…...

使用ALB实现gRPC协议的负载均衡

gRPC是一种高性能、开源的远程过程调用框架&#xff0c;当您使用gRPC进行后端服务通信时&#xff0c;您可使用应用型负载均衡ALB&#xff08;Application Load Balancer&#xff09;实现gRPC协议的负载均衡&#xff0c;统一流量入口。gRPC基于HTTP/2协议进行通信&#xff0c;目…...

解决IDEA的easycode插件生成的mapper.xml文件字段之间逗号丢失

问题 easycode插件生成的mapper.xml文件字段之间逗号丢失&#xff0c;如图 解决办法 将easycode(在settings里面的othersettings)设置里面的Template的mapper.xml.vm和Global Config的mybatisSupport.vm的所有$velocityHasNext换成$foreach.hasNext Template的mapper.xml.vm(…...

【Linux测试题】

1. 选择题 题目&#xff1a; 如果想将电脑中Windows C盘&#xff08;hd1&#xff09;安装在Linux文件系统的/winsys目录下&#xff0c;请问正确的命令是&#xff08;&#xff09;。 选项&#xff1a; A. root104.123.123.123:~# mount dev/hd1 /winsys B. root104.123.123.12…...