第四章 带头双向链表的讲解与实现

news2024/11/29 22:42:29

初阶数据结构

第一章 时间复杂度和空间复杂度
第二章 动态顺序表的实现
第三章 单向链表的讲解与实现
第四章 带头双向链表的讲解与实现


文章目录

  • 初阶数据结构
  • 前言
  • 一、什么是头节点(哨兵位)
  • 二、双向链表结点的定义
  • 三、接口函数的实现
    • 1、初始化
    • 2、尾插
    • 3、头插
    • 4、尾删
    • 5、头删
    • 6、打印
    • 7、查找
    • 8、随机插入
    • 9、随机删除
    • 10、销毁


前言

上一章节中,我们学习了无头指针的单向链表的逻辑和代码实现,但是我们发现这种单向结构在使用的时候是存在很大的弊端的,比如说我们无法通过中间的某个节点直接找到他前一个节点,只能从头开始遍历。这是非常低效地一种方式。为了解决链表的单向性,我们本章节将介绍一个双向链表。
同时,由于上一章节中,我们的链表是不带头节点的,即没有哨兵位。因此,我们在实现接口函数的时候大概率要单独讨论链表为空的情况。那么本章节将介绍一种带头的链表,从而统一各种情况下的处理方式。
综上,我们就引出了我们今天的主题:带头双向链表


一、什么是头节点(哨兵位)

在这里插入图片描述
在上述的双向链表中,在第一个节点的前面多出了一个节点,这个节点的数据域是没有用处的。但是头节点的指针域具有很重要的作用,它的指向后方节点的指针域记录了第一个节点的地址。指向前方节点的指针域记录了最后一个节点的地址。
那么这样设置一个头节点有什么作用呢?
最大的作用就是让链表中的节点个数始终不为0,什么意思呢?我们看下方图示:
在这里插入图片描述
我们发现,即使链表为空,头节点依旧存在,其妙处将在下面实现接口函数的时候体现出来。

二、双向链表结点的定义

typedef int ElementType;
typedef struct DListNode
{
    struct DListNode* next;
    struct DlistNode* prev;
    ElementType data;
}DLTnode;

在这里插入图片描述

三、接口函数的实现

1、初始化

初始化,即开辟一个头节点,然后让这个头节点的前后指针域都指向自己。

DLTnode* DListInit()
{
    DLTnode* phead = (DLTnode*)malloc(sizeof(DLTnode));
    phead->next = phead;
    phead->prev = phead;
    return phead;
}

2、尾插

尾插的逻辑如下图所示:
在这里插入图片描述

void DListPushBack(DLTnode* phead, ElementType dat)
{
    assert(phead != NULL);
    DLTnode* newnode = (DLTnode*)malloc(sizeof(DLTnode));
    newnode->data = dat;
    DLTnode* tail = phead->prev;
    tail->next = newnode;
    newnode->prev = tail;
    newnode->next = phead;
    phead->prev = newnode;
}

我们发现上述代码并没有单独讨论空链表的情况,这就是头节点的好处,之所以不用讨论就是因为节点的个数不可能为0,最少也包括一个头节点。

3、头插

在这里插入图片描述

void DListPushFront(DLTnode* phead, ElementType dat)
{
    assert(phead != NULL);
    DLTnode* newnode = (DLTnode*)malloc(sizeof(DLTnode));
    newnode->data = dat;
    newnode->next = phead->next;
    phead->next->prev = newnode;
    phead->next = newnode;
    newnode->prev = phead;

}

4、尾删

在这里插入图片描述

void DListPopBack(DLTnode* phead)
{
    assert(phead != NULL);
    assert(phead->next!=phead);//防止删掉头节点
    DLTnode* tail = phead->prev;
    DLTnode*tailprev=tail->prev;
    tailprev->next = phead;
    phead->prev = tailprev;
    free(tail);
    tail = NULL;

}

5、头删

在这里插入图片描述

void DListPopFront(DLTnode* phead)
{
    assert(phead!=NULL);
    assert(phead->next!=phead);//防止删掉头节点
    DLTnode* First = phead->next;
    DLTnode* second = phead->next->next;
    phead->next = second;
    second->prev = phead;
    free(First);
    First = NULL;
}

