双向循环链表

/********************************************************************************
*

  • file name: DoublecirCulateLinkedList.c
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • function : 双向循环链表
  • note : None
  • CopyRight (c) 2023-2024 yxw18679428019@163.com All Right Reseverd
  • ****************************************************************************/

include <stdio.h>

include <stdlib.h>

include <stdbool.h>

// 指的是双向循环链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;

// 构造双向循环链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct DoublecirCulateLinkedList
{
DataType_t data; // 结点的数据域
struct DoublecirCulateLinkedList *prev; // 直接前驱的指针域
struct DoublecirCulateLinkedList *next; // 直接后继的指针域

} DoubleCirLList_t;

/*******************************************************************************

  • name : DoubleCirLList_Create
  • function : 创建一个空双向循环链表,空链表应该有一个头结点,对链表进行初始化
  • argument : None
  • retval : 返回头结点的地址
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    DoubleCirLList_t *DoubleCirLList_Create(void)
    {
    // 1.创建一个头结点并对头结点申请内存
    DoubleCirLList_t *Head = (DoubleCirLList_t *)calloc(1, sizeof(DoubleCirLList_t));
    if (NULL == Head)
    {
    perror("Calloc memory for Head is Failed");
    exit(-1);
    }
// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向自身即可,体现“循环”
Head->prev = Head;
Head->next = Head;

// 3.把头结点的地址返回即可
return Head;

}

/*******************************************************************************

  • name : DoubleCirLList_NewNode
  • function : 创建新的结点,并对新结点进行初始化(数据域 + 指针域)
  • argument : None
  • retval : 返回新结点的地址
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    DoubleCirLList_t *DoubleCirLList_NewNode(DataType_t data)
    {
    // 1.创建一个新结点并对新结点申请内存
    DoubleCirLList_t *New = (DoubleCirLList_t *)calloc(1, sizeof(DoubleCirLList_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;

}

/*******************************************************************************

  • name : DoubleCirLList_HeadInsert
  • function : 头部插入结点
  • argument :
  •          @Head :头结点的地址
    
  •          @data :插入结点的数据
    
  • retval : true and false
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    bool DoubleCirLList_HeadInsert(DoubleCirLList_t *Head, DataType_t data)
    {
    DoubleCirLList_t *Phead = Head->next; // 备份新首结点的地址
    // 创建新的结点并对结点进行初始化
    DoubleCirLList_t *New = DoubleCirLList_NewNode(data);
    if (NULL == New)
    {
    printf("can not insert New Node");
    return false;
    }
// 判断链表是否为空
if (Head->next == Head)
{
    Head->next = New;
    return true;
}

// 链表不为空
Phead->prev->next = New; // 尾结点的next指针指向新结点
New->prev = Phead->prev; // 新结点的prev指针指向尾结点
New->next = Phead;       // 新结点的next指针指向首结点
Phead->prev = New;       // 首结点的prev指针指向新结点
Head->next = New;        // 头结点的next指针指向新结点
return true;

}

/*******************************************************************************

  • name : DoubleCirLList_TailInsert
  • function : 尾部插入结点
  • argument :
  •          @Head :头结点的地址
    
  •          @data :插入结点的数据
    
  • retval : true and false
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    bool DoubleCirLList_TailInsert(DoubleCirLList_t *Head, DataType_t data)
    {
// 创建新的结点并对结点进行初始化
DoubleCirLList_t *New = DoubleCirLList_NewNode(data);
if (NULL == New)
{
    printf("can not insert New Node");
    return false;
}

// 判断链表是否为空,则直接插入到首结点后
if (Head->next == Head)
{
    Head->next = New;
    return true;
}

// 链表不为空
New->prev = Head->next->prev; // 新结点的perv指针指向尾结点
Head->next->prev->next = New; // 把尾结点的next指针指向新结点
New->next = Head->next;       // 新结点的next指针指向首结点
Head->next->prev = New;       // 首结点的next指针指向新结点

}

/*******************************************************************************

  • name : DoubleCirLList_DestInsert
  • function : 插入到指定结点的尾部
  • argument :
  •          @Head    :头结点的地址
    
  •          @data    :插入结点的数据
    
  •          @DestVal :指定插入位置的结点数据
    
  • retval : true and false
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    bool DoubleCirLList_DestInsert(DoubleCirLList_t *Head, DataType_t DestVal, DataType_t data)
    {
    DoubleCirLList_t *Phead = Head->next; // 备份首结点
    // 创建新的结点并对结点进行初始化
    DoubleCirLList_t *New = DoubleCirLList_NewNode(data);
    if (NULL == New)
    {
    printf("can not insert New Node");
    return false;
    }
// 判断链表是否为空,则直接插入到首结点后
if (Head->next == Head)
{
    Head->next = New;
    return true;
}

while (Phead->next != Head->next)
{
    if (DestVal == Phead->data)
    {
        break;
    }
    Phead = Phead->next;
}

// 遍历到尾结点还未找到这插入失败
if (Phead->next == Head->next && Phead->data != DestVal)
{
    return false;
}

if (Phead->data == DestVal) // 指点插入
{
    New->prev = Phead;       // 新结点的prev指针指向目标结点
    New->next = Phead->next; // 新结点的next指针指向目标结点的直接后继
    Phead->next->prev = New; // 目标结点的直接后继的prev指针指向新结点
    Phead->next = New;       // 把目标结点的next指针指向新结点
}
else // 尾插
{
    New->prev = Phead;      // 把新结点的prev指针指向目标结点
    New->next = Head->next; // 把新结点的next指针指向首结点
    Head->next->prev = New; // 把首结点的prev指针指向新结点
    Phead->next = New;      // 把指定结点的next指针指向新结点
}

}

/*******************************************************************************

  • name : DoubleCirLList_HeadDel
  • function : 头部删除结点
  • argument :
  •          @Head    :头结点的地址
    
  • retval : true and false
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    bool DoubleCirLList_HeadDel(DoubleCirLList_t *Head)
    {
    DoubleCirLList_t *Phead = Head->next; // 备份首结点的地址
    // 判断链表是否为空
    if (Head == Head->next)
    {
    printf(" Linked list is empty");
    return false;
    }
// 链表非空
Phead->prev->next = Phead->next; // 尾结点的next指针指向待删除结点的直接后继
Phead->next->prev = Phead->prev; // 待删除结点的直接后继的perv指针指向尾结点
Head->next = Phead->next;        // 头结点的next指针指向待删除结点的直接后继
Phead->next = NULL;              // 首结点的next指针指向NULL
Phead->prev = NULL;              // 首结点的prev指针指向NULL
free(Phead);                     // 释放首结点内存
return true;

}

/*******************************************************************************

  • name : DoubleCirLList_TailDel
  • function : 尾部删除结点
  • argument :
  •          @Head    :头结点的地址
    
  • retval : true and false
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    bool DoubleCirLList_TailDel(DoubleCirLList_t *Head)
    {
    DoubleCirLList_t *tail = Head->next->prev; // 记录尾结点的地址
    // 判断链表是否为空
    if (Head == Head->next)
    {
    printf("Linked list is empty");
    return false;
    }
// 链表为非空
tail->prev->next = Head->next; // 尾结点的直接前驱的next指针指向首结点
Head->next->prev = tail->prev; // 首结点的next指针指向尾结点的直接前驱
tail->prev = NULL;             // 尾结点的prev指针指向NULL
tail->next = NULL;             // 尾结点的next指针指向NULL
free(tail);                    // 释放尾结点内存

}

/*******************************************************************************

  • name : DoubleCirLList_DestDel
  • function : 指定删除结点
  • argument :
  •          @Head    :头结点的地址
    
  •          @DeatVal :指定结点的数据
    
  • retval : true and false
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    bool DoubleCirLList_DestDel(DoubleCirLList_t *Head, DataType_t DestVal)
    {
    DoubleCirLList_t *Phead = Head->next; // 记录首结点的地址
    // 判断链表是否为空
    if (Head == Head->next)
    {
    printf("Linked list is empty");
    return false;
    }
// 判断是否只有一个首结点
if (Phead->next == Head->next)
{
    Phead->next = NULL; // 首结点的next指针指向NULL
    Phead->prev = NULL; // 首结点的prev指针指向NULL
    Head->next = Head;  // 头结点指向本身
}
while (Phead->next != Head->next)
{
    if (DestVal == Phead->data)
    {
        break;
    }
    Phead = Phead->next;
}
if (Phead == Head->next) // 头删
{
    Phead->prev->next = Phead->next; // 尾结点的next指针指向待删除结点的直接后继
    Phead->next->prev = Head->prev;  // 带删除结点的直接后继的prev指针指向尾结点
    Head->next = Phead->next;        // 头结点的next指针指向待删除结点的直接后继
    Phead->next = NULL;              // 待删除结点的next指针指向NULL
    Phead->prev = NULL;              // 待删除结点的prev指针指向NULL
    free(Phead);                     // 释放首结点的内存
}
else if (DestVal == Phead->data) // 尾部删除
{
    Phead->prev->next = Head->next; // 待删除点的直接前驱的next指针指向首结点
    Head->next->prev = Phead->prev; // 首结点的prev指针指向待删除结点的直接前驱
    Phead->prev = NULL;             // 待删除结点的prev指针指向NULL
    Phead->next = NULL;             // 待删除结点的next指针指向NULL
    free(Phead);                    // 释放删除结点的内存
}
else
{
    Phead->prev->next = Phead->next; // 待删除结点的直接前驱的next指针指向待删除结点的直接后继
    Phead->next->prev = Phead->prev; // 待删除结点的直接后继的prev指针指向待删除结点的直接前驱
    Phead->prev = NULL;              // 待删除结点的prev指针指向NULL
    Phead->next = NULL;              // 待删除结点的next指针指向NULL
    free(Phead);                     // 释放删除结点内存
}

}

/*******************************************************************************

  • name : DoubleCirLList_Print
  • function : 遍历双向链表的中的每个结点,并输出每个结点的数据
  • argument :
  •          @Head    :头结点的地址
    
  • retval : true and false
  • author : yxw18679428019@163.com
  • date : 2024/04/25
  • note : None
  • ***************************************************************************/
    bool DoubleCirLList_Print(DoubleCirLList_t *Head)
    {
    // 对单向循环链表的头结点的地址进行备份
    DoubleCirLList_t *Phead = Head;
// 判断当前链表是否为空,为空则直接退出
if (Head->next == Head)
{
    printf("current linkeflist is empty!\n");
    return false;
}

// 从首结点开始遍历
while (Phead->next)
{
    // 把头结点的直接后继作为新的头结点
    Phead = Phead->next;

    // 输出头结点的直接后继的数据域
    printf("data = %d\n", Phead->data);

    // 判断是否到达尾结点,尾结点的next指针是指向首结点的地址
    if (Phead->next == Head->next)
    {
        break;
    }
}

return true;

}

int main(int argc, char const *argv[])
{
DoubleCirLList_t *Head = DoubleCirLList_Create();
// 头部插入
DoubleCirLList_HeadInsert(Head, 3);
DoubleCirLList_HeadInsert(Head, 5);
DoubleCirLList_Print(Head);
printf("\n");
// 尾部插入
DoubleCirLList_TailInsert(Head, 1);
DoubleCirLList_TailInsert(Head, 2);
DoubleCirLList_Print(Head);
printf("\n");
// 指定插入
DoubleCirLList_DestInsert(Head, 2, 4);
DoubleCirLList_Print(Head);
printf("\n");
// 头删
DoubleCirLList_HeadDel(Head);
DoubleCirLList_HeadDel(Head);
DoubleCirLList_Print(Head);
printf("\n");
// 尾删
DoubleCirLList_TailDel(Head);
DoubleCirLList_TailDel(Head);
DoubleCirLList_Print(Head);
printf("\n");
// 指定删除
DoubleCirLList_DestDel(Head, 1);
DoubleCirLList_Print(Head);

return 0;

}

posted @   Yxw_lp  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示