【链表-双向链表】

news/2024/9/23 3:19:08/

链表-双向链表

  • 1.链表的分类
    • 1.1 分类依据
    • 1.2 常用类型
  • 2.双向链表
    • 2.1 双向链表的结构
    • 2.2 双向链表的操作
      • 2.2.1 **初始化**
      • 2.2.2 **尾插**
      • 2.2.3 **头插**
      • 2.2.4 **尾删**
      • 2.2.5 **头删**
      • 2.2.6 在pos位置之后插入数据
      • 2.2.7 删除pos节点
      • 2.2.8 查找
      • 2.2.9 销毁

1.链表的分类

1.1 分类依据

单向or双向
在这里插入图片描述
带头or不带头
(一般会称d1为头节点,但实际上head这个哨兵节点才是头节点)
在这里插入图片描述
循环or不循环
在这里插入图片描述
综上所述,222共有8种链表

1.2 常用类型

我们一般最常用的就是单链表和双链表
链表:不带头单向不循环链表
在这里插入图片描述

双向链表:带头双向循环链表
在这里插入图片描述

2.双向链表

2.1 双向链表的结构

双向链表包含三个部分,:
1.数据
2.指向下一个节点的指针
3.指向上一个节点的指针

struct ListNode
{int data;struct ListNode* next;struct ListNode* prev;
}

ps:单链表和双向链表的初始状态?
链表为空链表
双向链表剩下一个头结点(即哨兵位)

2.2 双向链表的操作

2.2.1 初始化

方法一

void LTInit(LTNode** pphead);
void LTInit(LTNode** pphead)
{//给双向链表创建一个哨兵位*pphead = LTBuyNode(-1);//哨兵位不存储有效数据
}

方法二

LTNode* LTInit();
LTNode* LTInit()
{LTNode* phead = LTBuyNode(-1);return phead;
}

打印双向链表
在这里插入图片描述

void LTPrint(LTNode* phead);
void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}
void LTInit(LTNode** pphead)
{//给双向链表创建一个哨兵位*pphead = LTBuyNode(-1);//哨兵位不存储有效数据
}

2.2.2 尾插

在这里插入图片描述

//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);//哨兵位空,那就不是一个有效的双向链表LTNode* newnode = LTBuyNode(x);//phead phead->prev newnodenewnode->prev = phead->prev;//新节点头指向原链表的尾节点newnode->next = phead;//新节点尾节点指向哨兵位phead->prev->next = newnode;//原本的尾节点phead->prev指向新的尾节点phead->prev = newnode;//哨兵位指向新的尾节点
}

2.2.3 头插

在这里插入图片描述

void LTPushFront(LTNode* phead, LTDataType x); 
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead newnode phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}

2.2.4 尾删

在这里插入图片描述

void LTPopBack(LTNode* phead);
void LTPopBack(LTNode* phead)
{//链表必须有效且链表不能为空(只有一个哨兵位)assert(phead && phead->next != phead);LTNode* del = phead->prev;//phead del->prev deldel->prev->next = phead;phead->prev = del->prev;//删除del节点free(del);del = NULL;
}

2.2.5 头删

在这里插入图片描述

void LTPopFront(LTNode* phead);
void LTPopFront(LTNode* phead)
{assert(phead && phead->next != phead);LTNode* del = phead->next;//phead del del->nextphead->next = del->next;del->next->prev = phead;//删除del节点free(del);del = NULL;
}

2.2.6 在pos位置之后插入数据

在这里插入图片描述

void LTInsert(LTNode* pos, LTDataType x);
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);//pos newnode pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}

2.2.7 删除pos节点

在这里插入图片描述

void LTErase(LTNode* pos);
void LTErase(LTNode* pos)
{//pos理论上来说不能为phead,但是没有参数phead,无法增加校验assert(pos);//pos->prev pos pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

PS:LTErase参数理论上要传二级,因为我们需要让形参的改变影响到实参,但是为了保持接口一致性才传的一级。

2.2.8 查找

LTNode* LTFind(LTNode* phead, LTDataType x);
LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}//没有找到return NULL;
}

2.2.9 销毁

在这里插入图片描述

void LTDesTroy(LTNode* phead);
void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//此时pcur指向phead,而phead还没有被销毁free(phead);phead = NULL;
} 

ps:LTDestroy参数理论上要传二级,因为我们需要让形参的改变影响到实参,但是为了保持接口一致性才传的一级。传一级存在的问题是,当形参phead置为NULL后,实参plist不会被修改为NULL,因此解决办法是:调用完方法后手动将实参置为NULL。


http://www.ppmy.cn/news/1458045.html

相关文章

Unity调用智谱API(简单操作 文本实时翻译)

代码展示: using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI;public class ZhiPuAi : MonoBehaviour {// API的端点URLpublic string…

JS 实现继承的几种方式

现在有parent、child两个函数,child函数的实例想要访问parent函数的属性和方法(child想要继承parent)。 1、原型链继承 缺点:有引用的值共享的问题 即当parent某个属性是引用数据类型的时候,child实例如果修改了这个…

【算法练级js+java】重复给定字符n次

题目 Repeats the given string n times.(复制指定的字符串n次) 期望结果 /** * Repeats the given string n times. * * repeat(‘, 3) * // > **’ * * repeat(‘abc’, 2) * // > ‘abcabc’ * * repeat(‘abc’, 0) * // > “” **/ 代码…

护眼台灯哪个牌子最好?618五款护眼台灯品牌推荐

在光照不足的环境中,护眼台灯还能提升阅读和学习的视觉舒适度,减轻眼疲劳和视觉疲劳的可能性。鉴于当今儿童和青少年的学习用眼时间较长,而且他们处于视力发展的关键阶段,眼瞳更为敏感,容易发生近视,因此&a…

专业软件测试会议

全国软件测试会议:这是一个系列性的专业会议,由中国的学术机构或专业组织主办,例如中国计算机学会的容错计算专业委员会。此会议自2005年起开始举办,历届会议地点包括北京、昆明和武汉等地。会议内容覆盖软件测试理论、实践、工具…

GO语言核心30讲 进阶技术 (第二部分)

原站地址:Go语言核心36讲_Golang_Go语言-极客时间 一、接口类型的合理运用 1. 接口类型只包含方法,不包含字段。 方法集合就是它的全部特征。 任何数据类型,只要实现了接口的方法集合全部,那么它就是这个接口的实现类型 2. 怎么…

网络安全之DHCP详解

DHCP:Dynamic Host Configration Protocol 动态主机配置协议 某一协议的数据是基于UDP封装的,当它想确保自己的可靠性时,这个协议要么选确认重传机制,要么选周期性传输。 DHCP是确认重传,【UDP|DHCP】,当DHCP分配完地…

Spring中用到的设计模式有哪些

工厂模式,BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象。 单例模式,Spring依赖注入Bean实例默认是单例的。Spring依赖注入(包括lazy-init方式)都是发生在AbstractBeanFactory的getBean里。getBean的doGetBean方法调用getSingleton进行bean的创…