数据结构——双向循环链表
二、双向循环链表
(一)双向循环链表的构造#
双向循环链表的首结点中的prev指针成员指向链表的尾结点,并且双向循环链表的尾结点里的next指针成员指向链表的首结点,所以双向循环链表也属于环形结构。
1)构造双向循环链表的结点#
//双向链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;
//构造双向链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct DouCircularLinkedList
{
DataType_t data; //结点的数据域
struct DouCircularLinkedList *prev; //直接前驱的指针域
struct DouCircularLinkedList *next; //直接后继的指针域
}DouCLList_t;
2)创建空双向循环链表的head#
/************************************************************************************
* name : DouGRList_Create
* function :创建一个空双向循环链表,空链表应该有一个头结点,对链表进行初始化
* argument : None
* retval : @head:返回头结点的地址
* date : 2024/04/25
* note : Note
************************************************************************************/
DouGRList_t * DouGRList_Create()
{
//创建一个头结点并对头结点申请内存
DouGRList_t *head = (DouGRList_t *)calloc(1,sizeof(DouGRList_t));
if (NULL == head){
perror("Calloc memory for Head is Failed");
exit(-1);
}
//对头结点进行初始化,头结点是不存储数据域,指针域指向自身
head->prev = head;
head->next = head;
return head;
}
3)创建双向循环链表的新结点
/************************************************************************************
* name : DouGRList_NewNode
* function :创建新的结点,并对新结点进行初始化(数据域 + 指针域)
* argument : @data :新结点数据域存储的数据
* retval : @newNode:返回新结点的地址
* date : 2024/04/25
* note : Note
************************************************************************************/
DouGRList_t * DouGRList_NewNode(DataType_t data)
{
DouGRList_t *newNode = (DouGRList_t *)calloc(1,sizeof(DouGRList_t));
if (NULL == newNode){
perror("Calloc memory for NewNode is Failed");
return NULL;
}
//对新结点的数据域和指针域(2个)进行初始化
newNode->data = data;
newNode->prev = newNode;
newNode->next = newNode;
return newNode;
}
(二)双向循环链表操作(方法)#
1)向双向循环链表头部添加新结点#
/************************************************************************************
* name : DouGRList_headIns
* function :向链表头部添加新结点
* argument : @head:双向循环链表头结点地址
* @data:新结点数据域的数据
* retval : None
* date : 2024/04/25
* note : Note
************************************************************************************/
bool DouGRList_headIns(DouGRList_t *head, DataType_t data)
{
DouGRList_t *newNode = DouGRList_NewNode(data);
DouGRList_t *temp = head->next;
//链表为空
if(head == head->next){
head->next = newNode;
return true;
}
//链表非空的情况,链表就有且只有一个首结点情况(后续看能否这两种情况能用同一代码实现否)
if(head->next == temp->next){
//新结点先链接首结点
newNode->prev = temp;
newNode->next = temp;
//首结点链接新结点
temp->prev = newNode;
temp->next =newNode;
//头结点链接新结点
head->next = newNode;
} else{
//新结点先链接首结点和尾结点
newNode->prev = temp->prev;
newNode->next = temp;
//尾结点的next链接新结点,断链首结点
temp->prev->next = newNode;
//首结点的prev链接新结点,断链尾结点
temp->prev = newNode;
//头结点链接新结点
head->next = newNode;
}
return true;
}
2)向双向循环链表尾部添加新结点#
/************************************************************************************
* name : DouGRList_endIns
* function :向链表尾部添加新结点
* argument : @head:双向循环链表头结点地址
* @data:新结点数据域的数据
* retval : None
* date : 2024/04/25
* note : Note
************************************************************************************/
bool DouGRList_endIns(DouGRList_t *head, DataType_t data)
{
DouGRList_t *newNode = DouGRList_NewNode(data);
DouGRList_t *temp = head->next;
//链表为空
if (head == head->next) {
head->next = newNode;
} else {
//链表非空的情况,新结点先链接首结点和尾结点
newNode->prev = temp->prev;
newNode->next = temp;
//尾结点的next链接新结点,断链首结点
temp->prev->next = newNode;
//首结点的prev链接新结点,断链尾结点
temp->prev = newNode;
}
return true;
}
3)根据目标值向双向循环链表任意地方添加新结点#
/************************************************************************************
* name : DouGRList_Insert
* function :向链表目标值destval后面添加新结点
* argument : @head :双向循环链表头结点地址
* @destval :目标值
* @data :新结点数据域的数据
* retval : None
* date : 2024/04/23
* note : Note
************************************************************************************/
bool DouGRList_Insert(DouGRList_t *head, DataType_t destval, DataType_t data)
{
DouGRList_t *newNode = DouGRList_NewNode(data);
DouGRList_t *temp = head->next;
//链表为空情况,不能根据目标值destval找到要添加的地方
if (head == head->next) {
perror("The place you want to add is not found in the linked list");
return true;
}
while (destval != temp->data){
//链表有且只有首结点或着循环到尾都没找到就break了
if(head->next == temp->next) {
perror("The place you want to add is not found in the linked list");
return true;
}
temp = temp->next;
}
//根据目标值destval找到了添加的位置
//新结点先链接首结点和尾结点
newNode->next = temp->next;
newNode->prev = temp;
temp->prev = newNode;
temp->next = newNode;
return true;
}
4)删除双向循环链表的首结点#
/************************************************************************************
* name : DouGRList_headDel
* function :删除双向循环链表的首结点
* argument : @head:双向循环链表头结点地址
* retval : None
* date : 2024/04/23
* note : Note
************************************************************************************/
bool DouGRList_headDel(DouGRList_t *head)
{
DouGRList_t *temp = head->next;
//链表为空情况,没得删
if (head == head->next) {
perror("The list is empty and does not have a head node");
return true;
}
//链表不为空的情况,链表有且只有首结点的情况
if (head->next == temp->next) {
head->next = head;
temp->next = NULL;
temp->prev = NULL;
free(temp);
} else {
head->next = temp->next;
head->next->prev = temp->prev;
temp->prev->next = head->next;
temp->next = NULL;
temp->prev = NULL;
free(temp);
}
return true;
}
作者:Mr--Song
出处:https://www.cnblogs.com/Mr--Song/p/18158379
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律