小白感觉双向链表和单向链表的区别并不大,就是地址的交接有点繁琐,需要清晰的逻辑,简单理解就是俩条平行线,无线延伸,但是俩个线不交叉,但都是在一张纸上开始延展,头结点就像这张纸,理解的可能有点抽象,但我感觉这就是个抽象的概念,所以特编写初级的代码如下:
/*****************************************************************
*
* file name :DoubleLinkedList.c
* authour :[email protected]
* date :2024/04/23
* function :设计一个函数,实现对双向链表的增删改查的功能。
* note :None
* CopyRight (c) 2024 [email protected] All Right Reseverd
*
******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int DataType_t;
//定义一个链表结构体,分别存储数据域和指针域
typedef struct doubleLinkedList
{
DataType_t data; // 数据域
struct doubleLinkedList *next; // 指针域
struct doubleLinkedList *prev;
}doubLList_t;
/*******************************************************************
*
* name : doubleLinkedList_creat
* function : 创建一个空链表并创建一个头结点,并进行初始化
* argument :
* retval : None
* author : [email protected]
* date : 2024/04/22
* note : None
*
* *****************************************************************/
//创建空链表,并创建一个头结点
doubLList_t * doubleLinkedList_creat()
{
doubLList_t *head = (doubLList_t *)calloc(1,sizeof(doubLList_t)); //calloc来申请不需要初始化更方便
if(NULL == head)
{
perror("calloc head is error\n"); // 分配内存失败
exit(1);
}
head->next = NULL; //头结点next初始化
head->prev = NULL; //头结点prev初始化
}
/*******************************************************************
*
* name : doubleLinkedList_NewNode
* function : 创建一新的双向链表结点,并对新结点初始化
* argument : @data 新结点的数据域的数据
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : 此函数不单独使用,需要配合Insert函数使用
*
* *****************************************************************/
doubLList_t * doubleLinkedList_NewNode(DataType_t data)
{
doubLList_t *New =(doubLList_t *)malloc(sizeof(doubLList_t));
if(NULL == New)
{
perror("calloc NewNode is error\n"); // 分配内存失败
return NULL;
}
New->data = data; //新结点数据域初始化
New->next = NULL; //新结点指针域next初始化
New->prev = NULL; //新结点指针域prev初始化
}
/*******************************************************************
*
* name : doubleLinkedList_HeadInsert
* function : 结点在头部插入
* argument : @data 要插入的结点的数据域的数据
* @head 链表的头结点
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : 要判断此链表是否为空,为空则直接在头结点后面插入
*
* *****************************************************************/
bool doubleLinkedList_HeadInsert(doubLList_t *head,DataType_t data)
{
doubLList_t *New = doubleLinkedList_NewNode(data);
if(NULL == New) //判断新节点是否创建成功
{
printf("calloc NewNode is failed\n");
return false;
}
if(NULL == head->next) //判断链表是否为空,则直接插入
{
head->next = New;
return true;
}
New->next = head->next;
head->next->prev = New;
head->next = New;
return true;
}
//尾插
/*******************************************************************
*
* name : doubleLinkedList_TailInsert
* function : 结点在尾部插入
* argument : @data 要插入的结点的数据域的数据
* @head 链表的头结点
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : 要判断此链表是否为空,为空则直接在头结点后面插入,尾结点指向NULL
*
* *****************************************************************/
bool doubleLinkedList_TailInsert(doubLList_t *head,DataType_t data)
{
doubLList_t *phead = head; // 备份头结点
doubLList_t *New = doubleLinkedList_NewNode(data);
if(NULL == New) //判断新节点是否创建成功
{
printf("calloc NewNode is failed\n");
return false;
}
if(NULL == head->next) //判断链表是否为空,则直接插入
{
head->next = New;
return true;
}
while(phead->next)
{
phead = phead->next; // 遍历链表
}
phead->next = New;
New->prev = phead;
return true;
}
//中间插
/*******************************************************************
*
* name : doubleLinkedList_DestInsert
* function : 结点在指定位置后插入
* argument : @data 指定结点的数据域的数据
* @value 要插入新的结点的数据域的数据
* @head 链表的头结点
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : None
*
* *****************************************************************/
bool doubleLinkedList_DestInsert(doubLList_t *head,DataType_t data,DataType_t value)
{
doubLList_t *phead = head; // 备份头结点
doubLList_t *p = head; // 备份头结点
doubLList_t *New = doubleLinkedList_NewNode(value);
if(NULL == New) //判断新节点是否创建成功
{
printf("calloc NewNode is failed\n");
return false;
}
if(NULL == head->next) //判断链表是否为空,则直接插入
{
head->next = New;
return true;
}
while(phead->next && phead->data != data) //再循环再次到尾巴结点时退出,说明没有该数据
{
phead = phead->next; // 遍历链表,找到和data相同的节点时(phead)退出,
}
if(phead == NULL) //当phead == NULL导致退出时,则没找该data,函数直接退出
{
printf("not found this data\n");
return false;
}
New->next = phead->next; //将指定插入结点的直接后继的地址给新节点的next
phead->next->prev = New; //将New的地址给指定插入结点的直接后继的prev
phead->next = New; //将新节点的地址给指定插入结点的next
New->prev = phead; //将指定插入结点的地址给新节点的prev
return true;
}
//删除指定节点
/*******************************************************************
*
* name : doubleLinkedList_DestDelete
* function : 删除指定位置的结点
* argument : @data 指定结点的数据域的数据
* @head 链表的头结点
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : None
*
* *****************************************************************/
bool doubleLinkedList_DestDelete(doubLList_t *head,DataType_t data)
{
if(NULL == head->next) //判断链表是否为空,为空直接退出
{
printf("doubLinkedList is empty\n");
return false;
}
doubLList_t *phead = head->next; // 备份头结点
doubLList_t *p = head; // 备份头结点
while(phead->next && phead->data != data) //再循环再次到尾巴结点时退出,说明没有该数据
{
phead = phead->next; // 遍历链表,找到和data相同的节点时(phead)退出,
}
if(phead == NULL) //当phead == NULL导致退出时,则没找该data,函数直接退出
{
printf("not found this data\n");
return false;
}
phead->prev->next = phead->next; //将指定的结点的next赋值给指定结点的直接前驱的next
phead->next->prev = phead->prev; //对删除的结点释放,防止内存泄漏,以及段错误
phead->next = NULL; //将指定删除结点的next指向NULL;
phead->prev = NULL; //将指定删除结点的prev指向NULL;
free(phead);
return true;
}
//删除首节点
/*******************************************************************
*
* name : doubleLinkedList_HeadDelete
* function : 删除首结点
* argument : @data 指定结点的数据域的数据
* @head 链表的头结点
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : None
*
* *****************************************************************/
bool doubleLinkedList_HeadDelete(doubLList_t *head)
{
if(NULL == head->next) //判断链表是否为空,为空直接退出
{
printf("doubleLinkedList is empty\n");
return false;
}
doubLList_t *phead = head->next; // 备份首结点
head->next = phead->next; //将首结点的直接后继地址给头结点
phead->next->prev = head; //将头结点的地址给首结点的直接后继的prev
phead->next = NULL; //对删除的结点释放,防止内存泄漏,以及段错误
free(phead);
return true;
}
//删除尾节点
/*******************************************************************
*
* name : doubleLinkedList_TailDelete
* function : 删除尾结点
* argument : @data 指定结点的数据域的数据
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : None
*
* *****************************************************************/
bool doubleLinkedList_TailDelete(doubLList_t *head)
{
int i = 0;
if(NULL == head->next) //判断链表是否为空,为空直接退出
{
printf("doubLinkedList is empty\n");
return false;
}
doubLList_t *phead = head; // 备份头结点
doubLList_t *p = head; // 备份头结点
while(phead->next)
{
phead = phead->next; // 遍历链表
}
phead->prev->next = NULL; //尾结点的直接前驱的next指向NULL,断开最后一个节点
phead->prev = NULL; //尾结点的prev指向NULL,与直接前驱断开
free(phead); //对删除的结点释放,防止内存泄漏,以及段错误
return true;
}
//打印链表
/*******************************************************************
*
* name : doubleLinkedList_Print
* function : 遍历双向链表,并打印各结点的数据域
* argument : @data 指定结点的数据域的数据
* retval : None
* author : [email protected]
* date : 2024/04/23
* note : None
*
* *****************************************************************/
void doubleLinkedList_Print(doubLList_t *head)
{
doubLList_t *phead = head; // 备份头结点
while(phead->next)
{
phead = phead->next; // 遍历链表
printf(" %d",phead->data); // 打印链表
}
printf("\n");
}
int main()
{
doubLList_t * Head = doubleLinkedList_creat();
doubleLinkedList_HeadInsert(Head,8);
doubleLinkedList_HeadInsert(Head,5);
doubleLinkedList_HeadInsert(Head,3);
doubleLinkedList_HeadInsert(Head,7);
doubleLinkedList_Print(Head); //7 3 5 8
doubleLinkedList_TailInsert(Head,42);
doubleLinkedList_TailInsert(Head,99);
doubleLinkedList_TailInsert(Head,87);
doubleLinkedList_TailInsert(Head,63);
doubleLinkedList_Print(Head); //7 3 5 8 42 99 87 63
doubleLinkedList_DestInsert(Head,42,11);
doubleLinkedList_DestInsert(Head,3,33);
doubleLinkedList_DestInsert(Head,87,61);
doubleLinkedList_Print(Head); //7 3 33 5 8 42 11 99 87 61 63
doubleLinkedList_DestDelete(Head,42);
doubleLinkedList_Print(Head);
doubleLinkedList_HeadDelete(Head);
doubleLinkedList_Print(Head);
doubleLinkedList_TailDelete(Head);
doubleLinkedList_Print(Head);// 3 33 5 8 11 99 87 61
return 0;
}
已经经过测试验证并成功,测试结果如代码的测试结果一致,如图:
虽然和上次的单向循环链表结果相同,主要是我测试的数据一样,嘿嘿嘿,偷了个懒,还有不少作业要做呢,希望以上的代码能对同是初学者的你有所帮助
标签:doubleLinkedList,结点,phead,next,链表,循环,双向,head From: https://www.cnblogs.com/xiaobaibudongjiuwen/p/18153844