首页 > 其他分享 >双向循环链表

双向循环链表

时间:2024-04-23 21:56:05浏览次数:25  
标签:doubleLinkedList 结点 phead next 链表 循环 双向 head

小白感觉双向链表和单向链表的区别并不大,就是地址的交接有点繁琐,需要清晰的逻辑,简单理解就是俩条平行线,无线延伸,但是俩个线不交叉,但都是在一张纸上开始延展,头结点就像这张纸,理解的可能有点抽象,但我感觉这就是个抽象的概念,所以特编写初级的代码如下:

/*****************************************************************
*
*      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;
}

已经经过测试验证并成功,测试结果如代码的测试结果一致,如图:

image

虽然和上次的单向循环链表结果相同,主要是我测试的数据一样,嘿嘿嘿,偷了个懒,还有不少作业要做呢,希望以上的代码能对同是初学者的你有所帮助

标签:doubleLinkedList,结点,phead,next,链表,循环,双向,head
From: https://www.cnblogs.com/xiaobaibudongjiuwen/p/18153844

相关文章

  • 单向循环链表的初体验
    单向循环链表经过小白今天一天的学习,感觉就是在单向链表的尾结点加了一个首结点的地址,不再指向NULL,个人理解就像一群孩子围成了一个圆,头尾相连,同时多少个孩子就是多少个结点,如击鼓传花一般一个个将手上的手绢传递给下一个人,一遍下来就像是单向循环的遍历,想要到谁的手上,就像是指定......
  • 单向循环链表
    //头插boolCircLList_HeadInsert(CircLList_t*Head,DataType_tdata){ //创建一个新节点 CircLList_t*New=CircLList_NewNode(data); //对单向循环链表的头结点的地址进行备份 CircLList_t*Phead=Head; //判断当前链表是否为空,就直接插入 if(Head->next==He......
  • 单向循环链表的接口程序
    自定义单向循环链表的增删改查接口函数/********************************************************************文件名称: 01单向循环链表的接口程序文件作者:[email protected]创建日期:2024/04/23文件功能:对单向循环链表的增删改查功能的定义注意事项:......
  • 单向循环链表——查找、删除、插入结点
    /********************************************************************* filename: CircularLinkedList.c* author :Dazz* date :2024/04/23* function:用于学习单向循环链表,并添加插入、删除、查找结点等函数* note :None** CopyRight(c)202......
  • 单向循环链表(其一)
    单向循环链表(其一)单向循环链表的原理与应用:单向循环的链表的使用规则和普通的单向链表没有较大的区别,需要注意:*单向循环链表的尾结点的指针域中必须指向链表的首结点的地址*,由于带头结点的单向循环链表更加容易进行管理,如下图所示:上图所示的就是一个典型的单向循环链表的结构,......
  • 设计单向循环链表的接口
    /***********************************************************************************filename:003_单向循环链表.cauthor:[email protected]:2024/04/23function:设计单向循环链表的接口note:......
  • 单项循环链表的头插、尾插、中间插、头删、尾删、中间删
    单项循环链表的头插、尾插、中间插、头删、尾删、中间删/******************************************************************** author :[email protected]* date :2024/04/23* function:单项循环链表的头插、尾插、中间插、头删、尾删、中间删* note :Non......
  • 数据结构:单循环链表的创建插入与删除
    数据结构:单循环链表的创建·插入·删除/***@filename: 单循环链表的创建·插入·删除*@brief实现单循环链表的创建删除插入的功能*@[email protected]*@date2024/04/23*@version1.0:版本*@notenoone*CopyRight(c)2023-2024liuliu@......
  • 单向循环链表的接口程序
    /**@filename: main.c@brief单向循环链表的接口程序@[email protected]@date2024/04/[email protected]:版本@property:属性介绍@note补充注意说明CopyRight(c)[email protected]*/include<stdio.h>include......
  • 链表的查找操作例题
    代码/********************************************name:find*function:查找链表倒数第k位置的结点*argument:@head:头指针@k:链表倒数第k位置的结点数*retval:None*date:2024/04/22*note:Note*********************......