当前位置: 首页 > news >正文

双向循环链表及实现

双向循环链表及实现

很好,学过链表的都知道,一个普通的单项链表会经常的面临一个很难受的问题就是只能向前不能向后。那有没有可以向前也可以向后的呢?有的兄弟有的,那就是我们的双向链表,再加上我们之前所学的循环链表,就可以组成我们今天的大宝贝——双向循环链表。

双向循环链表

竟然是链表,而且是双向的我们就可以参照之前的图来进行改进,那既然是双向,这图自然也要有两个指向,自然就画出了如下图

在这里插入图片描述

这就是它一个小节点,那么我们再用结构体去实现它

struct node{element_t val;struct node*next;struct node*prev;
}

好到又回到我们增删改查的老步骤,和单项链表不同的是,单项链表你只要记住站在前一个改变后一个就行了,而双向链表你需要在改变哪里就到哪里就行了。

好的我们开始学习插入操作

插入

要记住从后往前,然后你必然需要两个指针一个是前指针,一个是后指针,这两个个指针的名字也要选的好操作一些,比如前一个指针的名字可以叫next 后一个指针的名字可以叫prev

画个图来辅助理解

在这里插入图片描述

而我们从后向前的逻辑转化成代码一下就是

next->prev=new_node;
new_node->next=next;
new_node->prev=prev;
prev->next=new_node;

如果你把它封装完成以后就可以依靠这个轻松的完成头插尾插的实现。

来我们继续讲删除

删除

有了上面的经验我们也可以大胆的推一下删除如何处理,首先还是找到要删除的节点,而后从后向前删除,最后释放空间

图如下

在这里插入图片描述

从后向前,代码转换如下

next->prev=prev;
prev->next=next;
free(p);

我们刚才学习的方法其实就已经是万金油了,当面临循环链表的插入或删除时,我们完全可用上面的代码做成对应的接口,下面我们就用上面的方法来对我们循环双向链表进行实现。

当我们对一个头结点进行第一个节点的插入时

如图

在这里插入图片描述

我们完全可以使用之前插入的代码来实现

next->prev=new_node;
new_node->next=next;
new_node->prev=prev;
prev->next=new_node;

而我们只需要知道新节点,前一个节点,后一个节点就好了

我们将上面的代码封装成函数

insertHead(new_node,header,header->next)

最后实现

在这里插入图片描述

这是头插

同理,尾插也一样,只不过是还传入的值罢了

在这里插入图片描述

insertRear(new_node,heade->prev,header)

要不然为啥我说我们学的是万精油呢?

双向链表的完整代码实现

结构定义和结构操作的头文件


#ifndef DOUBLELIST_H
#define DOUBLELIST_Htypedef int Element;
typedef struct _node {Element val;struct _node *next;struct _node *prev;}DNode,DList;//使用一个带头节点的双向循环链表,头结点让用户来管理,提供初始化接口
void initDlist(DList *head);
void releseDlist(DList *head);//插入,头插法,尾插法
void insertDlist(DList *head, Element data);
void insertDlistRear(DList *head, Element data);//打印
void showDlist(const DList *head);
//删除
void deleteDlist(DList *head,Element data);#endif //DOUBLELIST_H

每个函数的具体实现


//
// Created by clr on 25-6-17.
//#include "doubleList.h"#include <stdio.h>
#include <stdlib.h>
static void addnode(DNode *newnode,DNode *prev,DNode *next) {next->prev=newnode;newnode->next=next;newnode->prev=prev;prev->next=newnode;
}
static void deldNode(DNode*prev,DNode *next) {next->prev=prev;prev->next=next;
}void initDlist(DList *head) {head->val=0;head->next=head->prev=head;
}void releseDlist(DList *head) {DNode*p=head->next;DNode*tmp=NULL;while(p!=head) {tmp=p;deldNode(p->prev,p->next);p=p->next;free(tmp);--head->val;}
}//头插
void insertDlist(DList *head, Element data) {DNode *newnode=malloc(sizeof(DNode));newnode->val=data;addnode(newnode,head,head->next);++head->val;
}
//尾插
void insertDlistRear(DList *head, Element data) {DNode *newnode=malloc(sizeof(DNode));newnode->val=data;addnode(newnode,head->prev,head);++head->val;
}void showDlist(const DList *head) {DNode *p=head->next;printf("show \n");while (p!=head) {printf("\t%d->",p->val);p=p->next;}printf("\n");printf("=============\n");
}void deleteDlist(DList *head,Element data) {//找到这个元素,不需要找到前置节点DNode *p=head->next;while (p!=head&&p->val!=data) {p=p->next;}if (p!=head) {deldNode(p->prev,p->next);p->prev=p->next=NULL;free(p);--head->val;}else {printf("nothing to delete\n");}}

测试


#include <stdio.h>
#include "doubleList.h"DList stu_table;int main() {initDlist(&stu_table);for (int i = 1; i <= 5; i++) {//insertDlist(&stu_table, i+100);insertDlistRear(&stu_table, i+100);}showDlist(&stu_table);deleteDlist(&stu_table,104);showDlist(&stu_table);releseDlist(&stu_table);return 0;
}

测试结果
在这里插入图片描述

好的,这篇博客到这里就结束了,喜欢记得点点赞哦(づ ̄3 ̄)づ╭❤~

相关文章:

  • 数学术语之源——(矩阵或行列式的)秩数(rank)
  • 机器学习1——贝叶斯理论上
  • GPU 性能可变性分析框架
  • 60 python asyncio模块(异步IO)
  • CANdela/Diva系列10--CDD文件在CANoe工程的应用2
  • LeetCode 312 戳气球题解(Swift)+ 区间 DP 原理详解 + 可运行代码
  • 高斯过程动态规划(GPDP)
  • FLUX.1 Kontext(Dev 版)训练lora基础教程
  • 将listener转换为事件流
  • 系统思考:结构影响行为
  • VS2022配置x86/x64调用32位和64位汇编语言动态库环境
  • 【C/C++】C++26新特性前瞻:全面解析未来编程
  • 【k近邻】 K-Nearest Neighbors算法原理及流程
  • 双指针技巧深度解析
  • 新一代python的包管理软件mamba
  • 详解HashMap底层原理
  • JDBC 工具类:1.0到3.0版本
  • 【大模型水印论文阅读2】前缀文本编码、均匀性约束
  • Java--数组
  • 基于springboot的火锅店点餐系统