文章目录

  • 一、前言
  • 二、双向链表的实现
    • ①、定义节点
    • ②、创建新节点(BuyLTNode)
    • ③、初始化链表(ListInit)
    • ④、双向链表销毁(ListDestory)
    • ⑤、双向链表打印(ListPrint)
    • ⑥、双向链表尾插(ListPushBack)
    • ⑦、双向链表头插(ListPushFront)
    • ⑧、双链表尾删(ListPopBack)
    • ⑨、双链表头删(ListPopFront)
    • ⑩、双向链表pos位置之前插入(ListInsert)
    • ⑪、双向链表删除pos位置(ListEarse)
    • ⑫、双向链表查找(ListFind)
  • 三、总结

一、前言

链表是数据结构中十分重要的内容,我们知道链表的结构是非常多样的

当所有情况组合起来就有8种链表结构:

1.单向或者双向:

2.带头或者不带头:

3.循环或者非循环:

4.最常用的两种结构:

今天我们就来介绍优势更为明显的带头双向循环链表

在介绍带头双向循环链表之前呢,我们需要先来简单了解一下无头单向非循环链表,从图中我们也可以看出来,该结构较为简单。所以我们一般不会用其单独来存储数据。在实际应用中我们更多的是将其作为其他数据结构的子结构,如哈希桶、图的邻接表等等。在这里多提一句,这种结构在笔试面试中出现的概率是比较高的。

而我们今天要着重讲解的带头双向循环链表,它的结构相对来说是比较复杂的,一般用来单独存储数据。在实际使用链表数据结构,都是带头双向循环链表。虽然这个结构的结构较为复杂,但是在我们真正使用起来的时候,我们会发现它给我们带来了许多优势,反而实现起来更加简单了,这在后文讲解中会有所体现。

二、双向链表的实现

NOTE:老规矩,在这里我们先把所需要用的的库给到大家:

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>

①、定义节点

首先和单向链表一样,我们需要先定义一个节点,大致的实现都是相同的,但由于双向的结构,我们需要额外新增一个新的指针,因为我们需要一个指针指向前面一个指针指向后面,节点的定义具体如下:

typedef int LTDataType;
typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;

②、创建新节点(BuyLTNode)

LTNode* BuyListNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail!");exit(-1);}node->next = NULL;node->prev = NULL;node->data = x;return node;
}

③、初始化链表(ListInit)

LTNode* ListInit()
{LTNode* guard = (LTNode*)malloc(sizeof(LTNode));if (guard == NULL){perror("malloc fail!");exit(-1);}guard->next = guard;guard->prev = guard;return guard;
}

④、双向链表销毁(ListDestory)

void ListDestory(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);
}

⑤、双向链表打印(ListPrint)

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

⑥、双向链表尾插(ListPushBack)

void ListPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;
}

⑦、双向链表头插(ListPushFront)

void ListPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);newnode->next = phead->next;phead->next->prev = newnode;phead->next = newnode;newnode->prev = phead;
}

⑧、双链表尾删(ListPopBack)

void ListPopBack(LTNode* phead)
{assert(phead);assert(!ListEmpty(phead));LTNode* tail = phead->prev;LTNode* prev = tail->prev;prev->next = phead;phead->prev = prev;free(tail);tail = NULL;
}

⑨、双链表头删(ListPopFront)

void ListPopFront(LTNode* phead)
{assert(phead);assert(!ListEmpty(phead));LTNode* first = phead->prev;LTNode* second = first->next;phead->next = second;second->prev = phead;free(first);first = NULL;
}

⑩、双向链表pos位置之前插入(ListInsert)

void ListInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* prev = pos->prev;LTNode* newnode = BuyListNode(x);prev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}

⑪、双向链表删除pos位置(ListEarse)

void ListErase(LTNode* pos)
{assert(pos);LTNode* prev = pos->prev;LTNode* next = pos->next;prev->next = next;next->prev = prev;free(pos);
}

⑫、双向链表查找(ListFind)

