链表基础4——带头双向循环链表

什么是带头双向循环链表

我们直接看图片

定义结点类型 

typedef int LTDataType;//存储的数据类型typedef struct ListNode
{LTDataType data;//数据域struct ListNode* prev;//前驱指针struct ListNode* next;//后继指针
}ListNode;

链表的初始化 

//创建一个新结点
ListNode* BuyListNode(LTDataType x)
{ListNode* node = (ListNode*)malloc(sizeof(ListNode));if (node == NULL){printf("malloc fail\n");exit(-1);}node->data = x;//新结点赋值node->prev = NULL;node->next = NULL;return node;//返回新结点
}//初始化链表
ListNode* ListInit()
{ListNode* phead = BuyListNode(-1);//申请一个头结点,头结点不存储有效数据//起始时只有头结点,让它的前驱和后继都指向自己phead->prev = phead;phead->next = phead;return phead;//返回头结点
}

销毁链表

销毁链表,从头结点的后一个结点处开始向后遍历并释放结点,直到遍历到头结点时,停止遍历并将头结点也释放掉。

//销毁链表
void ListDestroy(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;//从头结点后一个结点开始释放空间ListNode* next = cur->next;//记录cur的后一个结点位置while (cur != phead){free(cur);cur = next;next = next->next;}free(phead);//释放头结点
}

打印双向链表 

打印双向链表时也是从头结点的后一个结点处开始向后遍历并打印,直到遍历到头结点处时便停止遍历和打印(头结点数据不打印)。

//打印双向链表
void ListPrint(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;//从头结点的后一个结点开始打印while (cur != phead)//当cur指针指向头结点时,说明链表以打印完毕{printf("%d ", cur->data);cur = cur->next;}printf("\n");
}

查找元素

给定一个值,在链表中寻找与该值相同的结点,若找到了,则返回结点地址;若没有找到,则返回空指针(NULL)。

//查找元素
ListNode* ListFind(ListNode* phead, LTDataType x)
{assert(phead);ListNode* cur = phead->next;//从头结点的后一个结点开始查找while (cur != phead)//当cur指向头结点时,说明链表已遍历完毕{if (cur->data == x){return cur;//返回目标结点的地址}cur = cur->next;}return NULL;//没有找到目标结点
}

增加结点

头插

 头插,即申请一个新结点,将新结点插入在头结点和头结点的后一个结点之间即可。

//头插
void ListPushFront(ListNode* phead, LTDataType x)
{assert(phead);ListNode* newnode = BuyListNode(x);//申请一个结点,数据域赋值为xListNode* front = phead->next;//记录头结点的后一个结点位置//建立新结点与头结点之间的双向关系phead->next = newnode;newnode->prev = phead;//建立新结点与front结点之间的双向关系newnode->next = front;front->prev = newnode;
}

 尾插

 尾插,申请一个新结点,将新结点插入到头结点和头结点的前一个结点之间即可。因为链表是循环的,头结点的前驱指针直接指向最后一个结点,所以我们不必遍历链表找尾。

//尾插
void ListPushBack(ListNode* phead, LTDataType x)
{assert(phead);ListNode* newnode = BuyListNode(x);//申请一个结点,数据域赋值为xListNode* tail = phead->prev;//记录头结点的前一个结点的位置//建立新结点与头结点之间的双向关系newnode->next = phead;phead->prev = newnode;//建立新结点与tail结点之间的双向关系tail->next = newnode;newnode->prev = tail;
}

在指定位置插入结点

 在直到位置插入结点,准确来说,是在指定位置之前插入一个结点。我们只需申请一个新结点插入到指定位置结点和其前一个结点之间即可

//在指定位置插入结点
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* before = pos->prev;//记录pos指向结点的前一个结点ListNode* newnode = BuyListNode(x);//申请一个结点,数据域赋值为x//建立新结点与before结点之间的双向关系before->next = newnode;newnode->prev = before;//建立新结点与pos指向结点之间的双向关系newnode->next = pos;pos->prev = newnode;
}

删除结点

头删

 头删,即释放头结点的后一个结点,并建立头结点与被删除结点的后一个结点之间的双向关系即可。

//头删
void ListPopFront(ListNode* phead)
{assert(phead);assert(phead->next != phead);ListNode* front = phead->next;//记录头结点的后一个结点ListNode* newfront = front->next;//记录front结点的后一个结点//建立头结点与newfront结点之间的双向关系phead->next = newfront;newfront->prev = phead;free(front);//释放front结点
}

尾删

 尾删,即释放最后一个结点,并建立头结点和被删除结点的前一个结点之间的双向关系即可。

//尾删
void ListPopBack(ListNode* phead)
{assert(phead);assert(phead->next != phead);ListNode* tail = phead->prev;//记录头结点的前一个结点ListNode* newtail = tail->prev;//记录tail结点的前一个结点//建立头结点与newtail结点之间的双向关系newtail->next = phead;phead->prev = newtail;free(tail);//释放tail结点
}

删除指定位置结点

删除指定位置结点,释放掉目标结点后,建立该结点前一个结点和后一个结点之间的双向关系即可。

//删除指定位置结点
void ListErase(ListNode* pos)
{assert(pos);ListNode* before = pos->prev;//记录pos指向结点的前一个结点ListNode* after = pos->next;//记录pos指向结点的后一个结点//建立before结点与after结点之间的双向关系before->next = after;after->prev = before;free(pos);//释放pos指向的结点
}

