双向循环链表讲解及实现
文章目录
- 一.带头双向循环链表
- 二.实现
- (1).动态申请一个结点
- (2).创建头结点进行初始化
- (3).尾插
- (4).尾删
- (5).头插
- (6).头删
- (7).查找元素
- (8).在pos位置之前进行插入
- (9).删除pos位置的结点
- (10).打印数据
- 三.代码实现
一.带头双向循环链表
带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个链表虽然结构复杂,但是使用代码实现以后会发现能带来很多优势.
二.实现
Lish.h中部分声明
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* prev;struct ListNode* next;LTDataType data;
}ListNode;
prev为结点中的指向前一个结点的指针 , next 为指针中的指向后一个结点的指针 , data为结点中的数据
(1).动态申请一个结点
动态申请一个大小为sizeof(ListNode)的结点
// 动态申请一个结点
ListNode*BuyListNode(LTDataType x)
{ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));if(newNode == NULL){printf("分配内存失败\n");exit(-1);}newNode->prev = newNode->next = NULL;newNode->data = x;return newNode;
}
(2).创建头结点进行初始化
因为为带头的双向循环链表,因此初始化头结点时,头结点的prev,next指针都指向自已
// 创建头结点进行初始化
ListNode* ListInit()
{ListNode* plist = BuyListNode(0); // 头结点中的数据初始化为 0plist->prev = plist->next = plist;return plist;
}
(3).尾插
通过头结点的prev指针可以找到尾结点tail,tail->next指向待插入的结点,待插入结点的prev指针指向tail,头结点的prev指针指向待插入结点,待插入结点的next指向头结点
// 尾插
void ListPushBack(ListNode* plist,LTDataType x)
{assert(plist);ListNode* newNode = BuyListNode(x);ListNode* tail = plist->prev;tail->next = newNode;newNode->prev = tail;newNode->next = plist;plist->prev = newNode;
}
(4).尾删
通过头结点的prev指针找到尾结点tail,通过tail的prev指针找到 tailPrev结点
要使tailPrev成为尾结点,将tailPrev结点和plist头结点连接到一起
// 尾删
void ListPopBack(ListNode* plist)
{assert(plist);assert(plist->next != plist);ListNode* tail = plist->prev;ListNode* tailPrev = tail->prev;tailPrev->next = plist;plsit->prev = tailPrev;free(tail);tail = NULL;
}
(5).头插
动态申请一个结点newNode,通过plist->next找到当前的第一个结点(first),newNode结点要插入到plist头结点和first结点之间
// 头插
void ListPushFront(ListNode* plist,LTDataType x)
{assert(plist);ListNode* newNode = BuyListNode(x);ListNode* first = plist->next;plist->next = newNode;newNode->prev = plist;newNode->next = first;first->prev = newNode;
}
(6).头删
通过plist->next找到第一个结点(first),first->next找到第二个结点(second),将plist头结点和second结点连接到一起,释放掉第一个结点(first)
// 头删
void ListPopFront(ListNode* plist)
{assert(plist);assert(plist->next != plist);ListNode* first = plist->next;ListNode* second = first->next;plist->next = second;second->prev = plist;free(first);first = NULL;
}
(7).查找元素
遍历一次链表,终止条件为 cur != plist ,因为 cur = plist 说明已经循环了一遍
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x)
{assert(plist);ListNode* cur = plist->next;while (cur != plist){if (cur->data == x)return cur;cur = cur->next;}return NULL;
}
(8).在pos位置之前进行插入
动态申请一个结点 ,找到pos位置的前一个结点(posPrev),将pos,posPrev,newNode结点连接到一起
// 在pos位置前插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newNode = BuyListNode(x);ListNode* posPrev = pos->prev;posPrev->next = newNode;newNode->prev = posPrev;newNode->next = pos;pos->prev = newNode;
}
(9).删除pos位置的结点
找到pos的前一个结点(posPrev)和后一个结点(posNext),将posPrev,posNext结点连接到一起,删除掉pos结点
// 删除pos位置的结点
void ListErase(ListNode* pos)
{assert(pos);ListNode* PosPrev = pos->prev;ListNode* PosNext = pos->next;PosPrev->next = PosNext;PosNext->prev = PosPrev;free(pos);pos = NULL;
}
(10).打印数据
遍历一次链表,终止条件为 cur != plist ,因为 cur = plist 说明已经循环了一遍
// 打印
void Listprint(ListNode* plist)
{assert(plist);ListNode* cur = plist->next;while (cur != plist){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}
三.代码实现
List.h文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* prev;struct ListNode* next;LTDataType data;
}ListNode;
// 初始化创建头结点
ListNode* ListInit();
// 动态申请一个结点
ListNode* BuyListNode(LTDataType x);
// 打印
void Listprint(ListNode* plist);
// 尾插
void ListPushBack(ListNode* plist, LTDataType x);
// 尾删
void ListPopBack(ListNode* plist);
// 头插
void ListPushFront(ListNode* plist, LTDataType x);
// 头删
void ListPopFront(ListNode* plist);
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x);
// 在pos前插入
void ListInsert(ListNode* pos, LTDataType x);
// 删除pos位置的结点
void ListErase(ListNode* pos);
Lish.c文件
#include"List.h"
// 初始化创建头结点
ListNode* ListInit()
{ListNode* phead = BuyListNode(0);phead->next = phead;phead->prev = phead;return phead;
}
// 动态申请一个结点
ListNode* BuyListNode(LTDataType x)
{ListNode* NewNode = (ListNode*)malloc(sizeof(ListNode));if (NewNode == NULL){printf("分配内存失败\n");exit(-1);}NewNode->prev = NewNode->next = NULL;NewNode->data = x;return NewNode;
}
// 打印
void Listprint(ListNode* plist)
{assert(plist);ListNode* cur = plist->next;while (cur != plist){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}
// 尾插
void ListPushBack(ListNode* plist, LTDataType x)
{assert(plist);ListNode* NewNode = BuyListNode(x);ListNode* tail = plist->prev;tail->next = NewNode;NewNode->prev = tail;plist->prev = NewNode;NewNode->next = plist;
}
// 尾删
void ListPopBack(ListNode* plist)
{assert(plist);assert(plist->next != plist);ListNode* tail = plist->prev;ListNode* tail_prev = tail->prev;tail_prev->next = plist;plist->prev = tail_prev;free(tail);tail = NULL;
}
// 头插
void ListPushFront(ListNode* plist, LTDataType x)
{assert(plist);ListNode* NewNode = BuyListNode(x);ListNode* first = plist->next;plist->next = NewNode;NewNode->prev = plist;NewNode->next = first;first->prev = NewNode;
}
// 头删
void ListPopFront(ListNode* plist)
{assert(plist);assert(plist->next != plist);ListNode* first = plist->next;ListNode* second = first->next;plist->next = second;second->prev = plist;free(first);first = NULL;
}
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x)
{assert(plist);ListNode* cur = plist->next;while (cur != plist){if (cur->data == x)return cur;cur = cur->next;}return NULL;
}
// 在pos位置前插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* NewNode = BuyListNode(x);ListNode* PosPrev = pos->prev;PosPrev->next = NewNode;NewNode->prev = PosPrev;NewNode->next = pos;pos->prev = NewNode;
}
// 删除pos位置的结点
void ListErase(ListNode* pos)
{assert(pos);ListNode* PosPrev = pos->prev;ListNode* PosNext = pos->next;PosPrev->next = PosNext;PosNext->prev = PosPrev;free(pos);pos = NULL;
}
TestLish.c文件
#include"List.h"
void TestList01()
{ListNode* plist = ListInit();ListPushBack(plist, 1);ListPushBack(plist, 2);ListPushBack(plist, 3);ListPushBack(plist, 4);Listprint(plist);ListPopBack(plist);ListPopBack(plist);ListPopBack(plist);ListPopBack(plist);// ListPopBack(plist);Listprint(plist);ListPushFront(plist, 1);ListPushFront(plist, 2);ListPushFront(plist, 3);ListPushFront(plist, 4);Listprint(plist);ListPopFront(plist);ListPopFront(plist);ListPopFront(plist);ListPopFront(plist);// ListPopFront(plist);Listprint(plist);
}
void TestList02()
{ListNode* plist = ListInit();ListPushBack(plist, 1);ListPushBack(plist, 2);ListPushBack(plist, 3);ListPushBack(plist, 4);ListNode* pos = ListFind(plist, 3);ListInsert(pos, 30);Listprint(plist);ListErase(pos);Listprint(plist);}
int main()
{TestList01();TestList02();
}
双向循环链表讲解及实现相关推荐
- 双向循环链表的讲解及实现(图解+代码/C语言)
本次为大家分享的是双向循环链表的增删查改等系列操作. 目录 一.图解双向循环链表结构 二.分步实现 (1)创建并初始化 (2)链表元素打印 (3)头插和尾插 (4)判断链表为空 (5)头删和尾删 (6 ...
- 试编写一个将双向循环链表逆置的算法_图解:链表的快慢指针,解决 80% 的链表面试题!...
一.前言 链表是基本的数据结构之一,它与数组不同,数组在内存中存储,需要一块连续的内容空间来存储,对内存的要求比较高.例如我们需要 100MB 大小的数组,内存中就必须有一段连续的 100MB 的内存 ...
- 双向循环链表:鸿蒙轻内核中数据的“驿站”
本文分享自华为云社区<鸿蒙轻内核M核源码分析系列二 数据结构-双向循环链表>,原文作者:zhushy . 在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用. ...
- 比特数据结构与算法(第二章收尾)带头双向循环链表的实现
1.链表的分类 链表的分类 ① 单向或者双向 ② 带头或者不带头 ③ 循环或者非循环 常用的链表: 根据上面的分类我们可以细分出8种不同类型的链表,这么多链表我们一个个讲解这并没有意义.我们实际中最常 ...
- 玩转数据结构之双向循环链表
文章目录 一.前言 二.双向链表的实现 ①.定义节点 ②.创建新节点(BuyLTNode) ③.初始化链表(ListInit) ④.双向链表销毁(ListDestory) ⑤.双向链表打印(ListP ...
- 初阶数据结构之带头+双向+循环链表增删查实现(三)
文章目录 @[TOC](文章目录) 前言 一.带头双向循环链表的初始化 1.1带头双向循环链表的结构体定义 1.2初始化代码的实现 二.带头+双向+循环链表的增功能实现 2.1头插代码的实现 2.2尾 ...
- 【数据结构】-关于带头双向循环链表的增删查改
作者:低调 作者宣言:写好每一篇博客 文章目录 前言 一.带头双向循环链表的实现 1.1创建返回链表的头结点 1.2开辟一个新的结点 1.3双向链表的销毁 1.4双向链表的打印 1.5双向链表尾插 1 ...
- c语言实现数据结构中的带头双向循环链表
目录标题 一.单向链表的不足 二.带头双向链表的准备 三.带头双向链表的初始化 四.带头双向链表的尾插 五.带头双向链表的打印 六.带头双向链表头插 七.判断链表是否为空 八.带头双向链表尾删 九.带 ...
- 数据结构与算法(2-2)线性表之链式存储(单链表、静态链表、循环链表、双向循环链表)
目录 一.单链表 1.存储方式 2.插入 3.删除 总代码: 二.静态链表 1.存储方式 2.插入 3.删除 4.遍历 总代码: 三.循环链表 总代码: 四.双向循环链表 1.存储方式: 2.插入和删 ...
- 链表 -- 双向循环链表(线性表)
1,双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点.一般我们都构造双向循环 ...
最新文章
- java lambda 变量_java8新特性-lambda(变量捕获)
- 腾讯会议又一黑科技,屏蔽超过 200 种会议噪声是如何做到的?
- 全球移动SaaS市场规模5年将增170亿美元
- 使用apache的HttpClient进行http通讯,隐藏的HTTP请求头部字段是如何自动被添加的
- 让你的 Qt 桌面程序看上去更加 native(三):自定义 style
- ug链轮设计软件_正版UG软件,UG软件代理,正版UG软件模块功能介绍
- matlab信号系统响应实验,信号与系统实验(MATLAB版) (1)
- 谷歌浏览器好用的插件推荐
- mac下复制粘贴需要多次的问题
- 基于自适应决策算子的鲸鱼优化算法-附代码
- Linux 常用命令大全
- 查询用户活跃度表登录间隔30天的用户
- 初学rust——Tests
- IP查询和IPv6查询接口
- 利用动态二进制加密实现新型一句话木马之.NET篇(转)冰蝎
- IC芯片设计项目管理003:检查清单checklist的应用
- 图像分割 FCN(1):FCN网络讲解
- 对接阿里云sms短信服务发送验证码
- Google三驾马车:GFS、MapReduce和Bigtable
- Erlang NIF浅析