6、打印

打印的逻辑非常简单,就是从头遍历一遍即可,但是需要注意的是,这是一个循环链表,如果我们不加限制条件的话,他会一直循环下去。所以,我们这里需要加上判断条件。

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

7、查找

逻辑同查找一致。

DLTnode* DListFind(DLTnode* phead, ElementType dat)
{
    assert(phead!=NULL);
    DLTnode* cur = phead->next;
    while (cur != phead)
    {
        if (cur->data == dat)
        {
            return cur;
        }
        else
        {
            cur = cur->next;
        }
    }
    return NULL;
}

8、随机插入

在这里插入图片描述

void DListInsert(DLTnode*pos,ElementType dat)
{
    DLTnode* newnode = (DLTnode*)malloc(sizeof(DLTnode));
    newnode->data = dat;
    DLTnode* posprev = pos->prev;
    posprev->next = newnode;
    newnode->prev = posprev;
    newnode->next = pos;
    pos->prev = newnode;
}

9、随机删除

在这里插入图片描述

void DListErase(DLTnode*pos)
{
    DLTnode*posprev = pos->prev;
    DLTnode* posnex = pos->next;
    posprev->next = posnex;
    posnex->prev = posprev;
    free(pos);
    pos = NULL;
}

10、销毁

销毁的逻辑和单链表一样,逐个遍历,逐个销毁,但是注意野指针问题!!

