数据结构——双向循环链表

二、双向循环链表

(一)双向循环链表的构造#

双向循环链表的首结点中的prev指针成员指向链表的尾结点,并且双向循环链表的尾结点里的next指针成员指向链表的首结点,所以双向循环链表也属于环形结构。

image

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)向双向循环链表头部添加新结点#

image

/************************************************************************************
 * 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)向双向循环链表尾部添加新结点#

image

/************************************************************************************
 * 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)根据目标值向双向循环链表任意地方添加新结点#

image

/************************************************************************************
 * 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)删除双向循环链表的首结点#

image

/************************************************************************************
 * 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 国际」许可协议进行许可。

posted @   子非予  阅读(543)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu