创建双向链表(详解)

article/2025/9/30 11:57:50

双向链表操作

在学习了单链表之后,就顺带学习了双链表的操作。

什么是双链表?

双链表顾名思义,就是链表由单向的链变成了双向链。 使用这种数据结构,我们可以不再拘束于单链表的单向创建于遍历等操作,大大减少了在使用中存在的问题。

在这里插入图片描述

在单链表中,我们有一个数据域,还有一个指针域,数据域用来存储相关数据,而指针域则负责链表之间的“联系”。 而在双向链表中,我们需要有两个指针域,一个负责向后连接,一个负责向前连接

/* 单链表的结构 */
struct List{int data;				//  数据域struct List *next;			//  指针域 
};/* 双向链表的结构 */
typedef struct List{int data;			// 	数据域struct List *next;		//  向后的指针struct List *front;		//  向前的指针
};typedef struct List* pElem;
typedef struct List eElem;

同单链表一样,对双向链表的操作也有创建,插入,遍历,删除,销毁

双向链表的创建

在创建双向链表的时候,我们需要初始化的有两个指针。同单链表一样,我们需要一个头指针来标志链表的信息。因此我们可以写出该函数的定义:

pElem CreatList(){pElem head = (pElem)malloc( sizeof(eElem) );assert( head != NULL );		//  包含于标准库<assert.h>head->next = head->front = NULL;		//  初始化链表,指针置空return head;
}

双向链表的插入

在单向链表的头插法中,最主要的语句自然就是tmp->next = head->next, 而在双向链表中,自然也是一样,只不过多了连接一个向前的指针而已。

