0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

双向循环链表的创建

C语言编程学习基地 来源:C语言编程学习基地 作者:C语言编程学习基地 2022-05-24 16:27 次阅读

双向循环链表和它名字的表意一样,就是把双向链表的两头连接,使其成为了一个环状链表。只需要将表中最后一个节点的next指针指向头节点,头节点的prior指针指向尾节点,链表就能成环儿,如图所示:

c0a72b46-db39-11ec-ba43-dac502259ad0.jpg

需要注意的是,虽然双向循环链表成环状,但本质上还是双向链表,因此在双向循环链表中,依然能够找到头指针和头节点等。双向循环链表和双向链表相比,唯一的不同就是双向循环链表首尾相连,其他都完全一样。

注意:因为我上面已经讲了双向链表,所以这里只注重讲他们的实现差异。另因为带头节点会更好操作,所以我的代码都有头节点。

1、双向循环链表的创建

初始化时需要将头节点的next和prior都指向自己。

c0be579e-db39-11ec-ba43-dac502259ad0.jpg

//1、初始化双向循环链表(带头节点)

Status initLinkList(LinkList *list){

//创建头节点

*list = malloc(sizeof(Node));

if (*list == NULL) {

return ERROR;

}

//前驱和后继都指向自己

(*list)->prior = *list;

(*list)->data = -1;

(*list)->next = *list;

printf("已初始化链表~ ");

return OK;

}

2、遍历双向循环链表

注意它的尾节点的next不再是Null,而是头节点

//2、遍历双向循环链表

void printfLinkLisk(LinkList list){

printf("遍历链表: ");

if (list == NULL || list->next == list) {

printf("这是一个空链表 ");

return;

}

LinkList p = list;

//判断next是否全部正确

printf("根据next从前往后遍历:");

while (p->next != list) {

printf("%d ",p->next->data);

p = p->next;

}

printf(" ");

//判断prior是否全部正确

printf("根据prior从后往前遍历:");

while (p != list) {

printf("%d ",p->data);

p = p->prior;

}

printf(" ");

}

3、根据索引位置添加节点

这里不需要判断尾节点的next是否为Null,因为它会指向头节点。

//3、根据索引位置插入数据至链表中

Status insertLinkList(LinkList *list, int index, ElemType data){

if (list == NULL || index < 0) {

return ERROR;

}

int i = 0;

LinkList priorNode = *list;

//判断插入的位置,这里开始位置是0,index超过链表长度则插入末尾

while (i < index && priorNode->next != *list) {

priorNode = priorNode->next;

i++;

}

LinkList newNode = malloc(sizeof(Node));

if (newNode == NULL) {

return ERROR;

}

newNode->data = data;

//插入操作共四步,看好了,别眨眼

//1.将priorNode->next节点的前驱指向新节点

priorNode->next->prior = newNode;

//2.将新节点->next指向原来的priorNode->next

newNode->next = priorNode->next;

//3.将priorNode->next指向新节点

priorNode->next = newNode;

//4.新节点的前驱指向priorNode

newNode->prior = priorNode;

return OK;

}

4、根据索引位置删除节点

这里不需要判断尾节点的next是否为Null,因为它会指向头节点。

//4、根据索引位置删除节点

Status deleteLinkListByIndex(LinkList *list, int index, ElemType *data){

if (*list == NULL || index < 0) {

return ERROR;

}

LinkList locaNode = *list;

int i = 0;

//注意别删了头节点

while (i <= index) {

locaNode = locaNode->next;

if (locaNode == *list) {

printf("没有这个你想要删除的节点 ");

return ERROR;

}

i++;

}

//开始删除,只需要做两步

locaNode->prior->next = locaNode->next;

locaNode->next->prior = locaNode->prior;

*data = locaNode->data;

free(locaNode);

return OK;

}

5、根据存储的值删除节点

这里不需要判断尾节点的next是否为Null,因为它会指向头节点。

