《数据结构:C语言实现双链表》

news2024/9/19 4:54:46

文章目录

    • 一、链表的分类
    • 二、双向链表
        • 1、概念与结构
    • 三、双向链表实现
        • 1、双向链表要实现的功能
        • 2、哨兵位初始化
        • 3、双链表头插数据
        • 4、判断链表是否为空
        • 5、打印链表数据
        • 6、尾插数据
        • 7、头删数据
        • 8、尾删数据
        • 9、寻找数据所在结点
        • 10、在任意结点之后插入数据
        • 11、删除任意结点
        • 12、销毁链表

一、链表的分类

链表的结构非常多样,以下情况组合起来就有八种(2×2×2)链表结构:

在这里插入图片描述

虽然有这么多的链表的结构,但我们实际中最常用的还是两种结构:单链表和双向带头循环链表.

  • 1、无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。
  • 2、带头双向循环链表:结构复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单,后面我们代码实现了就知道了。

二、双向链表

1、概念与结构

在这里插入图片描述

  • 注意:这⾥的“带头”跟前⾯我们说的“头结点”是两个概念,实际前⾯的在单链表阶段称呼不严谨.

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

三、双向链表实现

1、双向链表要实现的功能

List.h文件中:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int LTDateType;

typedef struct ListNode
{
	LTDateType date;
	struct ListNode* next;//存放下个节点的地址
	struct ListNode* prev;//存放上一个结点的地址
}LT;

//初始化哨兵位
void LTInit(LT** pphead);

//初始化哨兵位,串一级指针更方便
LT* LTInit02();

//头插
void LTPushFornt(LT* phead,LTDateType x);

//尾插
void LTPushBack(LT* phead,LTDateType x);

//打印数据
void LTPrint(LT* phead);

//头删
void LTPopFront(LT* phead);

//尾删
void LTPopBack(LT* phead);

//判断链表是否为空
bool LTEmpty(LT* phead);

//返回数据所在结点
LT* LTFind(LT* phead, LTDateType x);

//在pos结点之后插入数据
void LTInsert(LT* pos, LTDateType x);

//删除pos结点的数据
void LTErase(LT* pos);

//销毁结点
void LTDesTroy(LT** pphead);

//穿一级指针销毁,需要手动置空
void LTDeaTroy02(LT* phead);
2、哨兵位初始化
//开辟结点空间
LT* LTBuyNode(LTDateType x)
{
	LT* newnode = (LT*)malloc(sizeof(LT));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	newnode->date = x;
	newnode->next = newnode;
	newnode->prev = newnode;
}


//初始化哨兵位
void LTInit(LT** pphead)
{
	assert(pphead != NULL);
	*pphead = LTBuyNode(-1);
}

