【数据结构】双链表解析+完整代码(创建、插入、删除)

3.2 双链表

3.2.1 双链表的定义
  • 定义

    单链表的缺点:无法逆向操作,插入删除时只能从头开始遍历,很不方便。

    双链表:每个结点都定义两个指针prior和next,分别指向前驱和后继,可进可退。

typedef struct DNode{
    ElemType data;
    struct DNode *prior,*next; //前驱指针和后继指针
}DNode,*DLinklist;
  • 初始化双链表

    bool InitDLinkList(DLinklist &L){
        L=(DNode*)malloc(sizeof(DNode)); //分配头结点
        if(L==NULL)return false;
        L->prior=NULL; //头结点的前驱指针永远指向NULL
        L->next=NULL; //头结点还暂时没有后继
    }
    
  • 判空(带头结点)

    bool Empty(DLinkList L){
        if(L->next==NULL)
            return true;
        else
            return false;
    }
    
3.2.2 双链表的插入
  • 步骤

    如图

    1.要插入结点s连接p的后继结点:s->next=p->next;

    2.p的后继结点连接s:p->next->prior=s;

    3.要插入结点s与p连接:s->prior=p;

    4.p与s连接:p->next=s;

    • 注:语句顺序不唯一,但不任意。

bool InsertNextDNode(DNode*p,DNode*s){
    if(p==NULL||s=NULL)return false;
    
    s->next=p->next;
    if(p->next!=NULL)p->next->prior=s; //先判断p有没有后继结点,防止p为链尾结点时产生的空指针
    s->prior=p;
    p->next=s;
    return true;
}
  • 时间复杂度: O ( 1 ) O(1) O(1)
3.2.3 双链表的删除
  • 步骤

    如图:

    1.将p指向要删结点q的后继结点:p->next=q->next

    2.将q的后继结点与p连接:q->next->prior=p

    3.释放要删结点q:free(q)

    • 时间复杂度: O ( 1 ) O(1) O(1)
//删除结点p的后继结点
bool DeleteNextDNode(DNode *p){
    if(p==NULL)return false;
    DNode *q=p->next; //q为要删结点
    if(q==NULL)return false;
    p->next=q->next;
    if(q->next!=NULL)q->next->prior=p; //该判断防止q是最后一个结点,从而指针制空
    free(q);
    return true;
}
  • 销毁双链表

    void DestoryList(DLinklist &L){
        //循环释放各结点数据
        while(L->next!=NULL)
            DeleteNextNode(L);
        free(L); //释放头结点
        L=NULL; //头指针指向NULL
    }
    
*完整代码 双链表

以上只解释了双链表的定义、插入、删除,其他查找等操作与单链表一样,可看文章:
【数据结构】单链表解析+完整代码(创建 增删 查找等)
这里不再赘述,只在代码中展现。

#include<stdio.h>
#include<stdlib.h>

#define ElemType int

typedef struct DNode {
	ElemType data;
	struct DNode* prior,*next;
}DNode, * DLinkList;

//初始化
bool InitList(DLinkList& L) {
	L = (DNode*)malloc(sizeof(DNode));
	L->next = NULL;
	L->prior = NULL;
	return true;
}

//求表长
int Length(DLinkList L) {
	int len = 0;
	DNode* p = L;
	while (p->next != NULL) {
		len++;
		p = p->next;
	}
	return len;
}

