数据结构:双向链表

文章目录

  • 1. 双向带头循环链表的结构
  • 2. 相关操作
    • 2.1 创建节点
    • 2.2 尾插
    • 2.3 头插
    • 2.4 打印
    • 2.5 尾删
    • 2.6 头删
    • 2.7 查找
    • 2.8 指定位置前/后插入
    • 2.9 删除指定位置的节点
    • 2.10 删除指定位置后的节点
    • 2.11 销毁链表
  • 3.顺序表与链表区别

在这里插入图片描述

1. 双向带头循环链表的结构

在这里插入图片描述
与单链表不同的是:

  • 双向链表有一个“哨兵位”作为单独的头节点
  • 每个节点都可以指向其前驱和后继节点
  • 链表是循环的

带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨的”
“哨兵位”存在的意义:遍历循环链表避免死循环。

typedef int ListDataType;
typedef struct List
{ListDataType data;struct List* prev;//指向前驱节点struct List* next;//指向后继节点
}List;

2. 相关操作

2.1 创建节点

在这里插入图片描述

  • 创建的每个节点应该自己成环
List* BuyNode(ListDataType x)
{List* newnode = (List*)malloc(sizeof(List));if (newnode == NULL){perror(malloc);return NULL;}newnode->data = x;newnode->next = newnode;newnode->prev = newnode;
}

创建哨兵位:

int main()
{//哨兵位List* head = BuyNode(-1);return 0;
}

2.2 尾插

在这里插入图片描述

void ListPushBack(List* phead, ListDataType x)
{assert(phead);List* newnode = BuyNode(x);newnode->next = phead;newnode->prev = phead->prev;//尾节点指向新节点phead->prev->next = newnode;phead->prev = newnode;
}

2.3 头插

在这里插入图片描述

void ListPushFront(List* phead, ListDataType x)
{assert(phead);List* newnode = BuyNode(x);newnode->next = phead->next;newnode->prev = phead;phead->next = newnode;//只有头节点时,就是头节点的prevphead->next->prev = newnode;
}

2.4 打印

由于是循环链表,所以循环停止的条件应该是:cur != head