void InsertElem( pElem head , int data ){if( head == NULL ){printf("The list is empty.\n");		//  头结点为空,则无法插入return;}pElem tmpHead = head;		//  创建一个临时的头结点指针if( tmpHead->next == NULL ){/*  当双向链表只有一个头结点时 */		pElem addition = (pElem)malloc( sizeof(eElem) );assert( addition != NULL );addition->data = data;		//  数据域赋值addition->next = tmpHead->next;		//  后向指针连接tmpHead->next = addition;addition->front = tmpHead;			//  将插入结点的front 指向头结点}else{/* 当双向链表不只一个头结点时 */pElem addition = (pElem)malloc( sizeof(eElem) );assert( addition != NULL );addition->data = data;		//  数据域赋值tmpHead->next->front = addition;		//  头结点的下一个结点的front 指针addition->front = tmpHead;		//  插入的结点的front 指针指向头结点addition->next = tmpHead->next;		//  插入结点的next 指针指向原本头指针的下一结点tmpHead->next = addtion;		//  将头结点的next 指针指向插入结点}
}

许多人肯定是被最后四条语句弄得一脸懵逼,都一样。但是当你画出图像时,你就会懂得一切。

在这里插入图片描述

我们创建一个新的结点addition, 此时链表中只有头结点,因此执行if中的程序,执行完毕之后就变成了:
在这里插入图片描述

具体步骤有以前的博客《创建单链表的头插法与尾插法详解》。

而当链表中不只有一个头结点时,这时有点意思了。

此时,headnext指针指向additionfront指针指向NULLadditionnext指向NULLfront 指针指向head
此时,我们要在链表中再插入一个新的结点。 此时,不只要对next 链进行断链,增链,还要对front 链进行同样操作。这样才能完成两条链的连接。

双向链表的遍历

不同于单链表的单向遍历,双向链表提供了操作的便捷性,可前可后的遍历方式简直聊咋咧… 因此在遍历中将实现next 的向后遍历,也会实现front的向前遍历。

void IlluList( pElem head ){printf("-------------------------------\n");if( head == NULL ){printf("The list is empty.\n");return;}pElem tmpHead = head;while( tmpHead->next != NULL ){tmpHead = tmpHead->next;		//  头结点数据域为空,因此直接从头结点的下一结点开始遍历printf("%d\n",tmpHead->data);}//  此时tmpHead 的地址在链表的最后一个结点处while( tmpHead->front->front != NULL ){printf("%d\n",tmpHead->data);		//	最后一个结点要输出tmpHead = tmpHead->front;}printf("%d\n",tmpHead->data);return;
}

当向后遍历完成之后,此时tmpHead的地址是链表的最后一个结点的地址,因此使用front 来进行向前的遍历。 如果判断条件是tmpHead->front != NULL 的话,会将头结点的数据域也输出,然头结点的数据域未使用,因此会输出一个不确定的值。 正因如此将判断条件定为tmpHead->front->front != NULL

删除一个结点

当删除一个结点的时候,我们要判断在链表中是否存在与之匹配的结点,有的话删除成功,否则失败。
在这里插入图片描述

就像这幅图一样,当删除addition结点时,先讲addition的下一个结点与head相连,而下一个结点是NULL , 因此可以得出函数为:

void DeleteElem( pElem head , int data ){if( head == NULL ){printf(""The list is empty.\n);return;}pElem tmpHead = head;while( tmpHead->next != NULL ){tmpHead = tmpHead->next;if( tmpHead->data == data ){tmpHead->front->next = tmpHead->next;		//  将被删结点的上一个结点的next 指针指向 被删结点的下一个结点tmpHead->next->front = tmpHead->front;		//  将被删结点的下一个结点的 front 指针指向 被删结点的上一个结点break;}}free(tmpHead);		//  释放内存
}

销毁链表

销毁一个双向链表的操作同单链表的相似。指针不断向后运动,每运动一个结点,释放上一个结点。

void DestroyList( pElem head ){pElem tmp;while( head->next != NULL ){tmp = head;		//  指针不断后移head = head->next;free(tmp);}free(head);
}

这里相对容易理解。
在这里插入图片描述
此时,tmp的地址就是head的地址,但当执行一个之后,就变成了这样。
在这里插入图片描述
上一次执行完之后,头结点已经被释放 ,此时头结点就在第一个数据结点处。 以此往后,最后循环结束,释放最后一个结点。

这样就是双向链表的基本操作


http://chatgpt.dhexx.cn/article/mnPdVkX1.shtml

相关文章

如何构建一个简单链表

如何构建一个简单链表 一、 含构造函数和默认实参的结构体 typedef struct node {int data;struct node* next;node(int data 0, struct node* next NULL): data(data), next(next) {}} node; 二、 创建一个一定长度的链表 (一) 错误样例&#xff1a; int n 3;node* head …

C++:创建链表的过程详解

创建链表的过程详解 本人是一名刚开始学习算法的小白&#xff0c;今天遇到了一些关于链表的创建问题&#xff0c;查了一些资料&#xff0c;我把它们整理了一下&#xff0c;希望大家多多指教。 整体的代码&#xff1a; #include<iostream> using namespace std;struct …

链表的创建与使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目录 文章目录 前言 一、链表是什么&#xff1f; 二、链表的创建与基本操作 1.链表的创建 3.链表的头插 4.链表的尾插 5.链表的销毁 6.链表的查找 7.链表的删除…

链表的创建

目录 一&#xff1a;链表的定义 二&#xff1a;链表的改进 链表的实现可以为后面JAVA的类集框架服务。 链表是一种最简单的数据结构&#xff0c;其主要目的是依靠引用关系实现多个数据的保存。 一&#xff1a;链表的定义 定义一个Node类&#xff0c;保存的数据是String型&a…

C语言之创建链表

自己琢磨着思考了一下书上的单链表的创建案例&#xff0c;记录一下自己的理解 代码如下&#xff1a; #include<stdio.h> #include<stdlib.h>struct Student{char cName[20];int age;struct Student* pNext; }; /*节点数量*/ int iCount0;/*创建链表的函数 返回头…

如何创建链表?

链表&#xff1a; 链表的组成其实很简单&#xff0c;就是由很多结点组成的。 一个结点包含数据域和指针域&#xff0c;数据域用来存放数据&#xff0c;指针域负责指向其他结点&#xff0c;起到链接的作用。创建链表&#xff1a; 其实创建一个链表也很简单&#xff0c;在我看来…

用CodeBlocks写SFML程序

vs2019 写sfml程序简直杀鸡用牛刀&#xff0c;vs2019占用资源太大了。 所以我想到了用Dev-C&#xff0c;然而我不会配置&#xff0c;卑鄙的CSDN相关资料查阅需要VIP&#xff0c;然而VIP太贵了。 SFML官方教程是用Code::Blocks&#xff0c;于是去下一个。 setup安装........ …

[笔记]使用SFML来生成分形图片

前言 最近在上《优秀科普纪录片》时&#xff0c;看了一部有关 分形 的纪录片&#xff0c;在观看的过程中&#xff0c;想着自己也来生成一些分形图片&#xff0c;正好偶然了解到了SFML这个简单的图形库&#xff0c;所以天时地利人和&#xff0c;正好查一些资料来学习一下。 以…

SFML环境配置

材料&#xff1a; 1.visual studio 2017 2.SFML-2.5.1-windows-vc15-32-bit 准备阶段 1.进入SFML官网下载sfml-vs2017-32bit版本 2.将该压缩包解压在一个文件夹中 步骤&#xff1a; 1.进入vs&#xff0c;在上述文件夹中新建Empty Project&#xff0c;右键资源文件->添加-…

[SFML] 多个OpenGL上下文

代码 #include <iostream> #include <gl/glew.h> #include <SFML/Graphics.hpp> #include <windows.h>int main() {auto getInstance [](){return (HINSTANCE)GetModuleHandle(nullptr);};auto debug [](GLenum source, GLenum type, GLuint id, GL…

SFML配置问题

先去下载安装包&#xff0c;这里我就不多说了&#xff0c;我想说的是其中的报错问题&#xff0c;按照我所说的对照下去&#xff0c;一般不会出现报错现象。 ** 第一步&#xff1a; **找到项目属性&#xff0c;这里我选择所有配置和所有平台&#xff0c;你们也可以选择其他的。…

SFML+vs2019安装

SFMLvs2019安装 1.创建一个c空项目 2.打开属性管理器 3.添加新项目属性表 在64下单击鼠标右键 添加成功后回到属性表64找到刚刚添加的属性表单击鼠标右键–>属性单击 找到SFML安装目录的include&#xff0c;复制路径粘贴到C/C->常规–>附加包含目录 找到SFM…

SFML初学-俄罗斯方块实现

偶然看到大神使用 SFML 制作游戏&#xff0c;简单学习了一下这个库的使用并且仿照YouTube上大神的思路做了一个俄罗斯方块&#xff0c;目前只实现了出现方块、消除方块的功能&#xff0c;随着慢慢学习一点点继续修改吧&#xff1b; 资源&#xff1a; 源码&#xff1a; /*******…

使用c++SFML制作月圆之夜总集篇

写在开头 重新以时间线的形式整理一下去年使用c的SFML库制作月圆之夜&#xff08;游戏程序设计大作业&#xff09;的开发过程&#xff0c;括号里面是新的补充以及对一年前自己的吐槽 因为是在大二转专业后做首次接触游戏开发后才做的&#xff0c;当时c学习得并不好&#xff0…

SFML loadFromFile()出错:failed to load image

解决方法&#xff1a;确保你的依赖项和你的运行库一致。 如果你的附加依赖项&#xff08;即动态链接库的.lib文件&#xff09;是debug版本&#xff0c;即以-d结尾。那么你的运行库也必须为debug版&#xff0c;即MDd。&#xff08;如下&#xff09; 附加依赖项的位置&#xff1…

用c++和SFML实现简易的界面版贪吃蛇

运行截图 等待开始界面 运行过程 失败界面截图 SFML配置 csdn上面已经有很多SFML配置的blog&#xff0c;随便就能搜到。正常配置好SFML后&#xff0c;还需要将字体ttf文件放在源代码同一目录和exe同一目录中&#xff0c;不然无法显示字符 代码部分 下面贴上各个部分的代码 …

VS2017、VS2019配置SFML

一、sfml官网下载32位的版本 一样的设置&#xff0c;64位的版本我没有成功&#xff0c;用不了。 https://www.sfml-dev.org/ bin目录下的文件拷贝到System32和SysWOW64里面。 二、 鼠标右击红色处&#xff0c;弹出菜单&#xff0c;点最后那个属性。 如果不是win32&#xff0c;…

VS2019配置SFML

VS2019配置SFML 1.下载安装SFML SDK 网址&#xff1a;https://www.sfml-dev.org/download.php 解压并放在文件夹里&#xff0c;记住这个路径。 在我的电脑中这个路径是F:\CProjects\_library\SFML-2.5.1 2.VS新建一个C控制台项目 我命名为SfmlTest&#xff0c;并放在常用的项…

sfml-tutorials 官方教程 windows篇

系列文章 SFML-windows 篇 SFML-Events explained 篇 SFML-Keyboard, mouse and joystick 篇 SFML-Using OpenGL in a SFML window 篇 SFML-Drawing 2D stuff 篇 SFML-Shapes 篇 SFML-Sprites and textures 篇 文章目录 系列文章打开一个windows执行windows绘制windows控制帧速…

SFML基础

原文地址&#xff1a;https://www.cnblogs.com/karl07/p/10285692.html (1) 窗口和交互 创建一个新窗口&#xff1a; sf::RenderWindow window(sf::VideoMode(500,500),"new window"); 但是光创建一个窗口并不能显示 还要加一个循环 while (window.isOpen()){sf:…