LTNode* ListFind(LTNode* phead, LTDataType x)
{assert(phead);size_t n = 0;LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

三、总结

带头双向循环链表是一种较为复杂的就够,但由于其具有的循环特性,会使我们通过代码实现它时反而更为简单,双向链表这个结构的应用场景我们会在下一篇博客里通过oj题目为大家介绍,感谢大家的支持!

玩转数据结构之双向循环链表相关推荐

  1. 数据结构-带头双向循环链表(增删查改详解)

    在上一篇博客中,详细介绍了单链表的增删查改,虽然单链表的结构简单,但是用起来却不是那么顺手.因此根据单链表的种种缺点,这篇博客所介绍的带头双向循环链表将会带来极大的优化. 上图就是带头双向循环链表的主 ...

  2. 双向循环链表:字母表实现前后移动

    问题描述 要求实现用户输入一个数使得26个字母的排列发生变化,例如用户输入3,使得结果为:DEFHIJKLMNOPQRSTUVWXYZABC, 同时需要支持负数,使得输入-3时,结果为:XYZABCD ...

  3. 双向循环链表:鸿蒙轻内核中数据的“驿站”

    本文分享自华为云社区<鸿蒙轻内核M核源码分析系列二 数据结构-双向循环链表>,原文作者:zhushy . 在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用. ...

  4. 数据结构 -- 双向循环链表

    这篇文章写的是双向循环链表,这也是个非常经典的数据结构,我们在看 Linux 内核代码时就经常会遇到它.比如,在Linux的内核中实现进程描述符,使用的就是双向循环链表,因为它使用起来很方便,每个节点 ...

  5. 数据结构与算法 | 带头双向循环链表

    上一节里实现的是最简单的链表,在实际中那种链表不会单独用来存储数据,更多是作为其他数据结构的子结构,如图的邻接表等.而比较常用的就是带头双向循环链表. 通过对比我们可以看出有三个不同,多了头节点,链表 ...

  6. 数据结构-线性表之带头结点的双向循环链表

    文章目录 前言 实现 (1)结构定义 (2)基本函数 (3)操作实现 测试 代码 前言 链表的类型有很多种(根据带头或不带头,循环或非循环等等),但是我们重点研究的只有两种,一种结构非常简单是无头单向 ...

  7. 《恋上数据结构第1季》单向循环链表、双向循环链表以及约瑟夫环问题

    循环链表(CircleList) 链表的接口设计 单向循环链表 单向循环链表完整源码 双向循环链表 双向循环链表完整源码 双向循环链表解决约瑟夫环问题 如何发挥循环链表的最大威力? 静态链表 数据结构 ...

  8. 比特数据结构与算法(第二章收尾)带头双向循环链表的实现

    1.链表的分类 链表的分类 ① 单向或者双向 ② 带头或者不带头 ③ 循环或者非循环 常用的链表: 根据上面的分类我们可以细分出8种不同类型的链表,这么多链表我们一个个讲解这并没有意义.我们实际中最常 ...

  9. 【数据结构】链表:带头双向循环链表的增删查改

    本篇要分享的内容是带头双向链表,以下为本片目录 目录 一.链表的所有结构 二.带头双向链表 2.1尾部插入 2.2哨兵位的初始化 2.3头部插入 2.4 打印链表 2.5尾部删除 2.6头部删除 2. ...

最新文章

  1. android systemtrace 报错
  2. form表单获取input对象浏览器区别
  3. SimpleExecutor.doQuery()-ResultSetHandler 处理结果集
  4. 聚集云原生,可观测性的实践与探索 | 线下技术沙龙
  5. android音乐播放器音乐加载,Android开源音乐播放器之在线音乐列表自动加载更多...
  6. 【转】Win10系统创建WiFi热点的两种方法
  7. 计算机一级举报单位,2018年9月计算机一级Photoshop考试巩固练习题(三)
  8. PyTorch的hook及其在Grad-CAM中的应用
  9. 24个整点报时_大连交通广播整点报时广告怎么做?大连交通广播全新广告价格...
  10. 当vue遇到pwa--vue+pwa移动端适配解决方案模板案例
  11. UVa11137 - Ingenuous Cubrency
  12. SpringMVCfrom:form表单标签和input表单标签简介
  13. 数独问题(java)
  14. CISCO路由器命令大全
  15. google的视频下载插件
  16. python可以ps吗_python-PS图片
  17. 软件定义闪存: SSD加速企业数据中心变革
  18. 迅雷在下载网页视频时没有自动弹出提示,怎么办?
  19. C51汇编语言寻址方式,80C51单片机指令系统的7种寻址方式
  20. 【SVN】SVN是什么?怎么使用?

热门文章

  1. win7下安装netmeeting
  2. sinx/x在0到无穷的积分
  3. 自助建站系统有什么好处?
  4. 谷歌地球下载 Outline密钥生成 问题备忘录
  5. 公众号接入 OpenAI 智能机器人
  6. DHCPv6原理与配置
  7. 欧姆龙机器视觉软件系统fh fz fj仿真软件CCD
  8. wav音频文件实例详细解析
  9. 【直流传动与控制系统】闭环调速CDIO课程设计
  10. php开发微信demo