如果想要提高单向链表或者单项循环链表的访问速度,则可以在链表中的节点中再添加一个指针域,让新添加的指针域指向当前节点的直接前驱的地址,也就意味着一个节点中有两个指针域(prev+next),也被称为双向链表(Double Linked List)

double_linked_list.h
/**
* @file : doublellist.h
* @brief : 实现双链表的创建、添加、删除、遍历
* @author : TingFengLuo@126.com
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note :双向链表节点有两个指针域(前指针和后指针),
前指针指向前一个节点的地址,后指针指向后一个节点的地址还有,一个数据域,用于存放数据,双向链表包含一个头指针指向首节点,便于管理链表
*/
#ifndef __DOUBLELLIST_H
#define __DOUBLELLIST_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//将int类型改名为Datatype_t,便于后续用户修改
typedef int Datatype_t;
//定义双向链表类型
typedef struct doublelinkedlist{
Datatype_t data;
struct doublelinkedlist *prev;
struct doublelinkedlist *next;
}doublellist_t;
//双链表的创建
doublellist_t * DoubleLList_create(void);
//双链表创建新节点
doublellist_t * Doublellist_NewNode(Datatype_t data);
//双链表的头部插入
bool Doublellist_HeadAdd(doublellist_t *head,Datatype_t data);
//双链表的目标值后面插入
bool Doulellist_DestAdd(doublellist_t *head,Datatype_t dest,Datatype_t data);
//双链表的尾部插入
bool Doublellist_TailAdd(doublellist_t *head,Datatype_t data);
//双向链表头部删除
bool Doublellist_HeadDel(doublellist_t *head);
//双向链表目标值删除
bool Doublellist_DestDel(doublellist_t *head,Datatype_t dest);
//双向链表尾部删除
bool Doublellist_TailDel(doublellist_t *head);
//遍历双向循环链表
void Doublellist_show(doublellist_t *head);
#endif
double_linked_list.c
#include "doublellist.h"
/**
* @name : DoubleLList_create
* @brief : 实现双向链表的创建
* @param : void
* @retval : 链表创建成功返回双链表的地址,创建失败,直接退出程序
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : 双链表的创建有一个头头节点,头节点的前指针和后指针都指向空,头指针没有数据域
*/
doublellist_t * DoubleLList_create(void)
{
//定义一个头指针,并对头指针创建存储空间
doublellist_t *head = (doublellist_t *)calloc(1,sizeof(doublellist_t));
//判断头节点是否创建成功,如果失败直接退出程序
if(NULL == head){
perror("create memory falied for head");
exit(-1);
}
//初始化头节点的指针域
head->prev = NULL;
head->next = NULL;
//返回头节点的地址
return head;
}
/**
* @name : Doublellist_NewNode
* @brief : 实现双向链表节点的创建
* @param
@data : 要传输的数据
* @retval : 返回新节点的地址
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
doublellist_t * Doublellist_NewNode(Datatype_t data)
{
//创建一个新节点
doublellist_t *new_node = (doublellist_t *)calloc(1,sizeof(doublellist_t));
//如果新节点创建失败,返回NULL
if(NULL == new_node){
perror("create memory failed for new_node");
return NULL;
}
new_node->data = data;
//将新节点的前后指针域指向NULL
new_node->prev = NULL;
new_node->next = NULL;
return new_node;
}
/**
* @name : Doublellist_HeadAdd
* @brief : 实现双向链表头节点的插入
* @param
@head :表示哪一个链表
@data : 要传输的数据
* @retval : 插入成功返回true,插入失败返回false
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
bool Doublellist_HeadAdd(doublellist_t *head,Datatype_t data)
{
//用于一个指针存储新节点的地址
doublellist_t *new_node = Doublellist_NewNode(data);
//判断新节点是否创建成功,如果new_node的地址为空,说明新节点创建失败,返回false
if(NULL == new_node){
printf("create new node falied\n");
return false;
}
//判断头节点的下一个地址是否为空,如果为空,直接在双向链表后插入
if(NULL == head->next){
new_node->prev = head;
head->next = new_node;
return true;
}
//如果链表不为空,新节点的next指针指向头节点的下一个地址
new_node->next = head->next;
//新节点的prev指针指向头节点
new_node->prev = head;
//之前的首节点的prev指针指向新节点
head->next->prev = new_node;
//头节点的next指针指向新节点
head->next = new_node;
return true;
}
/**
* @name : Doulellist_DestAdd
* @brief : 实现双向链表目标值后面插入新节点
* @param
@head :表示哪一个链表
@dest :需要找到的目标值
@data : 要传输的数据
* @retval : 插入成功返回true,插入失败返回false
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
bool Doulellist_DestAdd(doublellist_t *head,Datatype_t dest,Datatype_t data)
{
//定义变量存储新节点的地址
doublellist_t *new_node = Doublellist_NewNode(data);
//判断新节点是否创建出来
if(NULL == new_node){
printf("double linked list create new node failed\n");
return false;
}
//判断head是否存在
if(NULL == head){
printf("double linked list is Empty!!!\n");
return false;
}
//判断链表是否为空,如果为空直接在头节点后面插入
if(NULL == head->next){
new_node->prev = head;
head->next = new_node;
return true;
}
//定义变量用于存储插入节点的前一个地址
doublellist_t *phead = head->next;
//遍历节点找到目标值节点,然后将新节点插入
//判断当前节点是否为空
while(phead != NULL){
//如果当前节点的值与dest相同,在后面插入
if(phead->data == dest)
{
new_node->next = phead->next;
new_node->prev = phead;
//判断当前节点的Next指针是否为空
if(phead->next != NULL){
phead->next->prev = new_node;
}
phead->next = new_node;
//插入成功返回true
return true;
}
//当前指针指向下一个节点
phead = phead->next;
}
//当前节点为空,释放新节点,返回false
printf("double linked list do not dest value = %d\n",dest);
free(new_node);
return false;
}
/**
* @name : Doublellist_TailAdd
* @brief : 实现双向链表尾节点的插入
* @param
@head : 表示哪一个链表
@data : 要传输的数据
* @retval : 尾部插入成功返回true,失败返回false
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
bool Doublellist_TailAdd(doublellist_t *head,Datatype_t data)
{
//定义变量存储新节点的地址
doublellist_t *new_node = Doublellist_NewNode(data);
if(NULL == new_node){
printf("double linked list create new node failed\n");
return false;
}
//判断链表是否存在
if(NULL == head){
printf("create double linked list failed\n");
return false;
}
//判断链表是否为空,如果为空直接在头部添加
if(NULL == head->next){
new_node->prev = head;
head->next = new_node;
return true;
}
//创建变量用于遍历链表
doublellist_t *tail = head;
//如果不为空,先找到尾节点
while(NULL != tail->next){
tail = tail->next;
}
new_node->prev = tail;
tail->next = new_node;
return true;
}
/**
* @name : Doublellist_HeadDel
* @brief : 实现双向链表头部删除
* @param
@head : 表示哪一个链表
* @retval : 头部删除成功返回true,失败返回false
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
bool Doublellist_HeadDel(doublellist_t *head)
{
//判断头节点是否创建成功
if(NULL == head){
printf("create double linked list failed\n");
return false;
}
//判断链表是否为空
if(NULL == head->next){
printf("current linked list is Empty!!!\n");
return false;
}
//创建变量存储首节点的地址
doublellist_t *phead = head->next;
//判断链表是否只有一个首节点,如果只有一个首节点,直接将head的next指向NULL
if(phead->next == NULL){
head->next = NULL;
}else{
//如果不为空,直接删除首节点
head->next = phead->next;
phead->next->prev = head;
}
//将删除的首节点的前后指针置空,防止野指针
phead->prev = NULL;
phead->next = NULL;
//释放phead的内存
free(phead);
//避免野指针
phead = NULL;
return true;
}
/**
* @name : Doublellist_DestDel
* @brief : 实现双向链表目标值删除
* @param
@head : 表示哪一个链表
@dest : 表示要删除的目标值
* @retval : 目标值删除成功返回true,失败返回false
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
bool Doublellist_DestDel(doublellist_t *head,Datatype_t dest)
{
//判断头节点是否创建成功
if(NULL == head){
printf("create double linked list failed\n");
return false;
}
//判断链表是否为空
if(NULL == head->next){
printf("current linked list is Empty!!!\n");
return false;
}
//创建变量存储目标节点前一个节点的地址
doublellist_t *prev_destnode = head;
//创建变量存储目标节点的地址
doublellist_t *dest_node = head->next;
//遍历链表,找到第一个与目标值相同的节点
while(NULL != dest_node){
if(dest == dest_node->data){
prev_destnode->next = dest_node->next;
if(dest_node->next != NULL){
dest_node->next->prev = prev_destnode;
}
dest_node->prev = NULL;
dest_node->next = NULL;
free(dest_node);
dest_node = NULL;
return true;
}
prev_destnode = dest_node;
dest_node = dest_node->next;
}
printf("double linked list do not have dest value = %d!!!\n",dest);
return false;
}
/**
* @name : Doublellist_TailDel
* @brief : 实现双向链表尾部删除
* @param
@head : 表示哪一个链表
* @retval : 头部删除成功返回true,失败返回false
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
bool Doublellist_TailDel(doublellist_t *head)
{
//判断头节点是否创建成功
if(NULL == head){
printf("create double linked list failed\n");
return false;
}
//判断链表是否为空
if(NULL == head->next){
printf("current linked list is Empty!!!\n");
return false;
}
//创建变量存储尾节点
doublellist_t *phead = head->next;
//创建变量存储删除节点的前一个节点
doublellist_t *prev_phead = head;
//遍历链表,找到尾节点和尾节点的前一个节点
while(phead->next != NULL){
prev_phead = phead;
phead = phead->next;
}
//置空指针,防止野指针
prev_phead->next = NULL;
phead->prev = NULL;
free(phead);
//防止野指针
phead = NULL;
return true;
}
/**
* @name : Doublellist_show
* @brief : 实现双向链表的遍历
* @param
@head : 表示是哪个链表
* @retval : void
* @date : 2025-12-16
* @version 1.0 : v1.0
* @note : NULL
*/
void Doublellist_show(doublellist_t *head)
{
if(NULL == head){
printf("double linked list do not have head\n");
return;
}
if(head->next == NULL){
printf("double linked list is empty!!!\n");
printf("please Add new node in double linked list!!!!\n");
return;
}
//创建变量用来遍历链表
doublellist_t *phead = head;
//遍历每个节点的值,如果phead的next指针为空则退出循环
while(phead->next != NULL){
phead = phead->next;
printf("current node vlaue = %d\n",phead->data);
}
}
main.c
#include "doublellist.h"
int main(int argc,char const *argv[]){
//定义变量用来存储创建双向链表的地址
doublellist_t *head = DoubleLList_create();
if(head == NULL){
printf("create double linked list falied\n");
return -1;
}
Doublellist_show(head);
printf("-------------------------------------------------------------\n");
Doublellist_HeadAdd(head,34);
Doublellist_HeadAdd(head,68);
Doublellist_HeadAdd(head,29);
Doublellist_HeadAdd(head,76);
Doublellist_HeadAdd(head,17);
Doublellist_show(head);
printf("-------------------------------------------------------------\n");
Doulellist_DestAdd(head,34,20);
Doulellist_DestAdd(head,68,46);
Doublellist_show(head);
printf("-------------------------------------------------------------\n");
Doublellist_TailAdd(head,50);
Doublellist_TailAdd(head,51);
Doublellist_TailAdd(head,52);
Doublellist_show(head);
printf("-------------------------------------------------------------\n");
Doublellist_HeadDel(head);
Doublellist_HeadDel(head);
Doublellist_HeadDel(head);
Doublellist_show(head);
printf("-------------------------------------------------------------\n");
Doublellist_DestDel(head,68);
Doublellist_DestDel(head,20);
Doublellist_DestDel(head,52);
Doublellist_DestDel(head,10);
Doublellist_show(head);
printf("-------------------------------------------------------------\n");
Doublellist_TailDel(head);
Doublellist_show(head);
printf("-------------------------------------------------------------\n");
return 0;
}
发表回复