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

双向循环链表

时间:2024-04-24 23:56:46浏览次数:27  
标签:结点 DoubleLList Phead Head next 链表 循环 双向 NULL

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

  • 设计双向链表的接口
  • ******************************************************************************************************/

include <stdio.h>

include <stdbool.h>

include <stdlib.h>

include <unistd.h>

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

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

} DoubleLList_t;

// 创建一个空双向链表,空链表应该有一个头结点,对链表进行初始化
DoubleLList_t *DoubleLList_Create(void)
{
// 1.创建一个头结点并对头结点申请内存
DoubleLList_t *Head = (DoubleLList_t *)calloc(1, sizeof(DoubleLList_t));
if (NULL == Head)
{
perror("Calloc memory for Head is Failed");
exit(-1);
}

// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向NULL
Head->prev = NULL;
Head->next = NULL;

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

}

// 创建新的结点,并对新结点进行初始化(数据域 + 指针域)

DoubleLList_t *DoubleLList_NewNode(DataType_t data)
{
// 1.创建一个新结点并对新结点申请内存
DoubleLList_t *New = (DoubleLList_t *)calloc(1, sizeof(DoubleLList_t));
if (NULL == New)
{
perror("Calloc memory for NewNode is Failed");
return NULL;
}

// 2.对新结点的数据域和指针域(2个)进行初始化
New->data = data;
New->prev = NULL;
New->next = NULL;

return New;

}

// 头插
bool DoubleLList_HeadInsert(DoubleLList_t *Head, DataType_t data)
{
// 1.创建新的结点,并对新结点进行初始化
DoubleLList_t *New = DoubleLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node\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;

}

// 尾部插入
bool DoubleLList_TailInsert(DoubleLList_t *Head, DataType_t data)
{

// 1.创建新的结点,并对新结点进行初始化
DoubleLList_t *New = DoubleLList_NewNode(data);
if (NULL == New)
{
    printf("can not insert new node\n");
    return false;
}
// 如果链表为空
if (NULL == Head->next)
{
    // 头结点指向新结点
    Head->next = New;
    return true;
}

DoubleLList_t *temp = Head; // 记录尾结点
// 遍历链表,找到尾结点
while (temp->next)
{
    temp = temp->next;
}

// 把尾结点指向新结点
temp->next = New;
// 把新结点指向尾结点
New->prev = temp;
return true;

}

// 指定插入
bool DoubleLList_DestInsert(DoubleLList_t *Head, DataType_t Destval, DataType_t data)
{
// 1.创建新的结点,并对新结点进行初始化
DoubleLList_t *New = DoubleLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node\n");
return false;
}
// 如果链表为空
if (NULL == Head->next)
{
// 头结点指向新结点
Head->next = New;
return true;
}

DoubleLList_t *Phead = Head; // 备份头结点
// 遍历链表,找到目标结点
while (Phead->next)
{
    Phead = Phead->next;
    if (Destval == Phead->data)
    {
        break;
    }
}
if (Phead->next == NULL && Phead->data != Destval)
{
    printf("New Nodo Insertion failure");
    return false;
}

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

}

// 遍历链表
bool DoubleLList_Print(DoubleLList_t *Head)
{
// 对单向循环链表的头结点的地址进行备份
DoubleLList_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);
    usleep(100000);

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

return true;

}
// 头删
bool DoubleLList_HeadDel(DoubleLList_t *Head)
{
// 判断链表是否为空
if (NULL == Head->next)
{
printf("删除失败链表为空");
return false;
}
// 对链表首结点进行备份
DoubleLList_t *Phead = Head->next;
// 链表为非空则删除结点
Head->next = Head->next->next;
Phead->next = NULL;
Head->next->next->prev = NULL;
free(Phead);
return true;
}

// 尾删
bool DoubleLList_TailDel(DoubleLList_t *Head)
{
// 判断链表是否为空
if (NULL == Head->next)
{
printf("删除失败链表为空");
return false;
}
// 用于存储尾结点
DoubleLList_t *Phead = Head;
// 用于遍历找到尾结点
while (Phead->next)
{
Phead = Phead->next;
}

// 链表为非空则删除结点
Phead->prev->next = NULL;
Phead->prev = NULL;
free(Phead);
return true;

}

// 指定位置删除
bool DoubleLList_DestDel(DoubleLList_t *Head, DataType_t Destval)
{
// 定义一个指针存储待删除目标结点
DoubleLList_t *dest = Head;
// 判断链表是否为空
if (NULL == Head->next)
{
printf("删除失败链表为空");
return false;
}

// 判断是否只有首结点
if (NULL == dest->next->next)
{
    dest->next->next = NULL; // 首结点的next指针指向NULL
    dest->next->prev = NULL; // 首结点的prev指针指向NULL
    Head->next = NULL;       // 头结点的next指针指向NULL
    free(dest);              // 释放删除结点的内存
}

// 遍历链表,找到待删除接结点
while (dest->next)
{
    dest = dest->next;
    if (Destval == dest->data)
    {
        break;
    }
}

// 如果遍历到最后还没未找到该结点则删除失败
if (dest->next == NULL && dest->data != Destval)
{
    return false;
}

// 找到指定结点
if (dest == Head->next) // 头删
{

    Head->next = dest->next; // 头结点的next指针指向待删除结点的直接后继
    dest->next->prev = NULL; // 但删除结点的直接后继指向prev指针指向NULL
    dest->next = NULL;       // 但删除结点的next指针指向NULL
    free(dest);              // 释放待删除结点内存
}
else if (dest->next == NULL) // 尾部删除
{
    dest->prev->next = NULL; // 待删除结点的直接前驱的next指针指向NULL
    dest->prev = NULL;       // 待删除结点的prev指针指向NULL
    free(dest);              // 释放目标结点内存
}
else // 指定位置删除
{
    dest->prev->next = dest->next; // 待删除结点的直接前驱的next指针指向但删除结点的直接后继
    dest->next->prev = dest->prev; // 但删除结点的直接后继的perv指针指向但删除结点的直接前驱
    dest->next = NULL;             // 待删除结点的next指针指向NULL
    dest->prev = NULL;             // 待删除结点的perv指针指向NULL
    free(dest);                    // 释放待删除结点内存
}

return true;

}