//初始化哨兵位,串一级指针更方便
LT* LTInit02()
{
	LT* newnode = LTBuyNode(-1);
	return newnode;
}
3、双链表头插数据
//头插
void LTPushFornt(LT* phead, LTDateType x)
{
	assert(phead != NULL);
	LT* newnode = LTBuyNode(x);
	newnode->next = phead->next;
	newnode->prev = phead;
	phead->next->prev = newnode;
	phead->next = newnode;

}
4、判断链表是否为空
//判断链表是否为空
bool LTEmpty(LT* phead)
{
	assert(phead != NULL);

	return phead->prev == phead;
}
5、打印链表数据
//打印数据
void LTPrint(LT* phead)
{
	assert(phead != NULL);
	LT* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->date);
		pcur = pcur->next;
	}
	printf("\n");
}
6、尾插数据
//尾插
void LTPushBack(LT* phead, LTDateType x)
{
	assert(phead != NULL);
	LT* newnode = LTBuyNode(x);
	newnode->prev = phead->prev;
	newnode->next = phead;
	phead->prev->next = newnode;
	phead->prev = newnode;
}
7、头删数据
//头删
void LTPopFront(LT* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LT* del = phead->next;
	phead->next = del->next;
	del->next->prev = phead;
	free(del);
	del = NULL;
}
8、尾删数据
//尾删
void LTPopBack(LT* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LT* del = phead->prev;
	phead->prev = del->prev;
	del->prev->next = phead;
	free(del);
	del = NULL;
}
9、寻找数据所在结点
//返回数据所在结点
LT* LTFind(LT* phead, LTDateType x)
{
	assert(phead);
	LT* pcur = phead->next;
	while (pcur != phead)
	{
		if (pcur->date == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}
10、在任意结点之后插入数据
//在pos结点之后插入数据
void LTInsert(LT* pos, LTDateType x)
{
	assert(pos != NULL);
	LT* newnode = LTBuyNode(x);
	newnode->next = pos->next;
	newnode->prev = pos;
	pos->next->prev = newnode;
	pos->next = newnode;
}
11、删除任意结点
//删除pos结点的数据
void LTErase(LT* pos)
{
	assert(pos);
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
	pos = NULL;
}
12、销毁链表
//销毁结点
void LTDesTroy(LT** pphead)
{
	assert(pphead);
	LT* pcur = (*pphead)->next;
	while (pcur != *pphead)
	{
		LT* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	free(*pphead);
	*pphead = pcur = NULL;
}

//穿一级指针销毁,需要手动置空
void LTDeaTroy02(LT* phead)
{
	assert(phead);
	LT* pcur = phead->next;
	while (pcur != phead)
	{
		LT* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	free(phead);
	phead = pcur =NULL;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

debian 更新源

前言 实现一键替换在线源 一键更新源 Debian 全球镜像站以下支持现有debian 11 12 echo "Delete the default source" rm -rf /etc/apt/sources.listecho "Build a new source" cat <<EOF>>/etc/apt/sources.list.d/debian.sources Types:…

Shell的正确使用

目录 shell 介绍 变量名的定义规则 变量名定义&#xff1a; 删除变量 特殊的变量名&#xff1a; 算术运算符 逻辑运算符&#xff1a; (1)整数之间比较 (2)按照文件权限进行判断 (3)按照文件类型判断 (4)多条件判断 常用的特殊字符&#xff1a; 条件选择、判断 if判…

PHP上门按摩专业版防东郊到家系统源码小程序

&#x1f486;‍♀️【尊享级体验】上门按摩专业版&#xff0c;告别东郊到家&#xff0c;解锁全新放松秘籍&#xff01;&#x1f3e0;✨ &#x1f525;【开篇安利&#xff0c;告别传统束缚】&#x1f525; 亲们&#xff0c;是不是厌倦了忙碌生活中的疲惫感&#xff1f;想要享…

NET 语言识别,语音控制操作、语音播报

System.Speech. 》》System.Speech.Synthesis; 语音播报 》》System.Speech.Recognition 语音识别 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Speech.Recog…

[Redis]典型应用——分布式锁

什么是分布式锁&#xff1f; 在一个分布式系统中&#xff0c;也会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制&#xff0c;避免出现类似于"线程安全"的问题 举个例子&#xff0c;在平时抢票时&#xff0c;多个用户可能会同时买票&#…

Linux——多路复用之poll

目录 前言 一、poll的认识 二、poll的接口 三、poll的使用 前言 前面我们学习了多路复用的select&#xff0c;知道多路复用的原理与select的使用方法&#xff0c;但是select也有许多缺点&#xff0c;导致他的效率不算高。今天我们来学习poll的使用&#xff0c;看看poll较于…

利用AI与数据分析优化招聘决策

一、引言 在竞争激烈的职场环境中&#xff0c;招聘是组织获取人才、实现战略目标的关键环节。然而&#xff0c;传统的招聘方式往往依赖人力资源部门的主观经验和直觉&#xff0c;难以准确预测招聘效果&#xff0c;评估招聘渠道的效率。随着人工智能&#xff08;AI&#xff09;…

Windows右键新建Markdown文件类型配置 | Typora | VSCode

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天毛毛张分享的是如何在右键的新建菜单中添加新建MarkdownFile文件&#xff0c;这是毛毛张分享的关于Typora软件的相关知识的第三期 文章目录 1.前言&#x1f3dd;…

Android车载MCU控制音量和ARM控制音量的区别和优缺点—TEF6686 FM/AM芯片

不要嫌前进的慢&#xff0c;只要一直在前进就好 文章目录 前言一、系统架构图1.MCU控制音量的架构图&#xff08;老方法&#xff09;2.ARM控制音量的架构图&#xff08;新方法&#xff09; 二、为啥控制音量不是用AudioManager而是执着去直接控制TDA7729&#xff1f;三、MCU控制…

[数据集][目标检测]婴儿车检测数据集VOC+YOLO格式1073张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1073 标注数量(xml文件个数)&#xff1a;1073 标注数量(txt文件个数)&#xff1a;1073 标注…

Matlab基础语法篇(下)

Matlab基础语法&#xff08;下&#xff09; 一、逻辑基础&#xff08;一&#xff09;逻辑运算符&#xff08;二&#xff09;all、any、find函数&#xff08;三&#xff09;练习 二、结构基础&#xff08;一&#xff09;条件结构&#xff08;1&#xff09;if-elseif-else-end&am…

通过albumentation对目标检测进行数据增强(简单直接)

albumentation官方文档看不懂&#xff1f;xml文件不知道如何操作&#xff1f;下面只需要修改部分代码即可上手使用 要使用这个方法之前需要按照albumentation这个库还有一些辅助库,自己看着来安装就行 pip install albumentation pip install opencv-python pip install json…

<数据集>蛋壳裂缝检测数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;2520张 标注数量(xml文件个数)&#xff1a;2520 标注数量(txt文件个数)&#xff1a;2520 标注类别数&#xff1a;2 标注类别名称&#xff1a;[crack, egg] 序号类别名称图片数框数1crack245128352egg25142514 使…

揭秘饲料制粒机:生产颗粒料加工的利器

随着现代畜牧业的发展&#xff0c;饲料的质量和加工效率成为了养殖业者关注的焦点。在这个背景下&#xff0c;饲料制粒机——这一饲料加工设备的核心&#xff0c;凭借其稳定、环保的特点&#xff0c;逐渐加入养殖行业中。 一、饲料制粒机的工作原理 饲料制粒机主要通过挤压、切…

msyql (8.4,9.0) caching_sha2_password 转换 mysql_native_password用户认证

mysql 前言 caching_sha2_password 主要特性 用于增强用户账户密码的存储和验证安全性。这种插件利用 SHA-256 散列算法的变体来存储和验证密码 安全的密码散列&#xff1a; caching_sha2_password 使用基于 SHA-256 的算法来生成密码的散列值。这意味着即使数据库被未授权访…

【JS特效之手风琴效果】基于jquery实现手风琴网页特效(附源码)

HTMLCSSJS手风琴效果目录 &#x1f354;涉及知识&#x1f964;写在前面&#x1f367;一、网页主题&#x1f333;二、网页效果&#x1f40b;三、网页架构与技术3.1 脑海构思3.2 实现原理 &#x1f308;四、网页源码4.1 手风琴模块4.2 完整源码获取方式 &#x1f305; 作者寄语 &…

机械学习—零基础学习日志(高数05——函数概念与特性)

零基础为了学人工智能&#xff0c;真的开始复习高数 本小节讲解隐函数&#xff0c;有点神奇&#xff0c;我竟然完全没有隐函数记忆了。 隐函数 隐函数&#xff0c;我个人通俗理解就是&#xff0c;在复杂的环境里&#xff0c;发现纯净天地。例如&#xff0c;在外太空的某个大陆…

《JavaSE》---14.<面向对象系列之(附:this和super关键字)>

目录 系列文章目录 前言 一、为什么要有this引用 1. 用代码看有this与无this的区别 1.1 代码示例 1.2 输出结果&#xff1a; 1.3 代码示例&#xff1a; 1.4 输出结果&#xff1a; 2. this深度理解 3. 什么是this引用 3.1 this引用的概念 4. this引用的特性 二、th…

【TAROT学习日记】韦特体系塔罗牌学习(5)——皇帝 THE EMPEROR IV

韦特体系塔罗牌学习&#xff08;5&#xff09;——皇帝 THE EMPEROR IV 目录 韦特体系塔罗牌学习&#xff08;5&#xff09;——皇帝 THE EMPEROR IV牌面分析1. 基础信息2. 图片元素 正位牌意1. 关键词/句2.爱情婚姻3. 学业事业4. 人际财富5. 其他象征意 逆位牌意1. 关键词/句2…

大盘周期性复苏之际,英诺赛科的新叙事如何开讲?

半导体行业已经开始周期性复苏。 据同花顺iFinD统计&#xff0c;截至目前&#xff0c;已有37只半导体个股披露了上半年业绩预告&#xff0c;其中27股预喜&#xff0c;或扭亏或预增&#xff0c;预喜率超七成&#xff0c;长川科技净利预增幅度位居第一&#xff0c;暂列上半年半导…