//头插法建立
DLinkList List_HeadInsert(DLinkList& L) {
	L = (DNode*)malloc(sizeof(DNode));
	L->next = NULL;
	DNode* s;
	int x;
	scanf("%d", &x);
	while (x != 9999) {
		s = (DNode*)malloc(sizeof(DNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		scanf("%d", &x);
	}
	return L;
}

//尾插法建立
DLinkList List_TailInsert(DLinkList& L) {
	int x;
	L = (DNode*)malloc(sizeof(DNode)); //创建头结点
	DNode* s, * r = L; //s指向头结点,r指向尾结点
	scanf("%d", &x);
	while (x != 9999) {
		s = (DNode*)malloc(sizeof(DNode));
		s->data = x;
		r->next = s;
		r = s;
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}

//按序查找
DNode* GetItem(DLinkList& L, int i) {
	DNode* p = L->next;
	int j = 0;
	while (j < i && p != NULL) {
		p = p->next;
		j++;
	}
	return p;
}

//按值查找
int LocateElem(DLinkList& L, ElemType e) {
	DNode* p = L;
	int j = 0;
	while (p != NULL && p->data != e) {
		p = p->next;
		j++;
	}
	return j;
}

//按位序插入
bool ListInsert(DLinkList& L, int i, ElemType e) {
	if (i < 0)return false;

	DNode* p = L;
	int j = 0;
	while (j < i - 1 && p != NULL) {
		p = p->next;
		j++;
	}
	if (p == NULL)return false;

	DNode* s = (DNode*)malloc(sizeof(DNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

//指定结点后插操作
bool InsertNextDNode(DNode* p, DNode* s) {
	if (p == NULL||s==NULL)return false;

	s->next = p->next;
	if (p->next != NULL)p->next->prior = s; //先判断p有没有后继结点,防止p为链尾结点时产生的空指针
	s->prior = p;
	p->next = s;
	return true;
}

//删除结点p的后继结点
bool DeleteNextDNode(DNode* p) {
	if (p == NULL)return false;
	DNode* q = p->next; //q为要删结点
	if (q == NULL)return false;
	p->next = q->next;
	if (q->next != NULL)q->next->prior = p; //该判断防止q是最后一个结点,从而指针制空
	free(q);
	return true;
}

void PrintList(DLinkList& L) {
	DNode* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n\n");
}

void DestroyList(DLinkList& L) {
	//循环释放各结点数据
	while (L->next != NULL)
		DeleteNextDNode(L);
	free(L); //释放头结点
	L = NULL; //头指针指向NULL
}

int main() {
	DLinkList L;

	printf("头插法建立链表,输入以9999结束:\n");
	L = List_HeadInsert(L);
	PrintList(L);

	DestroyList(L);
	printf("尾插法建立链表,输入以9999结束:\n");
	L = List_TailInsert(L);
	PrintList(L);

	printf("求表长:%d\n", Length(L));
	printf("\n");

	printf("按位序插入:\n");
	int pos = 1, e = 998;
	ListInsert(L, pos, e);
	PrintList(L);

	printf("指定结点的后插操作:\n");
	DNode* p = L->next;
	DNode* q=(DNode*)malloc(sizeof(DNode));
	q->data = 222;
	q->next = NULL;
	q->prior = NULL;
	InsertNextDNode(p, q);
	PrintList(L);

	printf("按值查找:\n");
	printf("查找222的位序是:%d\n", LocateElem(L, 222));
	printf("\n");

	printf("按序查找:\n");
	DNode*x = GetItem(L, 2);
	printf("查找第3个元素值是:%d\n", x->data);
	printf("\n");

	printf("按指定结点删除:\n");
	p = L->next;
	DeleteNextDNode(p);
	PrintList(L);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32F103学习笔记(七) PWR电源管理(原理篇)

目录 1. PWR电源管理简介 2. STM32F103的PWR模块概述 2.1 PWR模块的基本工作原理 2.2 电源管理的功能和特点 3. PWR模块的常见应用场景 4. 常见问题与解决方案 1. PWR电源管理简介 PWR&#xff08;Power&#xff09;模块是STM32F103系列微控制器中的一个重要组成部分&…

阿里云短信验证笔记

1.了解阿里云的权限操作 进入AccessKey管理 选择子用户 创建用户组和用户 先创建用户组&#xff0c;建好再进行权限分配 添加短信管理权限 创建用户 创建好后的id和密码在此处下载可以得到 2.开通阿里云短信服务 进行申请&#xff0c;配置短信模板 阿里云短信API文档 短信服务…

xss过waf的小姿势

今天看大佬的视频学到了几个操作 首先是拆分发可以用self将被过滤的函数进行拆分 如下图我用self将alert拆分成两段依然成功执行 然后学习另一种姿势 <svg id"YWxlcnQoIlhTUyIp"><img src1 οnerrοr"window[eval](atob(document.getElementsByTagNa…

zk和etcd的读一致性对比

背景 zk和etcd都是日常我们用到的分布式一致性的组件集群&#xff0c;不过他们在读一致性上还是有一些差别的&#xff0c;本文就来对比一下 zk和etcd的读一致性对比 如果读客户端没有通过zk或者etcd自带的watcher监听的方式监听某个写客户端写入的内容&#xff0c;而是依赖写…

Spring Task的应用

介绍 Spring Task是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 定位&#xff1a; 定时任务框架 作用&#xff1a; 定时自动执行某段Java代码 应用场景&#xff1a; 引用卡每月还款提醒、银行贷款每月还款提醒、火车票售票系统处理未支…

力扣每日一题 统计可能的树根数目 换根DP

Problem: 2581. 统计可能的树根数目 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 灵神 复杂度 时间复杂度: O ( n m ) O(nm) O(nm) 空间复杂度: O ( n m ) O(nm) O(nm) Code class Solution {List<Integer>[] g;// 邻接表Set<Long> se…

安泰电压放大器怎么用

电压放大器是一种常见的电子设备&#xff0c;用于放大电压信号。它是许多电子系统中的关键组件之一&#xff0c;可以增加电压信号的幅度&#xff0c;以便于后续的处理和驱动其他设备。以下是电压放大器的使用方法&#xff1a; 确定需求&#xff1a;首先&#xff0c;明确你的需求…

Jquery操作DOM对象

文章目录 目录 文章目录 本章目标 一.DOM操作分类 二.JQuery中的DOM操作 内容操作 属性值操作 节点操作 节点属性操作 节点遍历 总结 本章目标 使用Jquery操作网页元素使用JQuery操作文本与属性值内容使用JQuery操作DOM节点使用Jquery遍历DOM节点使用JQuery操作CSS-DOM 一…

linux下 将指定网卡名加入udp组播代码示例(端口复用)

linux下可通过指定网卡名字来将网卡加入组播 一般来说网卡名为 eth0,eth1之类的,具体的需要通过ifconfig查看 具体逻辑就是通过指定的网卡名来获取网卡ip,后面就跟普通的创建udp套接字一样了,需要注意的是将网卡绑定到组播最好启用地址重用来避免端口相同导致的失败 SO_REUSE…

Python程序打包成exe可执行文件的常用方法

在Python中,您可以使用一些工具将您的Python程序打包成可执行文件(.exe)。以下是一些常用的工具: PyInstaller: PyInstaller是一个流行的工具,它可以将Python脚本打包成独立的可执行文件,支持Windows、Linux和Mac。您可以使用以下命令安装PyInstaller: pip install pyin…

疾控污水采样设备需具备云控功能吗

疾控污水采样设备是否需要具备云控功能&#xff0c;是一个值得深入探讨的问题。从当前的技术发展趋势和实际应用需求来看&#xff0c;具备云控功能的疾控污水采样设备具有显著的优势和必要性。 第一&#xff0c;云控技术的应用可以实现远程监控和管理。在污水采样过程中&#…

测试环境搭建整套大数据系统(七:集群搭建kafka(2.13)+flink(1.13.6)+dinky+hudi)

一&#xff1a;搭建kafka。 1. 三台机器执行以下命令。 cd /opt wget wget https://dlcdn.apache.org/kafka/3.6.1/kafka_2.13-3.6.1.tgz tar zxvf kafka_2.13-3.6.1.tgz cd kafka_2.13-3.6.1/config vim server.properties修改以下俩内容 1.三台机器分别给予各自的broker_id…

在Ubuntu中安装Anaconda和创建虚拟环境(保姆级教学,值得借鉴与信任)

一、下载linux版本的Anaconda 1.方法一&#xff1a;官网下载 https://www.anaconda.com/download#downloads2.方法二&#xff1a;在清华大学开源软件镜像站里下载 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/最后选择了Anaconda3-2022.10-Linux-x86_64.sh进行下…

AUTOMATION 自动化控制

Ansible介绍: 部署ansible:yum -y install ansible 批量管理服务器的工具2015年被红帽公司收购使用Python语言编写的基于ssh进行管理&#xff0c;所以不需要在被管端安装任何软件 ansible在管理远程主机的时候&#xff0c;主要是通过各种模块进行操作的 配置ansible管理环境: …

使用js写一个登录验证码效果

面试题 登录页面获取验证码的功能&#xff0c;用户点击获取验证码按钮(id”btn1”)&#xff0c;按文字变为“(N)后获取验证码”&#xff0c;N为倒计对秒数&#xff0c;从 60 开始&#xff0c;每秒减一&#xff0c;减到 0的时候&#xff0c;按钮文字变为“获取验证码”&#xff…

Python爬虫项目实战案例-批量下载网易云榜单音乐保存至本地

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…

Linux系统Docker部署StackEdit Markdown并实现公网访问本地编辑器

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…

国际伦敦银走势如此多变?如何应对

国际伦敦银走势由于受众多因素影响&#xff0c;因此它的多变是正常的&#xff0c;关键在于我们如何在多变的市场中应付自如&#xff0c;不光不会亏损&#xff0c;而且还要在多变的走势中抓住它的转折&#xff0c;找到入场的机会&#xff0c;下面我们就来讨论一下应对多变的国际…

刚入编的小学老师工资多少

“刚入编的小学老师&#xff0c;一个月能挣多少钱&#xff1f;”这个问题似乎总能激起一层波澜。不少人猜测&#xff0c;教师这份职业稳定、有寒暑假&#xff0c;工资应该不低吧&#xff1f;可真相往往出乎人们的意料。 事实上&#xff0c;一位刚入编的小学老师&#xff0c;月薪…

vue3使用echarts绘制地图

vue3使用echarts绘制地图 安装echarts npm install echarts下载地图的json数据【我这里是把json数据单独粘出来然后新建了一个文件china.json】 下载中国及各个省份的地图数据引入 import chinaJson from ./china.json绘制地图 <template><div ref"myChart&q…