广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言实现带头双向环形链表
  • 572
分享到

C语言实现带头双向环形链表

2024-04-02 19:04:59 572人浏览 安东尼
摘要

双向循环链表 上一次我们讲了单向无头非循环链表的实现,单向无头非循环链表的特点是:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构。而带头双向循环链表则恰恰与无

双向循环链表

上一次我们讲了单向无头非循环链表的实现,单向无头非循环链表的特点是:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构。而带头双向循环链表则恰恰与无头单向非循环链表相反,它的结构最复杂,一般用来单独存储数据。这个结构虽然复杂,但是使用单吗实现后会发现,这个结构用起来很简单。

结构示意图

带头双向循环链表在逻辑上大概就是这样的一个样子,链表的最后一个节点的后继指向的是头结点。而头结点的前驱则是指向链表的最后一个结点。所以,一个空的带头双向循环链表的逻辑结构应该是这样的:

它的前驱和后继都是指向的头结点。

实现带头双向循环链表


#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int LTDataType;
// 定义链表的节点
typedef struct Listnode {
 LTDataType data;
 struct ListNode* prev;
 struct ListNode* next;
}LTNode;

// 创建返回链表的头结点.
LTNode* ListCreate();
// 双向链表销毁
void ListDestory(LTNode* pHead);
// 双向链表打印
void ListPrint(LTNode* pHead);
// 双向链表尾插
void ListPushBack(LTNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(LTNode* pHead);
// 双向链表头插
void ListPushFront(LTNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(LTNode* pHead);
// 双向链表查找
LTNode* ListFind(LTNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(LTNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(LTNode* pos);

首先我们得定义一个结点的结构,它由前驱指针、后继指针和数据这三部分组成。


// 定义链表的节点
typedef struct ListNode {
 LTDataType data;
 struct ListNode* prev;
 struct ListNode* next;
}LTNode;

定义好之后,我们要创建一个头结点。我们把创建头结点的过程也封装成一个函数,这个函数的返回值就是头结点的指针。我们在使用的时候就创建一个变量来接收这个指针。

**注意:**头结点创建的时候,它的data部分是不存数据的,它的前驱和后继都是指向它自己


LTNode* ListCreate() {
 LTNode* head = (LTNode*)malloc(sizeof(LTNode));
 head->next = head;
 head->prev = head;
 return head;
}
// 在main函数中是这样使用的
int main(){
    LTNode* head = ListCreate();
    return 0;
}

创建好头结点之后就可以向链表中插入数据了,首先实现尾插,就是在链表的最后一个结点后面再插入一个结点。然后就是头插法,头插法就是在头结点的后面插入一个新节点。


// 双向链表尾插
void ListPushBack(LTNode* pHead, LTDataType x) {
 assert(pHead);
 LTNode* newnode = (LTNode*)malloc(sizeof(LTNode)); // 创建的新节点
 newnode->data = x;
    // 将新节点插入到链表中
 LTNode* prev = pHead->prev;
 prev->next = newnode;
 newnode->prev = prev;
 newnode->next = pHead;
 pHead->prev = newnode;

}

// 双向链表头插
void ListPushFront(LTNode* pHead, LTDataType x) {
 assert(pHead);
    // 创建新节点
 LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
 newnode->data = x;
    //将新节点插入链表
 LTNode* next = pHead->next;
 pHead->next = newnode;
 newnode->prev = pHead;
 newnode->next = next;
 next->prev = newnode;
}

有插入数据就有删除数据,同样的删除数据也有两种,一个是头删一个是尾删。头删就是将头结点的next指向的那个结点删除。尾删,就是将最后一个节点删掉。带头双向循环链表,在我们尾删的时候就很方便。因为头结点的前驱指向的节点就是链表的最后一个节点,就不需要我们再遍历链表去找最后一个节点的地址。


// 双向链表头删
void ListPopFront(LTNode* pHead) {
 assert(pHead);
 assert(pHead->next != pHead);
    // 定义一个临时变量来保存我们要删掉的节点的位置
 LTNode* popnode = pHead->next;
    // 将要删除节点的链都断掉
 LTNode* next = popnode->next;
 pHead->next = popnode->next;
 next->prev = pHead;
    // free掉那个节点
 free(popnode);
 popnode = NULL;
}

// 双向链表尾删
void ListPopBack(LTNode* pHead) {
 assert(pHead);
 assert(pHead->prev != pHead);
 LTNode* popnode = pHead->prev;
 LTNode* prev = popnode->prev;
 prev->next = pHead;
 pHead->prev = prev;
 free(popnode);
 popnode = NULL;
}

在实现了增加和删除节点之后,我们就实现查找结点。方法也是遍历整个链表,如果有一个节点的data的值和x相同就返回这个节点的地址。如果没找到就返回空。


// 双向链表查找
LTNode* ListFind(LTNode* pHead, LTDataType x) {
 if (pHead->next == pHead) {
  return NULL;
 }
 LTNode* find = pHead->next;
 while (find != pHead) {
  if (find->data == x) {
   return find;
  }
  find = find->next;
 }
 return NULL;
}

实现随机插入数据,这里的随机插入的意思是,我们把新节点插入到我们指定的节点的后面一个或前面一个。这个节点可以是在链表的任何一个地方。我们这个函数会传入一个节点的地址,通过那个地址可以找到要出入的那个节点,把新节点连接到那个节点后面就可以了


// 双向链表删除pos位置的节点
void ListErase(LTNode* pos) {
 assert(pos);
 LTNode* prev = pos->prev;
 LTNode* next = pos->next;
 prev->next = next;
 next->prev = prev;
 free(pos);
 pos = NULL;
}

打印双向循环链表,也是通过遍历链表来打印


// 双向链表打印
void ListPrint(LTNode* pHead) {
 assert(pHead);
 LTNode* tail = pHead->next;
 while (tail != pHead) {
  printf("%d->", tail->data);
  tail = tail->next;
 }
}

在我们使用完链表后,要记得销毁链表,防止内存泄漏


// 双向链表销毁
void ListDestory(LTNode* pHead) {
 assert(pHead);
 LTNode* tail = pHead->next;
 while (tail != pHead) {
  LTNode* tmp = tail->next;
  free(tail);
  tail = tmp;
 }
 free(pHead);
 pHead = NULL;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C语言实现带头双向环形链表

本文链接: https://www.lsjlt.com/news/158577.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言实现带头双向环形链表
    双向循环链表 上一次我们讲了单向无头非循环链表的实现,单向无头非循环链表的特点是:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构。而带头双向循环链表则恰恰与无...
    99+
    2022-11-12
  • C语言怎么实现带头双向环形链表
    本篇内容主要讲解“C语言怎么实现带头双向环形链表”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言怎么实现带头双向环形链表”吧!双向循环链表上一次我们讲了单向无头非循环链表的实现,单向无头非循...
    99+
    2023-06-21
  • C语言实现带头双向循环链表
    目录前言1. 创建结构体2.malloc新节点3.创建哨兵位节点4.尾插5.打印6.尾删7.头插8.在指定位置pos的前面进行插入9. 删除指定位置pos节点10.销毁链表前言 在...
    99+
    2022-11-13
  • C语言怎么实现带头双向循环链表
    本篇内容主要讲解“C语言怎么实现带头双向循环链表”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言怎么实现带头双向循环链表”吧!创建链表存储结构我们需要创建一个结构体来存储一个链表结点的相关信...
    99+
    2023-06-30
  • C语言带头双向循环链表怎么实现
    这篇“C语言带头双向循环链表怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言带头双向循环链表怎么实现”文章吧。带...
    99+
    2023-06-30
  • C语言如何实现带头双向循环链表
    这篇文章主要介绍了C语言如何实现带头双向循环链表,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言在实际生活中最常用的就是这两种链表。无头单向非循环链表。和带头双向循环链表。...
    99+
    2023-06-29
  • C语言实现带头双向循环链表的接口
    本文实例为大家分享了C语言实现带头双向循环链表的接口,供大家参考,具体内容如下 各函数功能如下 申请空间 ListNode* BuyListNode(LTDataType x) ...
    99+
    2022-11-12
  • C语言详解如何实现带头双向循环链表
    目录创建链表存储结构创建结点链表的初始化双向链表的打印双向链表尾插双向链表尾删双向链表头插双向链表头删双向链表查找双向链表pos前插入结点双向链表删除pos位置的结点双向链表的销毁顺...
    99+
    2022-11-13
  • C语言怎么实现线性表中的带头双向循环链表
    这篇文章主要介绍了C语言怎么实现线性表中的带头双向循环链表的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言怎么实现线性表中的带头双向循环链表文章都会有所收获,下面我们一起来看看吧。一、本章重点带头双向循环链...
    99+
    2023-06-29
  • C++带头双向循环链表怎么实现
    这篇文章主要介绍“C++带头双向循环链表怎么实现”,在日常操作中,相信很多人在C++带头双向循环链表怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++带头双向循环链表怎么实现”的疑惑有所帮助!接下来...
    99+
    2023-06-29
  • C++如何实现带头双向循环链表
    这篇文章主要为大家展示了“C++如何实现带头双向循环链表”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++如何实现带头双向循环链表”这篇文章吧。什么是带头双向循环链表什么是带头?双向?循环?(...
    99+
    2023-06-29
  • C语言超详细讲解双向带头循环链表
    目录一、双向带头循环链表的结构二、双向带头循环链表的函数接口1. 申请结点2. 初识化3. 打印4. 尾插尾删5. 头插头删6. 查找7. 中间插入和删除8. 判空及求链表长度9. ...
    99+
    2023-02-14
    C语言双向带头循环链表 C语言带头循环链表 C语言循环链表
  • C语言带头双向循环链表的示例代码
    目录前言结构分析链表的基本操作实现创建节点初始化链表链表销毁打印链表链表尾插链表尾删链表头插链表头删链表查找链表pos位置前面去插入删除pos位置链表判空代码复用总代码及头文件前言 ...
    99+
    2022-11-13
    C语言带头双向循环链表 C语言 双向循环链表 C语言 循环链表
  • C语言手把手带你掌握带头双向循环链表
    目录前言带头双向循环链表的结构代码操作前言 关于链表这一块,写了多篇博客,学习了顺序表、单链表、及其一些练习题 顺序表:传送门:顺序表 单链表:传送门:单链表1  ...
    99+
    2022-11-13
  • C语言数据结构中双向带头循环链表怎么实现
    这篇文章主要讲解了“C语言数据结构中双向带头循环链表怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言数据结构中双向带头循环链表怎么实现”吧!一、概念来画张图总体回顾下:在我们学习...
    99+
    2023-06-30
  • C语言如何实现双向链表和双向循环链表
    本文小编为大家详细介绍“C语言如何实现双向链表和双向循环链表”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言如何实现双向链表和双向循环链表”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。双向链表和双向循环链表...
    99+
    2023-06-16
  • C++实现带头双向循环链表的示例详解
    目录一、双向循环链表与顺序表的区别二、List.h三、List.c1、带头双向循环链表的初始化2、带头双向循环链表的销毁3、带头双向循环链表的打印4、动态开辟一个节点5、带头双向循环...
    99+
    2022-12-08
    C++带头双向循环链表 C++ 双向循环链表 C++ 循环链表
  • C语言超详细介绍与实现线性表中的带头双向循环链表
    目录一、本章重点二、带头双向循环链表介绍2.1什么是带头双向循环链表?2.2最常用的两种链表结构三、带头双向循环链表常用接口实现 3.1结构体创建3.2带头双向循环链表的初始化 3....
    99+
    2022-11-13
  • C语言实现循环双链表
    本文实例为大家分享了C语言实现循环双链表的具体代码,供大家参考,具体内容如下 #include<stdio.h> #include<stdlib.h> #...
    99+
    2022-11-12
  • C++带头双向循环链表超详细解析
    目录什么是带头双向循环链表带头双向循环链表常用接口实现上期我们讲完了无头单向非循环链表,这期我们接着来讲链表中结构最复杂的带头双向循环链表! 本期主要内容: 什么是带头双向循环链表...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作