void ListPrint(List* phead)
{assert(phead);List* cur = phead->next;while (cur != phead){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}

在这里插入图片描述

2.5 尾删

  • 不能没有节点
  • 尾节点的前驱节点指向头节点
  • 头节点指向尾节点的前驱节点
  • 释放尾节点
void ListPopBack(List* phead)
{assert(phead);//只有头节点assert(phead->next != phead);List* del = phead->prev;del->prev->next = phead;phead->prev = del->prev;free(del);
}

2.6 头删

  • 不能没有节点
  • 待删除节点的后继节点的prev指向头节点
  • 头节点指向待删除节点的后继节点
void ListPopFront(List* phead)
{assert(phead);assert(phead->next != phead);List* del = phead->next;del->next->prev = phead;phead->next = del->next;free(del);
}

2.7 查找

List* ListFind(List* phead, ListDataType x)
{assert(phead);assert(phead->next != phead);List* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

2.8 指定位置前/后插入

  • 将新节点与指定位置相连即可

指定位置前

void ListPosFrontInsert(List* pos, ListDataType x)
{assert(pos);List* newnode = BuyNode(x);List* prev = pos->prev;newnode->prev = prev;newnode->next = pos;prev->next = newnode;pos->prev = newnode;
}

指定位置后

void ListPosBackInsert(List* pos, ListDataType x)
{assert(pos);List* newnode = BuyNode(x);List* next = pos->next;newnode->next = next;newnode->prev = pos;next->prev = newnode;pos->next = newnode;
}

2.9 删除指定位置的节点

  • 将指定位置的前驱节点、后继节点连接即可
void ListPosDel(List* pos)
{assert(pos);List* prev = pos->prev;List* next = pos->next;prev->next = next;next->prev = prev;free(pos);pos = NULL;
}

2.10 删除指定位置后的节点

  • 若指定位置是尾节点,则应该执行头删
void ListPosAfterDel(List* phead, List* pos)
{assert(phead);assert(pos);if (pos->next == phead){ListPopFront(phead);}else{List* del = pos->next;del->next->prev = pos;pos->next = del->next;free(del);}
}

2.11 销毁链表

  • 此接口的参数是一级指针,所以并不能将哨兵位销毁;因此需要再调用处再将哨兵位置为空
void ListDestroy(List* phead)
{assert(phead);assert(phead->next != phead);List* cur = phead->next;while (cur != phead){List* next = cur->next;free(cur);cur = next;}cur = NULL;free(phead);phead = NULL;
}

在这里插入图片描述

3.顺序表与链表区别

不同点顺序表链表
存储空间上物理上一定连续逻辑上连续,物理上不一定连续
随机访问O(1)O(N)
任意位置插入或删除可能需要搬运元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够需要扩容没有容量的概念
应用场景元素高效存储,频繁访问任意位置频繁插入/删除
缓存利用率

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

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

相关文章

javaEE - 24( 20000 字 Servlet 入门 -2 )

一: Servlet API 详解 1.1 HttpServletResponse Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到HttpServletResponse 对象中. 然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过S…

JVS物联网、低代码、规则引擎2.5功能新增说明

物联网更新功能 新增: 1、新增离线存储-页面配置及指令下发对接; 用户可以对平台的页面进行自定义配置,通过平台,可以将指令下发给与之相连的设备或系统,这些指令可以是控制指令、配置指令或其他类型的指令。 2、新增数据压缩-…

diffusers单机多卡推理(全网首发)

起因 博主在部署InstantID项目时,显存不够,想要将模型分散在多张卡上。 翻到这篇发现是分布式推理,博主一直以为这个可以达到我想要的效果,但是效果是多线程并行推理,并不能将一个模型切片在多个GPU上。 Distributed …

Text2SQL研究-Chat2DB体验与剖析

文章目录 概要业务数据库配置Chat2DB安装设置原理剖析 小结 概要 近期笔者在做Text2SQL的研究,于是调研了下Chat2DB,基于车辆订单业务做了一些SQL生成验证,有了一点心得,和大家分享一下.: 业务数据库设置 基于车辆订…

Python(21)正则表达式中的“元字符”

大家好!我是码银🥰 欢迎关注🥰: CSDN:码银 公众号:码银学编程 获取资源:公众号回复“python资料” 在本篇文章中介绍的是正则表达式中一部分具有特殊意义的专用字符,也叫做“元…

一文学会Axios的使用

异步请求 同步发送请求过程如下 浏览器页面在发送请求给服务器,在服务器处理请求的过程中,浏览器页面不能做其他的操作。只能等到服务器响应结束后才能,浏览器页面才能继续做其他的操作。 异步发送请求过程如下浏览器页面发送请求给服务器&…

c语言实现io多路复用(select),进程,线程并发服务器

io多路复用&#xff08;select&#xff09;代码 #include<myhead.h> #include <sys/select.h> #define PORT 8888 #define IP "192.168.250.100" int main(int argc, char const *argv[]) { //创建套接字int sfd socket(AF_INET, SOCK_STREAM, 0…

小米电脑管家-非小米电脑安装教程

​​第一步&#xff1a;去浏览器搜索小米跨终端智联官网 下载小米电脑管家 如果是小米电脑&#xff0c;直接安装就行了 这里主要讲的是不是小米电脑&#xff0c;怎么去安装&#xff1f; 不是小米电脑就需要下载免检测机型插件&#xff0c;不然安装不了的 第二步&#xff1a;…

解决端口被占用问题

写文章原因: 本人在安装alist的时候,在使用5244端口的时候,显示端口被占用,于是想查看一下端口是被什么程序占用了,是否可以杀死占用的程序,还是更换端口. failed to start http: listen tcp 0.0.0.0:5244: bind: Only one usage of each socket address (protocol/network a…

幻兽帕鲁服务器搭建最简单新手教程,10秒钟自动部署,一键开服(腾讯云)

以下教程是基于腾讯云轻量应用服务器搭建的&#xff0c;非常简单&#xff0c;无论搭建幻兽帕鲁还是其他的游戏或者应用&#xff0c;都能以非常快的速度部署好。而且稳定流畅&#xff0c;功能丰富。 下面就来一起看看如何搭建吧。 幻兽帕鲁腾讯云服务器购买与一键部署教程&…

【Qt学习笔记】Qt Creator环境下 信号与槽 详解(自定义信号槽、断连、lambda表达式等)

文章目录 1. 信号槽概念1.1 信号的本质1.2 槽的本质1.3 标准信号槽1.4 信号槽 实例 2. 自定义信号槽2.1 自定义槽函数2.2 自定义信号2.3 带参 信号槽 3. 信号槽的意义 与 作用4. 信号槽断连 &#xff08;了解&#xff09;5. lamda表达式的使用5.1 基本用法5.2 捕获局部变量5.3 …

如何查看端口映射?

端口映射是一种用于实现远程访问的技术。通过将外网端口与内网设备的特定端口关联起来&#xff0c;可以使外部网络用户能够通过互联网访问内部网络中的设备和服务。在网络中使用端口映射可以解决远程连接需求&#xff0c;使用户能够远程访问设备或服务&#xff0c;无论是在同一…