//5、根据存储的值删除节点

Status deleteLinkListByData(LinkList *list, ElemType data){

if (*list == NULL) {

return ERROR;

}

LinkList locaNode = (*list)->next;

while (locaNode != *list) {

if (locaNode->data == data) {

break;

}

locaNode = locaNode->next;

}

if (locaNode == *list) {

printf("没有这个你想要删除的节点 ");

return ERROR;

}

//开始删除,只需要做两步

locaNode->prior->next = locaNode->next;

locaNode->next->prior = locaNode->prior;

free(locaNode);

return OK;

}

6、根据值查找节点

尾节点的next可是头节点哦,找到它就是最后一个了。

//6、查找元素

Status selectNode(LinkList list, ElemType data, LinkList *locaNode){

if (list == NULL) {

return ERROR;

}

LinkList p = list->next;

while (p != list) {

if (p->data == data) {

*locaNode = p;

break;

}

p = p->next;

}

if (*locaNode == NULL) {

printf("没有这个你想要的节点 ");

return ERROR;

}

else {

return OK;

}

}

其它代码

#include "stdlib.h"

#define OK 1

#define ERROR 0

//元素类型

typedef int ElemType;

//状态类型

typedef int Status;

//定义节点结构体

typedef struct Node {

struct Node *prior;

ElemType data;

struct Node *next;

} Node;

typedef Node *LinkList;

int main(int argc, const char * argv[]) {

LinkList list;

initLinkList(&list);

for (int i = 0; i < 10; i ++) {

insertLinkList(&list, i, i);

}

printfLinkLisk(list);

int index, data;

printf("输入你想插入的位置(从0开始)和存储的值:");

scanf("%d %d",&index,&data);

insertLinkList(&list, index, data);

printfLinkLisk(list);

printf("输入你想删除的位置(从0开始):");

scanf("%d",&index);

deleteLinkListByIndex(&list, index, &data);

printfLinkLisk(list);

printf("输入你想删除的节点的值(只删最前的那个):");

scanf("%d",&data);

deleteLinkListByData(&list, data);

printfLinkLisk(list);

printf(" ");

return 0;

}

输出结果:

c0cf2b46-db39-11ec-ba43-dac502259ad0.jpg

—END—

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 节点
    +关注

    关注

    0

    文章

    217

    浏览量

    24380
  • 链表
    +关注

    关注

    0

    文章

    80

    浏览量

    10547

原文标题:【C语言教程】“双向循环链表”学习总结及其代码实现!

