【双向链表的实现】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

1. 双向链表的结构

2. 双向链表的实现

2.1 头文件 ——双向链表的创建及功能函数的定义

2.2 源文件 ——双向链表的功能函数的实现

2.3 源文件 ——双向链表功能的测试

4.双向链表的操作示意图

3.顺序表和双向链表的优缺点分析

总结


前言

世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!


提示:以下是本篇文章正文内容,下面案例可供参考

1. 双向链表的结构

注意:这里的“带头”跟前面我们说的“头节点”是两个概念,实际前面的在单链表阶段称呼不严 谨,但是为了同学们更好的理解就直接称为单链表的头节点。

带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨的”

“哨兵位”存在的意义: 遍历循环链表避免死循环。

2. 双向链表的实现

2.1 头文件 ——双向链表的创建及功能函数的定义

List.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>//定义双向链表的节点的结构
typedef int STDataType;typedef struct ListNode
{STDataType data;struct ListNode* next;//保存下一个节点的地址struct ListNode* prev;//保存前一个节点的地址
}LTNode;//链表的初始化
//void LTInit(LTNode** pphead);//前提:我们要传入一个头节点//我们更倾向于第二种初始化的方法
//因为双向链表为空(只有一个哨兵位:哨兵位节点是不能被操作的,即不能被改变)
LTNode* LTInit();//不需要传入参数,调用该方法之后给我们返回一个头节点//在双向链表中不会改变哨兵位,所以可以传一级指针
//尾插入操作
void LTPushBack(LTNode* phead, STDataType x);//头插
void LTPushFront(LTNode* phead, STDataType x);//链表的打印
void LTPrint(LTNode* phead);//尾删
void LTPopBack(LTNode* phead);
//头删
void LTPopFront(LTNode* phead);//在pos位置之后插入的数据
void LTInsert(LTNode* pos, STDataType x);
//删除pos位置的节点
void LTErase(LTNode* pos);
LTNode* LTFind(LTNode* phead, STDataType x);//链表的销毁
void LTDestroy(LTNode* phead);

2.2 源文件 ——双向链表的功能函数的实现

List.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"//链表的初始化
//前提:我们要传入一个头节点
//void LTInit(LTNode** pphead)
//{
//	*pphead = (LTNode*)malloc(sizeof(LTNode));
//	if (*pphead == NULL)
//	{
//		perror("malloc");
//		return;
//	}
//	//节点有三部分内容:数据 前驱指针 后继指针
//	(*pphead)->data = -1;//哨兵位
//	(*pphead)->next = (*pphead)->prev = *pphead;
//}//链表初始化
//不需要传入参数,调用该方法之后给我们返回一个头节点
LTNode* LTInit()
{LTNode* phead = (LTNode*)malloc(sizeof(LTNode));if (phead == NULL){perror("malloc");return;}phead->data = -1;phead->next = phead->prev = phead;return phead;
}//申请一个新的节点
LTNode* ListBuyNode(STDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));node->data = x;node->next = node->prev = NULL;return node;
}//链表的打印
void LTPrint(LTNode* phead)
{LTNode* cur = phead->next;while (cur != phead){printf("%d->", cur->data);cur = cur->next;}printf("\n");
}//尾插入操作
void LTPushBack(LTNode* phead, STDataType x)
{assert(phead);LTNode* node = ListBuyNode(x);//先处理新节点node的前驱和后继指针node->prev = phead->prev;node->next = phead;//在处理phead->prev(之前的尾节点)和pheadphead->prev->next = node;phead->prev = node;
}//头插
void LTPushFront(LTNode* phead, STDataType x)
{assert(phead);LTNode* node = ListBuyNode(x);//node的节点 next prevnode->prev = phead;node->next = phead->next;//处理phead phead->nextphead->next->prev = node;phead->next = node;
}//尾删
void LTPopBack(LTNode* phead)
{assert(phead);//链表不能为空链表:链表中只有一个哨兵位节点assert(phead->next != phead);LTNode* del = phead->prev;//先处理del->prev节点del->prev->next = phead;//处理pheadphead->prev = del->prev;free(del);del = NULL;
}
//头删
void LTPopFront(LTNode* phead)
{assert(phead&& phead->next != phead);LTNode* del = phead->next;//phead del->nextdel->next->prev = phead;phead->next = del->next;free(del);del = NULL;
}//在pos位置之后插入的数据
void LTInsert(LTNode* pos, STDataType x)
{assert(pos);LTNode* node = ListBuyNode(x);//node的prev 和 nextnode->next = pos->next;node->prev = pos;//pos的next 和 pos->next的prevpos->next = node;node->next->prev = node;
}
//删除pos位置的节点
void LTErase(LTNode* pos)
{assert(pos);//pos->prev:next pos pos->next:prevpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}
//查找数据
LTNode* LTFind(LTNode* phead, STDataType x)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}//链表的销毁
void LTDestroy(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}//除了循环之后,还有哨兵位没有被释放free(phead);phead = NULL;//我们将phead指向的空间释放掉,plist实参的空间也被释放掉了,phead置为空//但是此时plist实参为野指针,还需要我们手动置为空
}

