双向循环链表

简介: 双向循环链表

什么是双向循环链表

双向:即该节点即可以指向前一个节点,又可以指向下一个节点。

循环:节点的头指向尾,节点的尾指向头。

类型的创建

为什么要把int类型的数据进行重新命名。是为了以后修改数据类型的方便。

该结构体类型包括前驱指针,后驱指针以及数据。

typedef int ListTypeDate;

typedef struct ListNode
{
  struct ListNode* prev;
  struct ListNode* next;
  ListTypeDate val;
}LNode;

创建双向循环链表的头节点(初始化)

初始化也就是给这个链表弄了一个头,该头的前驱指针和后驱指针都指向它自己。里面的值不管是多少都是一个随机的值。

LNode* BuyNewNode(ListTypeDate x)
{
  LNode* newnode = (LNode*)malloc(sizeof(LNode));
  newnode->val = x;
  return newnode;
}

LNode* InitList()
{
  LNode* head = BuyNewNode(-1);
  head->prev = head;
  head->next = head;
  return head;
}

该初始化的接口返回的是头节点的地址。

打印出链表里面的数据

因为是循环的,所以从链表头节点的下一个节点开始遍历打印,终止的打印的条件是遇到头节点。

void PrintList(LNode* head)
{
  LNode* cur = head->next;
  while (cur != head)
  {
    printf("%d ", cur->val);
    cur = cur->next;
  }
  printf("\n");
}

首插,尾插,首删,尾删

首插

void ListPushFront(LNode* head, ListTypeDate x)
{
  assert(head);
  LNode* newnode = BuyNewNode(x);
  LNode* cur = head->next;

  head->next = newnode;
  newnode->prev = head;
  newnode->next = cur;
  cur->prev = newnode;
}

尾插

链表的尾就是头节点的前驱指针指向的节点。

void ListPushBack(LNode* head, ListTypeDate x)
{
  LNode* newnode = BuyNewNode(x);
  LNode* tail = head->prev;

  head->prev = newnode;
  newnode->next = head;
  tail->next = newnode;
  newnode->prev = tail;
}

首删

当链表中没有节点的时候不能进行删除

void ListPopFront(LNode* head)
{
  assert(head);
  //链表没有节点的时候不能进行删除
  assert(head->next != head);

  LNode* cur = head->next;
  LNode* curnext = cur->next;

  head->next = curnext;
  curnext->prev = head;

  free(cur);
}

尾删

void ListPopBack(LNode* head)
{
  assert(head);
  //链表没有节点的时候不能进行删除
  assert(head->next != head);

  LNode* tail = head->prev;
  LNode* tailprev = tail->prev;

  head->prev = tailprev;
  tailprev->next = head;

  free(tail);
}

pos位置前插入,pos位置删除

pos位置前插入

void ListInsert(LNode* head, LNode* pos, ListTypeDate x)
{
  assert(head);
  LNode* newnode = BuyNewNode(x);
  LNode* posprev = pos->prev;
  posprev->next = newnode;
  newnode->prev = posprev;
  newnode->next = pos;
  pos->prev = newnode;
}

pos位置删除

void ListErase(LNode* head, LNode* pos)
{
  assert(head);
  assert(head->next != head);
  LNode* posnext = pos->next;
  LNode* posprev = pos->prev;

  posprev->next = posnext;
  posnext->prev = posprev;
  free(pos);
}

利用这两个接口实现,首尾插,删。

void ListPushFront(LNode* head, ListTypeDate x)
{
  ListInsert(head,head->next, x);
}

void ListPushBack(LNode* head, ListTypeDate x)
{
  ListInsert(head,head, x);
}

void ListPopFront(LNode* head)
{
  ListErase(head,head->next);
}

void ListPopBack(LNode* head)
{
  ListErase(head,head->prev);
}

销毁链表

void ListDestroy(LNode* head)
{
  while (head!=head->next)
  {
    ListPopBack(head);
  }
  free(head);
}
相关文章
|
算法 测试技术 开发工具
编写高效技术文档的艺术:C++项目实践指南
编写高效技术文档的艺术:C++项目实践指南
292 0
|
算法 Shell 计算机视觉
【特效】对实时动态人脸进行马赛克及贴图马赛克处理及一些拓展
【特效】对实时动态人脸进行马赛克及贴图马赛克处理及一些拓展
393 0
|
SQL 自然语言处理 数据挖掘
大模型与数据分析:探索Text-to-SQL(中)
大模型与数据分析:探索Text-to-SQL(中)
1834 0
|
6月前
|
人工智能 IDE Java
寻找通义灵码 AI 程序员 {头号玩家} ,体验 QwQ-Plus、DeepSeek 满血版的通义灵码
通义灵码联合 CHERRY 中国全网发起寻找 AI 程序员 {头号玩家},体验全新模型加持下的 AI 程序员的智能编码新功能,体验图生代码 Agent、单元测试 Agent 、跨语言编程等 AI 程序员能力,赢取通义灵码 X CHERRY 联名定制个人签名款机械键盘 、CHERRY MX8.3 旗舰级机械键盘、CHERRY 无线双模鼠标、码力全开蛇皮袋等奖品!
|
6月前
|
存储 算法 C++
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
321 73
|
11月前
|
机器学习/深度学习 自然语言处理 语音技术
使用Python实现深度学习模型:智能产品设计与开发
【10月更文挑战第2天】 使用Python实现深度学习模型:智能产品设计与开发
213 4
|
IDE Java 开发工具
如何在Windows操作系统上安装PyCharm?
【7月更文挑战第5天】如何在Windows操作系统上安装PyCharm?
398 59
|
12月前
|
缓存 监控
如何解决协商缓存中资源更新不及时的问题?
如何解决协商缓存中资源更新不及时的问题?
|
数据采集 自然语言处理 数据可视化
基于python数据挖掘在淘宝评价方面的应用与分析,技术包括kmeans聚类及情感分析、LDA主题分析
本文探讨了基于Python数据挖掘技术在淘宝评价分析中的应用,涵盖了数据采集、清洗、预处理、评论词频分析、情感分析、聚类分析以及LDA主题建模和可视化,旨在揭示淘宝客户评价中的潜在模式和情感倾向,为商家和消费者提供决策支持。
352 0
|
开发工具 git
【分支管理】远程分支删除后在本地还能看到的解决办法
【分支管理】远程分支删除后在本地还能看到的解决办法