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

1.数据结构-双链表

一.双链表与单链表的对比:


二.双链表的初始化(带头结点):

1.图解:

2.代码演示:

#include<stdio.h>
#include<stdlib.h>
​
//定义双链表结构体
typedef struct DNode
{
    int data;
    struct DNode *prior;//前驱指针即指向前面数据的指针 
    struct DNode *next;//后继指针即指向后面数据的指针 
}DNode,*DLinklist; //DLinklist与DNode *等价,DLinklist强调链表,DNode *强调结点 
​
//初始化双链表
bool InitDLinkList(DLinklist &L)
{
    L = (DNode *)malloc( sizeof(DNode) );//分配一个头结点
    if( L==NULL ) //内存不足,分配失败 
    {
        return false;
    } 
    L->prior = NULL;//头结点的prior(前驱)永远指向NULL
    L->next = NULL;//头结点之后(后继)暂时还没有结点 
    return true;
} 
​
//判断双链表是否为空(带头结点)->只需要看第一个结点是否为空即可 
bool Empty(DLinklist L)
{
    if( L->next == NULL )//代表双链表第一个结点为空,是空双链表
    {
        return true;
    }
    else
    {
        return false;//代表双链表第一个结点不为空,不是空双链表 
    }
} 
​
int main()
{
    //初始化双链表 
    DLinklist L;
    InitDLinkList(L);
    //后续代码。。。 
    return 0;
}

三.双链表的插入:

图解:

此时要p结点之后插入s结点,起初p->next指向y,先把p的下一个结点即y和要插入的结点即s的指向下一个结点的指针对接即s->next = p->next:

之后还需要把p结点的后继结点即p->next的前向指针p->next->prior指向s即p->next->prior = s:

再把要插入的结点即s结点的前驱指针指向p结点即 s->prior = p:

最后把p结点的后继结点指向s即p->next = s:

但对于上述代码,有一个bug,当p结点是最后一个结点时,p->next->prior = s就会报空指针的错,因为

p结点是最后一个结点时p->next指向NULL,因此,严谨的代码如下:对p->next进行空指针判断

  • 按位序插入:找到要插入的位序的前驱结点,在该结点实现后插操作即可

  • 前插操作:由于双链表的特性,可以很方便的找到给定结点的前驱结点,再对前驱结点进行后插操作即可


四.双链表的删除:

图解:

此时要删除p结点的后继结点q,因此要把q结点的下一个结点和p结点连接,即p->next = q->next:

再把要删除的q结点的后继结点即q->next的前驱结点即q->next->prior指向p即q->next->prior = p:

最后再释放要删除的q结点即free(q):free函数要用到头文件#include<stdlib.h>

但上述代码也有bug,如果此时要删除的q结点为双链表最后一个结点,那么q->next就指向NULL,q->next->prior就会报空指针错误,因此对q->next进行空指针判断以增加严谨性:

销毁双链表:每一次删除头结点的后继结点即可

因为比如第一次删除头结点的后继结点即第一个结点,第二次删除时第二个结点就来了第一个位置,相当于头结点的后继结点,删除即可,以此类推,可销毁双链表:


五.双链表的遍历:

1.对于前向遍历(跳过头结点)的循环条件当p->prior == NULL时,说明此时p结点指向的就已经是头结点了,此时跳出循

环,不操作头结点了;

2.对于按位查找,只需要添加一个计数器,用于记录此时指向的哪个位置的元素,当位置和要找的位置匹配时打印即可;

3.对于按值查找,只需要对当前指向的结点和要找的值对比即可,找到了就打印即可;

4.双链表没有随机存取的特性,所以按位查找,按值查找的时间复杂度为O(n),因为只能用循环的方式一个一个对比依次

往后找。


六.总结:



http://www.kler.cn/news/308736.html

相关文章:

  • YOLOv8改进 - 注意力篇 - 引入CBAM注意力机制
  • TCP.IP四层模型
  • Redis命令:redis-cli
  • 【乐企】基础请求封装
  • 【基于C++的产品入库管理系统】
  • Java项目实战II基于Java+Spring Boot+MySQL的图书管理系统的设计与实现 (源码+数据库+文档)
  • 关于yolov5遇到空标签导致训练暂停的解决
  • C++基于select和epoll的TCP服务器
  • 计算机毕业设计 毕业季一站式旅游服务定制平台的设计与实现 Java实战项目 附源码+文档+视频讲解
  • sshj使用代理连接服务器
  • as 类型断言
  • 动手学深度学习(四)卷积神经网络-下
  • 飞书项目管理使用攻略
  • MySQL基于GTID同步模式搭建主从复制
  • Spring Boot-API版本控制问题
  • 【Linux修行路】信号的产生
  • AI与自然语言处理(NLP):中秋诗词生成
  • ffmpeg硬件解码一般流程
  • 关于RabbitMQ重复消费的解决方案
  • 大数据新视界 --大数据大厂之数据挖掘入门:用 R 语言开启数据宝藏的探索之旅
  • 图数据库的力量:深入理解与应用 Neo4j
  • Vue2知识点
  • makefile 的语法(7):函数 word wordlist words firstword lastword ;
  • SurrealDB:现代应用的端到端云原生数据库解决方案
  • Golang | Leetcode Golang题解之第401题二进制手表
  • 【图像拼接】基于SIFT/SURF特征算法的图像拼接,matlab实现
  • 【重学 MySQL】三十三、流程控制函数
  • 探索未来游戏边界:AI驱动的开放世界RPG引擎与UGC平台
  • 【每日一题】LeetCode 2332.坐上公交的最晚时间(数组、双指针、二分查找、排序)
  • 大数据新视界 --大数据大厂之Kafka消息队列实战:实现高吞吐量数据传输