void DListDestory(DLTnode** pphead)
{
    DLTnode* cur = (*pphead)->next;
    while (cur != *pphead)
    {
        DLTnode* curnex = cur->next;
        free(cur);
        cur = curnex;
    }
    free(*pphead);
    *pphead = NULL;
    cur = NULL;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【附源码】计算机毕业设计java中国朝鲜族民族特色服务系统设计与实现

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

超全,看完这份微服务架构与实践文档,微服务不再难

前言: 微服务近年来受到了极大的关注并成为趋势,不信的话可以查看 Google Trends。 可以看到从2014年开始人们对它产生了极大的兴趣,随着时间的推移,这一趋势仍在增长。 随着数字化转型的推进,越来越多的企业开始尝…

IntelliJ IDEA禁止某些文件夹indexing

IntelliJ IDEA禁止某些文件夹indexing 文章目录IntelliJ IDEA禁止某些文件夹indexing问题描述方法一:标记文件夹为Exclude方法二:.iml文件中手动加入excludeFolder节点方法三:直接加入IDEA忽略文件和文件夹列表问题描述 IDEA启动后&#xff…

计算机毕业设计(附源码)python在线答题系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

MySQL数据库——日志管理、备份与恢复

一、数据备份的重要性 备份的主要目的是灾难恢复。 在生产环境中,数据的安全性至关重要。 任何数据的丢失都可能产生严重的后果。 造成数据丢失的原因: 程序错误人为操作错误运算错误磁盘故障灾难(如火灾、地震)和盗窃 二、数据…

【Tomcat】解决Tomcat服务器乱码问题

俩地方开展出现乱码的原因1、以startup.bat文件打开的服务器出现乱码2、在IDEA中运行Tomcat服务器出现乱码问题3、有关社区版IDEA如何开发JavaWeb项目出现乱码的原因 使用了错误的字符编码去解码字节流,所以出现乱码咱思维要清晰,就去找字符编码是否与其…

vue3.0微信活动推广分享项目-实现验证码登录功能

⭐️⭐️⭐️ 作者:船长在船上 🚩🚩🚩 主页:来访地址船长在船上的博客 🔨🔨🔨 简介:CSDN前端领域优质创作者,资深前端开发工程师,专注前端开发…

二、稀疏数组和队列

稀疏数组 1、基本介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以用稀疏数组来保存该数组。 2、处理方式 记录数组一共有几行几列,有多少个不同的值把具有不同值的元素的行列及值记录在一个小规模数组中,从而缩小…

【OpenCV】红绿灯检测C++Demo实现

很久以来一直想实现红绿灯检测,今天它来了。 文章目录原理代码实现打包程序为exe原理 OpenCV好强,能够提取红绿灯的轮廓,并根据颜色空间判断红绿,不依赖深度学习算法也能做到可用的效果/demo。 红绿灯检测的基本步骤如下&#x…

20221103使用ffmpeg提取mp4视频的字幕

20221103使用ffmpeg提取mp4视频的字幕 2022/11/3 12:19 百度搜索: MP4 内置字幕 提取 https://www.6yxk.com/ruanjianjiaocheng/224526.html 提取mp4格式视频字幕的方法(工具) ffmpeg -i D:\temp\001.mp4 -map 0:s:0 sub1.srt 百度搜索: ffmp…

web前端面试题附答案044 - vue获取param参数,有什么缺点吗?

看这个vue的图标像不像小时候看的《魔神坛斗士》身上的某个元素。真希望成年人的世界就像小时候一样简单快乐。 今天这道面试题主要围绕vue中获取param参数展开,看完本文你可以吸取到以下知识点 ◇ 首先是最基本的2中获取方式 ◇ 如果不用vue应该怎么获取&#xff…

Linux查看性能相关命令

#Linux查看性能相关命令 ##CPU性能 ###/cat/proc/cpuinfo 这个文件能够获取到物理cpu的数量,每个物理cpu的核心数,是否开启超线程等信息 物理cpu: 表示主板上实际存在的cpu数量 cpu核数: 单个cpu上可以处理数据的芯片组数量,如双核,四核等 逻辑cpu数量: 一般来说,…

数据链路层 随机接入-CSMA/CA协议

媒体接入控制-动态接入控制-随机接入 CSMA/CA协议 载波监听多址接入/碰撞避免CSMA/CA 既然CSMA/CA协议已经成功的应用于使用广播信道的有限局域网,那么同样使用广播信道的无线局域网能不能也使用CSMA/CD协议呢? 在无线局域网中,仍然可以使…

httpClient同步、异步性能对比

0、测试目的 同步阻塞模式下,如果服务端接口响应较慢,那会直接影响客户端接口请求的吞吐量,虽然可以通过在应用代码中通过异步线程的方式优化,但是会增加客户端的线程开销。所以考虑用异步模式来解决这个问题 因此测试时&#x…

【网络篇】如何给虚拟机添加网卡,设置固定ip

引言 基于Centos7,准备两台虚拟机作为rac服务器。 以Oracle rac集群的配置说明。 网络分配 根据子网地址,我们给虚拟机分配如下ip: 名称公网私网网关rac1192.168.189.10192.168.83.10192.168.189.2rac2192.168.189.11192.168.83.11192.168.189.2 说明…

从零到一手写迷你版Vue

Vue响应式设计思路 Vue响应式主要包含: 数据响应式监听数据变化,并在视图中更新Vue2使用Object.defineProperty实现数据劫持Vu3使用Proxy实现数据劫持模板引擎提供描述视图的模板语法插值表达式{{}}指令 v-bind, v-on, v-model, v-for,v-if渲染将模板转…

高性能服务器之Reactor设计

今天来针对上一节课讲的多路转接知识再进一步进行设计,Reactor是基于epoll的ET模式设计的,在现在的高校和企业中是广泛应用的,今天我们来实现一个简洁版,完整版博主可没那个实力~ 目录 基本原理 代码实现 epoll_server.cc A…

当面试官让我回答React和Vue框架的区别......

我们为什么需要错误边界 在React组件中可能会由于某些JavaScript错误,导致一些无法追踪的错误,导致应用崩溃。部分 UI 的 JavaScript 错误不应该导致整个应用崩溃。为此,React引入了错误边界(Error Boundary)的概念:可以捕获发生…

MySQL搭建主从复制流程及相关问题

目录一、关于主从复制1.1 关于主从复制1.2 应用场景1.3 优缺点1.4 原理二、配置主从复制2.1 同步各个服务器的时间2.2 修改主库(M1)配置2.3 主库(M1)为从库(S1\S2)增加账号2.3 查看主库(M1&…

欢迎女神科学家颜宁回国,并祝她如愿以偿

目录1、女神科学家颜宁是谁2、颜宁在深圳人才论坛最新演讲,以及招聘邮箱3、颜宁微博回应4、结论与展望最近女神科学家颜宁回国了,整个科学界和中国都沸腾了,也上了热搜,成了热门话题,越来越多的海归精英选择回国 1、…