數據結構 雙向迴圈鏈表 雙向迴圈鏈表的增刪改查 /***************************************************************************************************************** * * file na ...
數據結構
雙向迴圈鏈表
雙向迴圈鏈表的增刪改查
/*****************************************************************************************************************
*
* file name : DoubleCirLinkedList.c
* author : [email protected]
* data : 2024/04/24
* function : 雙向迴圈鏈表的介面程式
* note : None
*
* CopyRight (c) 2024 [email protected] All Right Reseverd
*
* ****************************************************************************************************************/
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
//指的是雙向迴圈鏈表中的結點有效數據類型,用戶可以根據需要進行修改
typedef int DataType_t;
//構造雙向迴圈鏈表的結點,鏈表中所有結點的數據類型應該是相同的
typedef struct DoubleLinkedList
{
DataType_t data; //結點的數據域
struct DoubleLinkedList *prev; //直接前驅的指針域
struct DoubleLinkedList *next; //直接後繼的指針域
}DoubleLList_t;
//創建一個空雙向迴圈鏈表,空鏈表應該有一個頭結點,對鏈表進行初始化
DoubleLList_t * DoubleCirLList_Create(void)
{
//1.創建一個頭結點並對頭結點申請記憶體
DoubleLList_t *Head = (DoubleLList_t *)calloc(1,sizeof(DoubleLList_t));
if (NULL == Head)
{
perror("Calloc memory for Head is Failed");
exit(-1);
}
//2.對頭結點進行初始化,頭結點是不存儲數據域,指針域指向自身即可,體現“迴圈”
Head->prev = Head;
Head->next = Head;
//3.把頭結點的地址返回即可
return Head;
}
//創建新的結點,並對新結點進行初始化(數據域 + 指針域)
DoubleLList_t * DoubleCirLList_NewNode(DataType_t data)
{
//1.創建一個新結點並對新結點申請記憶體
DoubleLList_t *New = (DoubleLList_t *)calloc(1,sizeof(DoubleLList_t));
if (NULL == New)
{
perror("Calloc memory for NewNode is Failed");
return NULL;
}
//2.對新結點的數據域和指針域(2個)進行初始化,指針域指向結點自身,體現“迴圈”
New->data = data;
New->prev = New;
New->next = New;
return New;
}
/******************************************************************************************************************
*
* func name : DoubleCirLLinst_HeadInsert
* function : 把新結點插入雙向迴圈鏈表中的頭部
* retval : bool
* note : None
* author : [email protected]
* date : 2024/04/24
*
* ****************************************************************************************************************/
//頭插
bool DoubleCirLLinst_HeadInsert(DoubleLList_t *Head,DataType_t data)
{
//1.創建新結點,並對新結點進行初始化
DoubleLList_t *New = DoubleCirLList_NewNode(data);
if (NULL == New)
{
printf("Can not insert new node\n");
return false;
}
//2.判斷迴圈雙向鏈表是否為空,如果為空,則直接插入即可
if (Head->next == Head)
{
Head->next = New;
return true;
}
//3.如果迴圈雙向鏈表為非空,則把新結點插入鏈表頭部
Head->next->prev->next = New; //把尾結點的next指針指向新結點
New->prev = Head->next->prev; //把新結點的prev指針指向尾結點
New->next = Head->next; //把新結點的next指針指向原本首結點
Head->next->prev = New; //把原本首結點的prev指針指向新結點
Head->next = New; //把頭結點的next指針指向新結點
return true;
}
/******************************************************************************************************************
*
* func name : DoubleCirLLinst_TailInsert
* function : 把新結點插入雙向迴圈錶鏈中的尾部
* retval : bool
* note : None
* author : [email protected]
* date : 2024/04/24
*
* ****************************************************************************************************************/
//尾插
bool DoubleCirLLinst_TailInsert(DoubleLList_t *Head,DataType_t data)
{
//1.創建新結點,並對新結點進行初始化
DoubleLList_t *New = DoubleCirLList_NewNode(data);
if (NULL == New)
{
printf("Can not insert new node\n");
return false;
}
//2.判斷迴圈雙向鏈表是否為空,如果為空,則直接插入即可
if (Head->next == Head)
{
Head->next = New;
return true;
}
//3.如果迴圈雙向鏈表為非空,則把新結點插入鏈表頭部
New->prev= Head->next->prev; //把新結點的prev指針指向原本的尾結點
Head->next->prev->next = New; //把原本的尾結點的next指針指向新結點
New->next = Head->next; //把新結點的next指針指向首結點
Head->next->prev = New; //把首結點的prev指針指向新結點
return true;
}
/******************************************************************************************************************
*
* func name : DoubleCirLLinst_DestInsert
* function : 把新結點插入雙向迴圈鏈表中的指定元素的尾部
* retval : bool
* note : None
* author : [email protected]
* date : 2024/04/24
*
* ****************************************************************************************************************/
//指定插
bool DoubleCirLLinst_DestInsert(DoubleLList_t *Head,DataType_t destval,DataType_t data)
{
//1.創建新結點,並對新結點進行初始化
DoubleLList_t *New = DoubleCirLList_NewNode(data);
if (NULL == New)
{
printf("Can not insert new node\n");
return false;
}
//2.判斷迴圈雙向鏈表是否為空,如果為空,則直接插入即可
if (Head->next == Head)
{
Head->next = New;
return true;
}
//3.如果迴圈雙向鏈表為非空,則把新結點插入鏈表中指定元素的尾部
DoubleLList_t *Phead = Head->next; //備份首結點地址,防止首結點丟失
while (Phead->next != Head->next)
{
if (Phead->data == destval)
{
break;
}
Phead = Phead->next;
}
//如果遍歷鏈表之後發現沒有目標結點,則退出即可
if (Phead->next == Head->next && Phead->data != destval)
{
printf("dest node is not found\n");
return false;
}
//如果遍歷鏈表找到目標結點,則分為(頭部 or 尾部 or 中間)
// if (Phead == Head->next)
// {
// New->prev = Head->next; //把新結點的prev指針指向首結點
// New->next = Head->next; //把新結點的next指針指向首結點
// Head->next->next = New; //把首結點的next指針指向新結點
// Head->next->prev = New; //把首結點的prev指針指向新結點
// }
if (Phead->next == Head->next)
{
New->next = Head->next; //把新結點的next指針指向首結點
New->prev = Phead; //把新結點的prev指針指向原本的尾結點
Phead->next = New; //把原本的尾結點的next指針指向新結點
Head->next->prev = New; //把首結點的prev指針指向新結點
}else
{
New->next = Phead->next; //把新結點的next指針指向指定結點的直接後繼
Phead->next->prev = New; //把指定結點的直接後繼的prev指針指向新結點
New->prev = Phead; //把新結點的prev指針指向指定節點
Phead->next = New; //把指定節點的next指針指向新結點
}
return true;
}
/******************************************************************************************************************
*
* func name : DoubleCirLLinst_HeadDel
* function : 刪除雙向迴圈鏈表的頭部結點
* retval : bool
* note : None
* author : [email protected]
* date : 2024/04/24
*
* ****************************************************************************************************************/
//頭刪
bool DoubleCirLLinst_HeadDel(DoubleLList_t *Head)
{
//1.判斷當前鏈表是否為空,為空則直接退出
if (Head->next == Head)
{
printf("current linkedlist is empty!\n");
return false;
}
//2.判斷鏈表中是否只有首結點
if (Head->next == Head->next->next)
{
Head->next = Head; //頭結點的next指針指向頭結點,體現“迴圈”
free(Head->next); //釋放首結點記憶體
return true;
}
//3.如果當前鏈表為非空,則刪除當前鏈表的頭部結點
DoubleLList_t *Phead = Head->next; //備份首結點地址
Head->next->prev->next = Head->next->next; //把尾結點的next指針指向首結點的直接後繼
Head->next->next->prev = Head->next->prev; //把首結點的直接後繼的prev指針指向尾結點
Head->next =Phead->next; //把頭結點的next指針指向首結點的直接後繼
Phead->next = Phead; //把首結點的next指針指向首結點
Phead->prev = Phead; //把首結點的prev指針指向首結點
free(Phead); //釋放首結點記憶體
return true;
}
/******************************************************************************************************************
*
* func name : DoubleCirLLinst_TailDel
* function : 刪除雙向迴圈鏈表的尾部結點
* retval : bool
* note : None
* author : [email protected]
* date : 2024/04/24
*
* ****************************************************************************************************************/
//尾刪
bool DoubleCirLLinst_TailDel(DoubleLList_t *Head)
{
//1.判斷當前鏈表是否為空,為空則直接退出
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return false;
}
//2.判斷鏈表中是否只有首結點
if (Head->next == Head->next->next)
{
Head->next = Head; //頭結點的next指針指向頭結點,體現“迴圈”
free(Head->next); //釋放首結點記憶體
return true;
}
//3.如果當前鏈表為非空,則刪除當前鏈表的尾部結點
DoubleLList_t *Phead = Head->next->prev; //備份尾結點地址
Head->next->prev->prev->next = Head->next; //把尾結點的直接前驅的next指針指向首結點
Head->next->prev = Head->next->prev->prev; //把首結點的prev指針指向尾結點的直接前驅
Phead->next = Phead; //把尾結點的next指針指向尾結點
Phead->prev = Phead; //把尾結點的prev指針指向尾結點
free(Phead); //釋放尾結點記憶體
return true;
}
/******************************************************************************************************************
*
* func name : DoubleCirLLinst_DestDel
* function : 刪除雙向迴圈鏈表的指定結點
* retval : bool
* note : None
* author : [email protected]
* date : 2024/04/24
*
* ****************************************************************************************************************/
//指定刪
bool DoubleCirLLinst_DestDel(DoubleLList_t *Head,DataType_t destval)
{
//1.判斷當前鏈表是否為空,為空則直接退出
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return false;
}
//2.判斷鏈表中是否只有首結點
if (Head->next == Head->next->next)
{
Head->next = Head; //頭結點的next指針指向頭結點,體現“迴圈”
free(Head->next); //釋放首結點記憶體
return true;
}
//3.如果當前鏈表為非空,則刪除當前鏈表的指定結點
DoubleLList_t *Phead = Head->next; //備份首結點地址
while (Phead->next != Head->next)
{
if (Phead->data == destval)
{
break;
}
Phead = Phead->next;
}
//如果遍歷鏈表之後發現沒有目標結點,則退出即可
if (Phead->next == Head->next && Phead->data != destval)
{
printf("dest node is not found\n");
return false;
}
//如果遍歷鏈表找到目標結點,則分為(頭部 or 尾部 or 中間)
if (Phead == Head->next)
{
Head->next->prev->next = Head->next->next; //把尾結點的next指針指向首結點的直接後繼
Head->next->next->prev = Head->next->prev; //把首結點的直接後繼的prev指針指向尾結點
Head->next = Head->next->next; //把頭結點的next指針指向首結點的直接後繼
Phead->next = Phead; //把首結點的next指針指向首結點
Phead->prev = Phead; //把首結點的prev指針指向首結點
free(Phead); //釋放首結點記憶體
}else if (Phead->next == Head->next)
{
Phead->prev->next = Head->next; //把尾結點的直接前驅的next指針指向首結點
Head->next->prev = Phead->prev; //把首結點的prev指針指向尾結點的直接前驅
Phead->next = Phead; //把尾結點的next指針指向尾結點
Phead->prev = Phead; //把尾結點的prev指針指向尾結點
free(Phead); //釋放尾結點記憶體
}else
{
Phead->prev->next = Phead->next; //把指定結點的直接前驅的next指針指向指定結點的直接後繼
Phead->next->prev = Phead->prev; //把指定結點的直接後繼的prev指針指向指定結點的直接前驅
Phead->next = Phead; //把指定結點的next指針指向指定結點
Phead->prev = Phead; //把指定結點的prev指針指向指定結點
free(Phead); //釋放指定結點的記憶體
}
return true;
}
/******************************************************************************************************************
*
* func name : DoubleCirLLinst_Print
* function : 遍歷雙向迴圈鏈表並輸出鏈表中的數據域
* retval : bool
* note : None
* author : [email protected]
* date : 2024/04/24
*
* ****************************************************************************************************************/
//遍歷雙向迴圈鏈表
bool DoubleCirLLinst_Print(DoubleLList_t *Head)
{
//1.判斷當前雙向迴圈鏈表是否為空,為空則直接退出
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return false;
}
//2.從首結點開始遍歷鏈表
DoubleLList_t *Phead = Head; //備份頭結點地址,防止頭結點丟失
while (Phead->next)
{
Phead = Phead->next; //把頭結點的直接後繼作為新的頭結點
printf("%d->",Phead->data); //輸出頭結點的直接後繼的數據域
if (Phead->next == Head->next)//判斷是否到達尾結點,尾結點的next指針是指向首結點的地址
{
break;
}
}
return true;
}
int main(int argc, char const *argv[])
{
//創建雙向迴圈鏈表
DoubleLList_t *Head = DoubleCirLList_Create();
//頭插
DoubleCirLLinst_HeadInsert(Head,5);
DoubleCirLLinst_HeadInsert(Head,56);
DoubleCirLLinst_HeadInsert(Head,35);
DoubleCirLLinst_HeadInsert(Head,20);
DoubleCirLLinst_HeadInsert(Head,8);
DoubleCirLLinst_Print(Head);
printf("\n");
// //尾插
DoubleCirLLinst_TailInsert(Head,61);
DoubleCirLLinst_TailInsert(Head,9);
DoubleCirLLinst_TailInsert(Head,4);
DoubleCirLLinst_TailInsert(Head,18);
DoubleCirLLinst_TailInsert(Head,40);
DoubleCirLLinst_Print(Head);
printf("\n");
//指定插
DoubleCirLLinst_DestInsert(Head,5,21);
DoubleCirLLinst_DestInsert(Head,40,89);
DoubleCirLLinst_Print(Head);
printf("\n");
// 頭刪
DoubleCirLLinst_HeadDel(Head);
DoubleCirLLinst_HeadDel(Head);
DoubleCirLLinst_Print(Head);
printf("\n");
// 尾刪
DoubleCirLLinst_TailDel(Head);
DoubleCirLLinst_TailDel(Head);
DoubleCirLLinst_Print(Head);
printf("\n");
// //指定刪
DoubleCirLLinst_DestDel(Head,5);
DoubleCirLLinst_DestDel(Head,61);
DoubleCirLLinst_Print(Head);
printf("\n");
return 0;
}
結果驗證: