玩转数据结构之双向循环链表
文章目录
- 一、前言
- 二、双向链表的实现
- ①、定义节点
- ②、创建新节点(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题目为大家介绍,感谢大家的支持!
玩转数据结构之双向循环链表相关推荐
- 数据结构-带头双向循环链表(增删查改详解)
在上一篇博客中,详细介绍了单链表的增删查改,虽然单链表的结构简单,但是用起来却不是那么顺手.因此根据单链表的种种缺点,这篇博客所介绍的带头双向循环链表将会带来极大的优化. 上图就是带头双向循环链表的主 ...
- 双向循环链表:字母表实现前后移动
问题描述 要求实现用户输入一个数使得26个字母的排列发生变化,例如用户输入3,使得结果为:DEFHIJKLMNOPQRSTUVWXYZABC, 同时需要支持负数,使得输入-3时,结果为:XYZABCD ...
- 双向循环链表:鸿蒙轻内核中数据的“驿站”
本文分享自华为云社区<鸿蒙轻内核M核源码分析系列二 数据结构-双向循环链表>,原文作者:zhushy . 在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用. ...
- 数据结构 -- 双向循环链表
这篇文章写的是双向循环链表,这也是个非常经典的数据结构,我们在看 Linux 内核代码时就经常会遇到它.比如,在Linux的内核中实现进程描述符,使用的就是双向循环链表,因为它使用起来很方便,每个节点 ...
- 数据结构与算法 | 带头双向循环链表
上一节里实现的是最简单的链表,在实际中那种链表不会单独用来存储数据,更多是作为其他数据结构的子结构,如图的邻接表等.而比较常用的就是带头双向循环链表. 通过对比我们可以看出有三个不同,多了头节点,链表 ...
- 数据结构-线性表之带头结点的双向循环链表
文章目录 前言 实现 (1)结构定义 (2)基本函数 (3)操作实现 测试 代码 前言 链表的类型有很多种(根据带头或不带头,循环或非循环等等),但是我们重点研究的只有两种,一种结构非常简单是无头单向 ...
- 《恋上数据结构第1季》单向循环链表、双向循环链表以及约瑟夫环问题
循环链表(CircleList) 链表的接口设计 单向循环链表 单向循环链表完整源码 双向循环链表 双向循环链表完整源码 双向循环链表解决约瑟夫环问题 如何发挥循环链表的最大威力? 静态链表 数据结构 ...
- 比特数据结构与算法(第二章收尾)带头双向循环链表的实现
1.链表的分类 链表的分类 ① 单向或者双向 ② 带头或者不带头 ③ 循环或者非循环 常用的链表: 根据上面的分类我们可以细分出8种不同类型的链表,这么多链表我们一个个讲解这并没有意义.我们实际中最常 ...
- 【数据结构】链表:带头双向循环链表的增删查改
本篇要分享的内容是带头双向链表,以下为本片目录 目录 一.链表的所有结构 二.带头双向链表 2.1尾部插入 2.2哨兵位的初始化 2.3头部插入 2.4 打印链表 2.5尾部删除 2.6头部删除 2. ...
最新文章
- android systemtrace 报错
- form表单获取input对象浏览器区别
- SimpleExecutor.doQuery()-ResultSetHandler 处理结果集
- 聚集云原生,可观测性的实践与探索 | 线下技术沙龙
- android音乐播放器音乐加载,Android开源音乐播放器之在线音乐列表自动加载更多...
- 【转】Win10系统创建WiFi热点的两种方法
- 计算机一级举报单位,2018年9月计算机一级Photoshop考试巩固练习题(三)
- PyTorch的hook及其在Grad-CAM中的应用
- 24个整点报时_大连交通广播整点报时广告怎么做?大连交通广播全新广告价格...
- 当vue遇到pwa--vue+pwa移动端适配解决方案模板案例
- UVa11137 - Ingenuous Cubrency
- SpringMVCfrom:form表单标签和input表单标签简介
- 数独问题(java)
- CISCO路由器命令大全
- google的视频下载插件
- python可以ps吗_python-PS图片
- 软件定义闪存: SSD加速企业数据中心变革
- 迅雷在下载网页视频时没有自动弹出提示,怎么办?
- C51汇编语言寻址方式,80C51单片机指令系统的7种寻址方式
- 【SVN】SVN是什么?怎么使用?