数据结构入门(C语言版)线性表带头双向循环链表接口实现(上)

简介: 第一步当然是先使用malloc函数申请内存空间,然后就是两个指针的建立,尾部指针指向头结点头部,头部指针指向头结点尾部,返回带头结点,头结点初始化完成。

5d74882d88c44e34904e221ddbc59cb0.png


导航


1、带头双向循环链表介绍


52c51e96575442859756ce7e7b6e8343.jpg


在上一篇博客我们讲述了链表的概念和结构,还实现了无头单向非循环链表接口写法,那么这一章节,我们来实现另一种常用的链表组成结构——带头双向循环链表。

如果对前面的链表基本概念还是不了解,可以看作者的上一篇博客:线性表中链表介绍及无头单向非循环链表接口实现


2、结构体及接口函数定义


首先是结构体的定义

代码如下:


typedef int LTDateType;
typedef struct ListNode
{
  LTDateType data;//结点存储元素
  struct ListNode* next;//下一结点指针
  struct ListNode* prev;//上一结点指针
}LTNode;


然后就是接口函数的定义

代码如下:


void ListInit(LTNode* phead);//哨兵位头结点初始化
LTNode* BuyListNode(LTDateType x);//动态申请结点
void ListPushBack(LTNode* phead, LTDateType x);//双向链表尾插
void ListPopBack(LTNode* phead);//双向链表尾删
void ListPushFront(LTNode* phead, LTDateType x);//双向链表头插
void ListPopFront(LTNode* phead);//双向链表头删
LTNode* ListFind(LTNode* phead, LTDateType x);//双向链表查找
void ListInsert(LTNode* pos, LTDateType x);//在pos位置前插入
void ListErase(LTNode* pos);//删除pos位置的结点
void ListPrint(LTNode* phead);//打印双向链表
void ListDestroy(LTNode* phead);//销毁双向链表


3、接口函数实现


在上一篇博客中我们讲到不带头的单非循环链表存在一定缺陷,就是无法访问上一结点,但是这一节讲的带头双向循环链表就很好的弥补了这一缺点,带头双向循环链表看来比单链表结构要复杂很多,但其实实现起来要比单链表更简单,更高效;下面我们就来实现带头双向循环链表的接口函数吧!


3.1 头结点初始化


头结点初始化(ListInit)

首先是我们的头结点的定义,它是不存放数据的,起到一个哨兵的作用

代码如下:


void ListInit(LTNode* phead)
{
  // 哨兵位头结点
  LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
  phead->next = phead;
  phead->prev = phead;
  return phead;
}


第一步当然是先使用malloc函数申请内存空间,然后就是两个指针的建立,尾部指针指向头结点头部,头部指针指向头结点尾部,返回带头结点,头结点初始化完成。


3.2 结点动态内存申请


结点动态内存申请(BuyListNode)

这个函数和上一篇中的单链表的函数类似

代码如下:


LTNode* BuyListNode(LTDateType x)
{
  LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
  newnode->data = x;
  newnode->next = NULL;
  newnode->prev = NULL;
  return newnode;
}


第一步也是先使用malloc函数申请内存空间,然后就是初始化这个结点的操作,将元素插入,两个指针指向空,返回新结点,完成结点初始化操作。


3.3 双向链表尾插


双向链表尾插(ListPushBack)

代码如下:


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


这里我们先是把phead的上一级指针赋给tail

再将要插入的元素赋给临时结点newnode

接着将tail的下一级指针指向newnode

再将newnode上一级指针指向tail

newnode下一级指针指向被插入结点phead

最后将phead的上一级指针再指向newnode完成尾插操作


3.4 双向链表尾删


双向链表尾删(ListPopBack)

代码如下:


void ListPopBack(LTNode* phead)
{
  assert(phead);
  assert(phead->next != phead);//防止链表中无元素继续删除的断言
  LTNode* tail = phead->prev;
  phead->prev = tail->prev;
  tail->prev->next = phead;
  free(tail);
}


上述代码中第二个断言是为了防止链表中无元素继续删除

这里我们也是先把phead的上一级指针赋给tail

再将tail的上一级指针赋给phead的上一级指针

也就是指向要删除结点的上一结点

最后将要删除结点的前一个结点的下一级指针指向头结点

然后释放掉tail的内存空间完成尾删


3.5 双向链表头插


双向链表头插(ListPushFront)

代码如下:


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


这里我们先和尾插一样将要插入的元素值赋给临时结点newnode

将phead下一级指针赋给临时结点next

再将newnode赋给phead下一级指针

也就是把phead的尾部指针指向newnode

把phead赋给newnode的上一级指针

再将next赋给newnode的下一级指针

最后把newnode赋给next的上一级指针,完成头插

相关文章
|
10月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
401 30
|
10月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
479 25
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
401 7
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
11月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
546 5
|
11月前
|
存储 编译器 C语言
【C语言程序设计——入门】C语言入门与基础语法(头歌实践教学平台习题)【合集】
本文档介绍了C语言环境配置和编程任务,主要内容包括: - **C语言环境配置**:详细讲解了在Windows系统上配置C语言开发环境的步骤。 - **第1关:程序改错**:包含任务描述、相关知识(如头文件引用、基本语法规则)、编程要求、测试说明及通关代码。 - **第2关:scanf函数**:涉及`scanf`和`printf`函数的格式与使用方法,提供编程要求、测试说明及通关代码。 文档结构清晰,涵盖从环境搭建到具体编程任务的完整流程,适合初学者学习和实践。
376 4
|
11月前
|
C语言
【C语言程序设计——入门】基本数据类型与表达式(头歌实践教学平台习题)【合集】
这份文档详细介绍了编程任务的多个关卡,涵盖C语言的基础知识和应用。主要内容包括: 1. **目录**:列出所有关卡,如`print函数操作`、`转义字符使用`、`数的向上取整`等。 2. **各关卡的任务描述**:明确每关的具体编程任务,例如使用`printf`函数输出特定字符串、实现向上取整功能等。 3. **相关知识**:提供完成任务所需的背景知识,如格式化输出、算术运算符、关系运算符等。 4. **编程要求**:给出具体的代码编写提示。 5. **测试说明**:包含预期输入输出,帮助验证程序正确性。 6. 文档通过逐步引导学习者掌握C语言的基本语法和常用函数,适合初学者练习编程技能。
295 1
|
12月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
存储 缓存 C语言
数据结构——双链表(C语言)
数据结构——双链表(C语言)
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
1186 4
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
422 0

热门文章

最新文章