int main(int argc, char const *argv[])
{
DoubleLList_t *Head = DoubleLList_Create();
// 头部插入
DoubleLList_HeadInsert(Head, 2);
DoubleLList_HeadInsert(Head, 4);
DoubleLList_HeadInsert(Head, 6);
DoubleLList_HeadInsert(Head, 8);
DoubleLList_Print(Head);
// 尾部插入
DoubleLList_TailInsert(Head, 1);
DoubleLList_TailInsert(Head, 3);
DoubleLList_TailInsert(Head, 5);
DoubleLList_TailInsert(Head, 7);
DoubleLList_Print(Head);
// 指定位置charu
DoubleLList_DestInsert(Head, 3, 9);
DoubleLList_DestInsert(Head, 4, 10);
DoubleLList_Print(Head);
printf("\n");
// 头部删除
DoubleLList_HeadDel(Head);
DoubleLList_HeadDel(Head);
DoubleLList_Print(Head);
// 尾部删除
DoubleLList_TailDel(Head);
DoubleLList_TailDel(Head);
DoubleLList_Print(Head);
// 指定删除
DoubleLList_DestDel(Head, 4);
DoubleLList_Print(Head);
return 0;
}

标签:结点,DoubleLList,Phead,Head,next,链表,循环,双向,NULL
From: https://www.cnblogs.com/Yxwwant/p/18156629

相关文章

  • 双向链表和双向循环链表的(创建、插入、删除、遍历)
    V1.02024年4月24日发布于博客园目录目录目录双向链表和双向循环链表的(创建、插入、删除、遍历)设计双向链表的接口创建一个空的双向链表,空链表应该有一个头结点,对链表进行初始化创建新的结点,并对新结点进行初始化(数据域+指针域)创建一个新的结点进行头部插入创建一个新的......
  • 用一个尽可能高效的算法,查找单向链表(有头结点)中倒数第k个位置上的结点
    思路  定义两个指向链表首结点的指针变量,第一个指针变量向后移动k个位置后,第二个指针变量也开始跟着一起向后移动,直到第一个指针变量指向尾结点为止,第二个指针变量指向的位置结点就是倒数第k个结点。实现步骤及参考代码(C语言)intLList_FindLK(LList_t*Head,DataType_tda......
  • 自定义双向循环链表基本函数接口
    自定义双向循环链表的函数接口/********************************************************************* 文件名称: 双向循环链表的函数接口* 文件作者:[email protected]* 创建日期:2024/04/24* 文件功能:对双向链表的增删改查功能的定义* 注意事项:No......
  • 双向循环链表及各功能函数设计
    双向循环链表/***@filename:双向链表接口设计*@brief*@[email protected]*@date2024/04/24*@version1.0:版本*@property:*@note*CopyRight(c)[email protected]*/构造双向循环链表的结点//指的是双向循......
  • 设计双向链表的接口
    /***********************************************************************************filename:004_双向链表.cauthor:[email protected]:2024/04/24function:设计双向循环链表的接口note:None......
  • 数据结构(双向链表的实现)
    目录一:带头双向链表什么叫双向链表:二:实现声明结构体(1).创建头结点进行初始化(2).动态申请一个结点(3).插入头插入:尾插入指定位置插入(中间插入)4:删除:头删除:尾删除:中间删除:5:打印链表一:带头双向链表什么叫双向链表:结点互相指向的,首结点指向null,尾结点指向null。如果想要提高单......
  • 双向循环连链表的另类实现
    `#include<stdio.h>include<stdlib.h>/**@filename: Untitled-1.c@brief双向链表的另类实现@[email protected]@date2024/04/[email protected]:版本@property:属性介绍@noteCopyRight(c)[email protected]*/typed......
  • 双向循环链表:(创建、插入、遍历、求长、查找、删除、排序、销毁)待测
    目录一、双向循环链表存在的意义二、节点的定义三:实现1:创建链表(即创建一个空链表)2:创建新结点3:遍历4:插入头插入尾插入中间插入一、双向循环链表存在的意义数组这样的结构提供了连续内存的访问和使用,链表是对内存零碎空间的有效组织和使用,双向循环链表增大了访问的自由度。二、......
  • 数据结构-双循环链表的插入
    数据结构-双循环链表插入/*************************************************/***@filename: DcirLLinkInsert*@brief对双向循环链表插入的功能实现*@[email protected]*@date2024/04/24*@version1.0:在下坂本,有何贵干*@property:none......
  • 单向链表的插入、与删除
    链表在C语言中,链表是一种常用的数据结构,它可以用来存储一系列的元素。链表中的每个元素都存储了下一个元素的地址,从而形成了一条链。这种结构使得在插入和删除元素时不需要像数组那样移动大量元素,因此它在插入和删除操作多的情况下有很大的优势。在C语言中,链表可以有多种实现方......