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

双向链表+循环链表

循环链表+双向链表

循环链表

循环链表是头尾相接的链表(即表中最后一个结点的指针域指向头结点,整个链表形成一个)(circular linked list)

img

**优点:**从表中任一结点出发均可访问全部结点

循环链表与单链表的主要差别当链表遍历时,判别当前指针p是否指向表尾结点的终止条件不同。在单链表中,判别条件为p!=NULL或p->next=NULL,而循环单链表的判别条件为p!=L或p->next!=L

img

img

img

img

#include<stdio.h>
#include<stdlib.h>typedef struct Lnode {int data;struct Lnode* next;
}Lnode,*LinkList;/*初始化循环单链表*/
Lnode* InitList(LinkList L)
{L = (Lnode*)malloc(sizeof(Lnode));if (L == NULL){//提示分配失败}L->next = L;
}//判断循环单链表是否为空 (终止条件为p或p->next是否等于头指针)
int Isempty(LinkList L)
{if (L->next == L){return 1;}else {return -1;}
}//判断结点p是否为循环单链表的表尾结点
int isTail(LinkList L, Lnode* p)
{if (p->next == L){return 1;}else {return -1;}
}

单链表和循环单链表的比较:
**单链表:**从一个结点出发只能找到该结点后续的各个结点;对链表的操作大多都在头部或者尾部;设立头指针,从头结点找到尾部的时间复杂度=O(n),即对表尾进行操作需要O(n)的时间复杂度;
**循环单链表:**从一个结点出发,可以找到其他任何一个结点;设立尾指针,从尾部找到头部的时间复杂度为O(1),即对表头和表尾进行操作都只需要O(1)的时间复杂度;

双向链表

img

为了克服单链表的这一缺点,老科学家们设计了双向链表(double linked list)是在单链表的每个结点中再设计一个指向其前驱结点的指针域。所以在双向链表中的结点有两个指针域,一个指向直接后继,另一个指向直接前驱。这样链表中有两个不同方向的链。img

img

img

与单循环链表类似双向链表也可以有循环表(首尾相接形成"环"[2个])

让头结点的前驱指针指向链表的最后一个结点

最后一个结点的后继指针指向头结点

img

双向链表结构有对称性(设指针p指向某一个结点)

p->prior->next=p=p->next->prior(前进一步后退一步相当于原地踏步)

在双向链表中有些操作(ListLength,GetElemment等因为只涉及一个方向的指针他们的算法与线性表的相同)但在插入和删除需要修改两个方向上的指针两者的算法复杂度均为O(n)

双向链表的插入

img

img

单链表只需修改两个指针,而双向链表修改四个指针

算法复杂度O(n)img

img

总结

image-20230303213156515

链式存储结构的优点:

  • 结点空间可以动态申请和释放;

  • 数据元素的逻辑次序靠结点的指针来指示,插入和删除不需要移动元素。

链式存储结构的缺点:

  • 存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占的字节数不多时,指针域所占的存储空间的比重显得很大。

  • 存储密度是指结点数据本身占用的空间**/结点占用的空间总量**

img

链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链查找到该结点,这增加了算法的复杂度。(对某个结点操作一般要先找到该结点)

img

代码总结

双向链表

#include<stdio.h>
#include<stdlib.h>typedef struct Lnode {int data;                       //数据域struct Lnode* prior, * next;    //前驱和后继指针
}DLnode,*DLinkList;DLnode* InitDLinkList(DLinkList L)
{L = (DLnode*)malloc(sizeof(DLnode));if (L == NULL){return -1;     //分配失败}else{L->prior = NULL;    //头指针的前驱指针永远指向NULLL->next = NULL;     }return L;
}void InsertNextDLnode(DLnode* p, DLnode* s) { //将结点 *s 插入到结点 *p之后if (p == NULL || s == NULL) //非法参数return;s->next = p->next;if (p->next != NULL)   //p不是最后一个结点=p有后继结点  p->next->prior = s;s->prior = p;p->next = s;return;
}
/*
按位序插入操作:
思路:从头结点开始,找到某个位序的前驱结点,对该前驱结点执行后插操作;
前插操作:
思路:找到给定结点的前驱结点,再对该前驱结点执行后插操作;*//*删除*/
/*删除p结点的后继结点*/
void DeleteDLnode_next(DLnode* p)
{if (p == NULL) {return;}DLnode* q = p->next;    //找到p的后继结点if (q == NULL) {return;}p->next = q->next;if (q->next != NULL)  //q不是最后一个结点{q->next->prior = p;}free(q);
}/*销毁一个双向链表*/
void DestotyDLinkList(DLinkList L)
{//循环释放各个数据结点while (L->next != NULL){DeleteDLnode_next(L);  //删除头结点的后继节点free(L);   //释放头结点L = NULL;}
}/*双链表的遍历操作——前向遍历*/
while (p != NULL)
{//对接点p做相应处理,并打印p = p->prior;
}/*双链表的遍历操作——后向遍历*/
while (p != NULL) {//对结点p做相应处理,eg打印p = p->next;
}

双向循环链表

#include<stdio.h>
#include<stdlib.h>typedef struct Lnode {int data;                       //数据域struct Lnode* prior, * next;    //前驱和后继指针
}DLnode, * DLinkList;/*初始化空的循环双向链表*/
void InitDLinkList(DLinkList L)
{L=(DLnode*)malloc(sizeof(DLnode));if (L == NULL){//提示空间不足,分配失败return;}L->prior = L;    //头结点的前驱&后继指针都指向头结点L->next = L;
}//判断循环双向链表是否为空
int IsEmpty(DLinkList L)
{if (L->next == L){return 1;}else return -1;
}//判断p结点是否为循环双向链表的表尾结点
int IsTail(DLinkList L, DLnode* p) {if (p->next == L){return 1;}else return -1;
}//双向循环链表的插入
void InsertNextDLnode(DLnode* p, DLnode* s)
{s->next = p->next;p->next->prior = s;s->prior = p;p->next = s;
}//双向链表的删除操作
void DeleteDLnode(DLnode* p)
{if (p == NULL) {return;}DLnode* q = p->next;    //找到p的后继结点if (q == NULL) {return;}p->next = q->next;if (q->next != NULL)  //q不是最后一个结点{q->next->prior = p;}free(q);
}
http://www.lryc.cn/news/27329.html

相关文章:

  • Java程序的逻辑控制
  • BUCTOJ - 2023上半年ACM蓝桥杯每周训练题-1-A~K题C++Python双语版
  • 存储的本质-学习笔记
  • 新一代骨传导机皇重磅发布:南卡Neo骨传导运动耳机,性能全面提升
  • Hbase Schema设计与数据模型操作
  • 微电影广告有哪些传播优势?
  • html基础(列表(ul、ol、dl)、表格table、表单(input、button、label)、div和span、空格nbsp)
  • uniapp常用标签
  • 《数字中国建设整体布局规划》发布,推进IPv6部署和应用是重点
  • 【Java】 异步调用实践
  • 园区智慧能源管理系统
  • 基于卷积神经网络CNN的分类研究,基于卷积神经网络的手写体识别
  • mybatis的增删改查运用
  • centos8安装docker运行java文件
  • Docker容器化部署.net core API
  • springcloud 服务调用feign、熔断hystrix、网关gateway
  • 《C++ Primer》 第十二章 动态内存
  • 多个关键字用or、and、包含、不包含动态拼接为正则表达式和SQL查询条件
  • 初始Linux操作系统
  • 【算法数据结构体系篇class12、13】:二叉树
  • 数字IC手撕代码--联发科(总线访问仲裁)
  • 白盒测试复习重点
  • 学习C++这几个网站足矣
  • 第十四届蓝桥杯模拟赛(第三期)——C语言版
  • Flutter Button 实例
  • 好玩的docker项目,盒子刷的海思nas,挂载外接硬盘。qb种子
  • RabbitMQ的使用
  • Selenium如何隐藏浏览器页面?
  • 基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离
  • Acwing---843. n-皇后问题