2.3 源文件 ——双向链表功能的测试

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "List.h"void ListTest()
{//第一种初始化方法:/*LTNode* plist = NULL;LTInit(&plist);*///第二种初始化方法;LTNode* plist = LTInit();//尾插LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);//打印LTPrint(plist);头插//LTPushFront(plist, 5);//LTPushFront(plist, 6);//LTPushFront(plist, 7);//LTPrint(plist);//尾删//LTPopBack(plist);//头删/*LTPopFront(plist);LTPopFront(plist);*///测试指定位置之后插入//LTNode* find = LTFind(plist, 1);//LTInsert(find, 11);/*LTErase(find);LTPrint(plist);*///销毁链表LTDestroy(plist);//传一级指针的要手动将plist置为空plist = NULL;
}
int main()
{ListTest();return 0;
}

4.双向链表的操作示意图

3.顺序表和双向链表的优缺点分析


总结

好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/235874.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工业APP1+X证书笔记

第一套 选择题 操作题一 let AbstractTrigger require(AbstractTrigger);class MyTrigger extends AbstractTrigger {execute(context,param){let bookDetail{bookCode:"1001",cnt:10,bookName:"中国上下五千年",bookAuth:"墨人",bookDate:&qu…

web:ics-05(本地文件包含漏洞、preg_replace函数/e漏洞、php伪协议读取文件)

题目 打开页面显示如下 只有这个页面能打开 显示如下 用dirsearch扫一下 查看了一下&#xff0c;发现没什么用 查看页面源代码 返回了&#xff0c;写入的参数&#xff0c;猜测可能有文件包含漏洞 用php伪协议读取文件 构造payload ?pagephp://filter/readconvert.base64-en…

学习k8s的介绍(一)

一、kubernetes及Docker相关介绍 1、kubernetes是什么 1-1、简称为k8s或kube&#xff0c;是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化。 声明式配置语法&#xff1a; kubectl create/apply/delete -f xx…

动态规划--整数拆分

题目描述 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: n 10 输出: 36 解释…

APITable免费开源的多维表格与可视化数据库本地部署公网远程访问

APITable免费开源的多维表格与可视化数据库公网远程访问 文章目录 APITable免费开源的多维表格与可视化数据库公网远程访问前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c…

20个Python源码项目下载

20个很不错的Python项目源码&#xff0c;其中包括适合毕业设计的项目。这些资源中涵盖了Django 3版本的项目&#xff1a; DjangoMysqlBulma实现的商场管理系统源码 PythonDjango实现基于人脸识别的门禁管理系统 PythonFlaskMySQL实现的学生培养计划管理系统 Python大熊猫主题人…

【超全】C++速查手册:面向对象与继承多态

C速查手册 C 类和对象 面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠…

树与二叉树堆:经典OJ题集

目录 查找值为x的结点&#xff1a; 思路分析&#xff1a; 单值二叉树&#xff1a; 示例&#xff1a; 思路分析&#xff1a; 相同的树&#xff1a; 示例&#xff1a; 思路分析&#xff1a; 二叉树的前序遍历&#xff1a;——使用前序遍历把结点元素放入数组中 题…

架构的模式

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容&#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作…

继承中的析构函数的权限的深入了解

如果一个父类中的析构函数如果设置为 private 权限 &#xff0c;一个子类public继承了这个父类&#xff0c;那么 这个父类可以创建对象吗&#xff1f; 答案是 不可以 看看下面的代码 class A { public:private:~A() {} };class B :public A {A a; // 这个地方编译不报错&…

微服务--08--Seata XA模式 AT模式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 分布式事务Seata 1.XA模式1.1.两阶段提交1.2.Seata的XA模型1.3.优缺点 AT模式2.1.Seata的AT模型2.2.流程梳理2.3.AT与XA的区别 分布式事务 > 事务–01—CAP理论…

MAMP Pro v6.8.1(PHP/MySQL开发环境)

MAMP Pro是一款专为Mac用户设计的全功能本地服务器软件&#xff0c;可以将电脑变成一个完整的Web开发环境。无论个人开发者、网站管理员还是团队协作&#xff0c;MAMP Pro都提供了强大的工具和便捷的管理方式&#xff0c;能够更加高效地构建和测试网站。 MAMP Pro的基本功能包括…