文章出处:【微信号:cyuyanxuexi,微信公众号:C语言编程学习基地】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    OpenHarmony语言基础类库【@ohos.util.LinkedList (线性容器LinkedList)】

    LinkedList底层通过双向链表实现,双向链表的每个节点都包含对前一个元素和后一个元素的引用。当需要查询元素时,可以从头遍历,也可以从尾部遍历,插入、删除效率高,查询效率低。Lin
    的头像 发表于 05-11 16:16 510次阅读
    OpenHarmony语言基础类库【@ohos.util.LinkedList (线性容器LinkedList)】

    什么是PLC循环移位指令 PLC循环移位的特点

    PLC循环移位指令包括循环左移指令和循环右移指令。在循环移位过程中,移出的位并不会丢失,而是会放回空出的位上,形成一个环形移位。
    的头像 发表于 03-07 16:57 1949次阅读
    什么是PLC<b class='flag-5'>循环</b>移位指令 PLC<b class='flag-5'>循环</b>移位的特点

    verilog双向端口的使用

    在Verilog硬件描述语言中,端口是指连接模块(Module)与其他模块、寄存器或是物理设备的输入或输出接口。单向端口可以作为输入或输出使用,而双向端口具有双重作用,既可以接收输入信号,又可以输出
    的头像 发表于 02-23 10:18 1286次阅读

    数组和链表在内存中的区别 数组和链表的优缺点

    数组和链表在内存中的区别 数组和链表的优缺点  数组和链表是常见的数据结构,用于组织和存储数据。它们在内存中的存储方式以及优缺点方面存在一些显著的差异。本文将详细探讨这些差异以及它们的优缺点。 1.
    的头像 发表于 02-21 11:30 891次阅读

    数组和链表有何区别

    数组和链表的区别,这个问题,不仅面试中经常遇到,考研的同学也得掌握才行。
    的头像 发表于 02-19 15:33 449次阅读
    数组和<b class='flag-5'>链表</b>有何区别

    arduino如何停止loop循环

    Arduino的loop循环是其主要的程序执行部分,该循环将在Arduino开发板上持续运行,并且只有在程序被重新上传或开发板断电重启时才会停止。然而,在某些情况下,你可能需要在程序执行过程中停止或
    的头像 发表于 02-14 16:24 4181次阅读

    arduino中while循环怎么跳出

    Arduino 是一款开源的硬件平台,广泛应用于各种物联网和嵌入式系统项目。在 Arduino 上编写代码时,循环结构起到了至关重要的作用。而其中的 while 循环更是常用于需要根据特定条件重复
    的头像 发表于 02-14 16:22 2382次阅读

    循环指令loop规定循环次数

    循环指令是计算机编程中非常重要的概念,它允许程序重复执行一段代码块,使得程序可以更有效地处理大量数据和重复性任务。在本文中,我们将详尽、详实、细致地介绍循环指令的相关概念、语法和应用场
    的头像 发表于 02-14 16:10 1457次阅读

    如何在循环中断中创建工艺对象PID控制器?

    以下步骤将介绍如何在循环中断 OB“PID [OB200]”中调用工艺对象“PID_Compact” 。
    的头像 发表于 12-29 18:10 1741次阅读
    如何在<b class='flag-5'>循环</b>中断中<b class='flag-5'>创建</b>工艺对象PID控制器?

    数据结构:删除有序链表的重复节点

    给定一个有序单链表(从小到大有序)的头结点head(该结点有值),删除链表中的重复元素,使链表中的所有元素都只出现一次。如当输入 {1,1,2} 时,经删除后,原链表变为 {1,2},
    的头像 发表于 12-05 15:46 861次阅读
    数据结构:删除有序<b class='flag-5'>链表</b>的重复节点

    数据结构:判断链表回文结构

    给定一个链表,判断该链表是否为回文结构。回文是指该字符串正序逆序完全一致。如当输入链表 {1,2,3,2,1} 时,断定是回文结构,输出True。
    的头像 发表于 12-01 13:26 611次阅读
    数据结构:判断<b class='flag-5'>链表</b>回文结构

    数据结构:单链表的排序

    给定一个单链表的头结点head(该结点有值),长度为n的无序单链表,对其按升序排序后,返回新链表。如当输入链表 {3,1,4,5,2} 时,经升序排列后,原
    的头像 发表于 11-30 13:56 1489次阅读
    数据结构:单<b class='flag-5'>链表</b>的排序

    python怎么设置循环次数

    在Python中,可以使用循环语句来重复执行一段代码多次。要设置循环次数,可以使用循环的计数器来控制循环的执行次数。以下是几种常用的设置循环
    的头像 发表于 11-23 15:50 5082次阅读

    python循环创建变量并赋值

    循环是Python编程中非常重要的一个概念,它可以让我们轻松地重复执行某些代码块,从而简化编程过程并提高代码的效率。在循环中,我们经常需要创建变量并赋值,这是非常常见的操作。接下来,我将详尽地解释在
    的头像 发表于 11-23 14:51 1609次阅读

    for循环里的变量是局部变量吗

    对于一个普通for循环而言,循环变量是局部变量。在大多数编程语言中,循环变量只在循环内部的作用域中可见。换句话说,循环变量的声明和赋值仅在
    的头像 发表于 11-23 14:50 2522次阅读