链表判空

 链表判空,即判断头结点的前驱或是后驱指向的是否是自己即可。

//链表判空
bool ListEmpty(ListNode* phead)
{assert(phead);return phead->next == phead;//当链表中只有头结点时为空
}

获取链表中的元素个数

 获取链表中的元素个数,即遍历一遍链表,统计结点的个数(头结点不计入)并返回即可。

//获取链表中的元素个数
int ListSize(ListNode* phead)
{assert(phead);int count = 0;//记录元素个数ListNode* cur = phead->next;//从头结点的后一个结点开始遍历while (cur != phead)//当cur指向头结点时,遍历完毕,头结点不计入总元素个数{count++;cur = cur->next;}return count;//返回元素个数
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/636303.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

社交媒体数据恢复:Dust

社交媒体数据恢复:Dust/CYBER DUST 网络灰尘:更安全的发短信场所 概述 CYBER DUST 让您掌控自己的数字生活。我们相信网络生活就是现实生活,因此只有您应该控制有关您的信息。我们的用户受到保护——不用担心被窥探、数据挖掘、粗略的黑客&…

Golang | Leetcode Golang题解之第42题接雨水

题目&#xff1a; 题解: func trap(height []int) (ans int) {n : len(height)if n 0 {return}leftMax : make([]int, n)leftMax[0] height[0]for i : 1; i < n; i {leftMax[i] max(leftMax[i-1], height[i])}rightMax : make([]int, n)rightMax[n-1] height[n-1]for i…

06 MapStream递归

Collections(集合工具类) 可变参数 就是一种特殊形参&#xff0c;定义在方法、构造器的形参列表里&#xff0c;定义格式是&#xff1a;方法名(数据类型… 形参名称){ } 可变参数的特点和好处 **特点&#xff1a;**可以不传数据给它&#xff1b;可以传一个或者同时传多个数据给…

Edge 浏览器使用方法和经验技巧

目前我已经将主力浏览器从火狐更换到Edge&#xff0c;本文将会根据我自己的使用经验来不断更新完善&#xff0c;内容包括下载、常用插件、使用技巧和常见问题等 下载安装 Edge是win10内置的浏览器&#xff0c;因此多数人不需要下载&#xff0c;如果你的电脑并没有安装&#x…

LearnOpenGL(二)之三角形

一、重要概念 顶点数组对象&#xff1a;Vertex Array Object&#xff0c;VAO顶点缓冲对象&#xff1a;Vertex Buffer Object&#xff0c;VBO元素缓冲对象&#xff1a;Element Buffer Object&#xff0c;EBO 或 索引缓冲对象 Index Buffer Object&#xff0c;IBO 以数组的形式…

《2024最新Java面试题及答案(带完整目录)》

2024最新Java面试题及答案有史以来见过的最全面试题 获取链接&#xff1a;《2024最新Java面试题及答案&#xff08;带完整目录&#xff09;》 更多技术书籍&#xff1a;技术书籍分享&#xff0c;前端、后端、大数据、AI、人工智能... ​ ​ ​ 4.1.9.8. 可重入锁&#xff…

【KMP】优质模板推荐+解读

KMP – y神模板 引言&#xff1a;由于本人与4月20日前周五的一节数据结构课中偶然听到了老师讲kmp这个算法的概念并且发现老师讲的听不懂一点儿导致异常难受&#xff0c;于是花了两天左右自行弄懂了kmp算法的逻辑&#xff0c;并写下本文以便以后复习&#xff0c;并作留念。 声明…

数据结构10:堆和堆排序

文章目录 树的概念及结构树的概念树的相关概念树的表示树在实际中的应用表示文件系统的目录树结构 二叉树概念及结构概念特殊的二叉树二叉树的性质二叉树的存储结构顺序存储链式存储 二叉树的顺序结构及实现二叉树的顺序结构堆的概念及结构 堆的实现堆的插入堆的删除堆的创建向…

8.1 二叉排序树 —— C语言实现

系列文章目录 参考船说系列——数据结构与算法中的第八章内容。 二叉排序树AVL树红黑树B-树 文章目录 系列文章目录前言一、二叉排序树基础二、二叉排序树的操作2.1 插入2.2 删除 三、代码演示总结参考文献 前言 数据结构 结构定义 结构操作 结构操作是用来维护结构性质的…

spring高级篇(二)

1、Aware和InitializingBean Aware和InitializingBean都与Bean的生命周期管理相关。 Aware接口: 概念: Aware接口是Spring框架中的一个标记接口&#xff0c;它表示一个类能够感知到&#xff08;aware of&#xff09;Spring容器的存在及其特定的环境。Spring框架提供了多个Awar…

自然语言处理基础面试

文章目录 TF-IDFbag-of-wordsBert 讲道理肯定还得有Transformer&#xff0c;我这边先放着&#xff0c;以后再加吧。 TF-IDF TF&#xff08;全称TermFrequency&#xff09;&#xff0c;中文含义词频&#xff0c;简单理解就是关键词出现在网页当中的频次。 IDF&#xff08;全称…

【Pytorch】PytorchCPU版或GPU报错异常处理(10X~4090D)

Pytorch为CPU版或GPU使用报错异常处理 文章目录 Pytorch为CPU版或GPU使用报错异常处理0.检查阶段1. 在conda虚拟环境中安装了torch2.卸载cpuonly3.从tsinghua清华源安装不完善误为cpu版本4.用tsinghua清华源安装成cpu错误版本5.conda中torch/vision/cudatoolkit版本与本机cuda版…