C语言:数据结构(双向链表)

news2024/11/19 11:17:22

目录

  • 1、双向链表的结构
  • 2、顺序表和双向链表的优缺点分析
  • 3、双向链表的实现

1、双向链表的结构

在这里插入图片描述

注意:这⾥的“带头“跟前面我们说的“头节点”是两个概念,实际前面的在单链表阶段称呼不严谨,但是为了更好的理解就直接称为单链表的头节点。
带头链表里的头节点,实际为“放哨的”,哨兵位节点不存储任何有效元素,只是站在这里“放哨的”。
“哨兵位”存在的意义:遍历循环链表避免死循环。

2、顺序表和双向链表的优缺点分析

不同点顺序表链表
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持O(N)
任意位置插⼊或者删除元素可能需要搬移元素,效率低只需修改指针指向
插入动态顺序表,空间不够时需要扩容没有容量的概念
应用场景元素高效存储和频繁访问任意位置频繁插入和删除

3、双向链表的实现

ListNode.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//定义双向链表节点的结构
typedef int Ltdatatype;
typedef struct ListNode
{
	Ltdatatype data;
	struct ListNode* prev;//指向前一个节点的指针
	struct ListNode* next;//指向后一个节点的指针
}ListNode;
//双向链表的初始化
ListNode* LtInit();
//尾插
//不改变哨兵位的地址,所以传一级即可
void LtPushBack(ListNode* phead, Ltdatatype x);//插入数据之前,链表必须初始化到只有一个头结点的情况
//打印链表
void LtPrint(ListNode* phead);
//头插
void LtPushFront(ListNode* phead, Ltdatatype x);
//尾删
LtPopBack(ListNode* phead);
//头删
LtPopFront(ListNode* phead);
//查找
ListNode* LtFind(ListNode* phead, Ltdatatype x);
//指定位置前插入
void LtInsert(ListNode* pos, Ltdatatype x);
//删除pos位置
void LtErase(ListNode* pos);
//销毁链表
void LtDestroy(ListNode* phead);

ListNode.c

#define _CRT_SECURE_NO_WARNINGS
#include "ListNode.h"
//申请节点
ListNode* LtBuyNode(Ltdatatype x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	//申请成功
	node->data = x;
	node->next = node->prev = node;
	return node;
}
//双向链表的初始化
ListNode* LtInit()
{
	ListNode*phead = LtBuyNode(-1);
	return phead;
}
//尾插
void LtPushBack(ListNode* phead, Ltdatatype x)
{
	assert(phead);
	ListNode* newnode = LtBuyNode(x);
	//改变新节点的指向
	newnode->prev = phead->prev;
	newnode->next = phead;
	//改变尾节点和哨兵位的指向
	phead->prev->next = newnode;
	phead->prev = newnode;
}
//打印链表
void LtPrint(ListNode* phead)
{
	ListNode* pcur = phead->next;
	//遍历链表
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}
//头插
void LtPushFront(ListNode* phead,Ltdatatype x)
{
	assert(phead);
	ListNode* newnode = LtBuyNode(x);
	newnode->prev = phead;
	newnode->next = phead->next;
	//修改哨兵位和第一个有效节点的指向
	phead->next->prev = newnode;
	phead->next = newnode;
}
//尾删
LtPopBack(ListNode* phead)
{
	//链表必须有效且链表不能为空(只有一个哨兵位)
	assert(phead && phead->next != phead);
	ListNode* Del = phead->prev;//尾节点
	ListNode* DelPrev = Del->prev;//尾节点的前一个节点
	phead->prev = DelPrev;
	DelPrev->next = phead;
	free(Del);//删除Del节点
	Del = NULL;
}
//头删
LtPopFront(ListNode* phead)
{
	//判断链表是否有效和链表是否为空
	assert(phead && phead->next != phead);
	ListNode* Del = phead->next;//第一个有效节点
	ListNode* DelNext = Del->next;//有效节点的下一个节点
	phead->next = DelNext;
	DelNext->prev = phead;
	free(Del);//删除Del节点
	Del = NULL;
}
//查找
ListNode* LtFind(ListNode* phead, Ltdatatype x)
{
	ListNode* pcur = phead->next;
	//遍历链表
	while (pcur != phead)
	{
		if (pcur->data == x)
			return pcur;
		pcur = pcur->next;//继续让pcur往下遍历
	}
	return NULL;//没有找到
}
//在pos位置之前插入数据
void LtInsert(ListNode* pos,Ltdatatype x)
{
	ListNode* newnode = LtBuyNode(x);
	newnode->prev = pos->prev;
	newnode->next = pos;
	pos->prev->next = newnode;
	pos->prev = newnode;
}
//删除pos位置
void LtErase(ListNode* pos)
{
	assert(pos);
	ListNode* PosPrev = pos->prev;//pos的前一个节点
	ListNode* PosNext = pos->next;//pos的后一个节点
	PosPrev->next = PosNext;
	PosNext->prev = PosPrev;
	free(pos);
	//pos = NULL;这里就算置空了,也不会影响实参
}
//销毁链表
void LtDestroy(ListNode* phead)
{
	ListNode* pcur = phead->next;
	//边遍历边释放节点
	while (pcur != phead)
	{
		ListNode* Next = pcur->next;//保存要释放掉节点的下一个地址
		free(pcur);
		pcur = Next;
	}
	//此时pcur指向phead,而phead还没有被销毁
	free(phead);
	pcur = NULL;
}

text.c

#define _CRT_SECURE_NO_WARNINGS
#include "ListNode.h"
void LtnodeTest()
{
	//测试初始化
	ListNode* plist = LtInit();
	//测试尾插
	LtPushBack(plist,1);
	LtPushBack(plist,2);
	LtPushBack(plist,3);
	//测试打印
	LtPrint(plist);
	//测试头插
	//LtPushFront(plist,4);
	//LtPushFront(plist,5);
	//LtPushFront(plist,6);
	//LtPrint(plist);
	//测试尾删
	LtPopBack(plist);
	LtPrint(plist);
	//测试头删
	//LtPopFront(plist);
	//LtPrint(plist);
	//测试查找
	//ListNode*find = LtFind(plist,2);
	//if (find)
	//	printf("找到了!\n");
	//else
	//	printf("没找到!\n");
	//测试在pos位置之前插入数据
	//LtInsert(find,88);
	//LtPrint(plist);
	//测试删除pos位置
	//LtErase(find);
	//find = NULL;//形参的改变不会影响实参,所以要在函数调用结束之后置为空
	//LtPrint(plist);
	//测试销毁链表
	//LtDestroy(plist);
	//plist = NULL;
}
int main()
{
	LtnodeTest();
	return 0;
}

如果对你有所帮助的话,别忘了一键三连哟,谢谢宝子们😘!

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

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

相关文章

上位机开发PyQt(五)【Qt Designer】

PyQt5提供了一个可视化图形工具Qt Designer&#xff0c;文件名为designer.exe。如果在电脑上找不到&#xff0c;可以用如下命令进行安装&#xff1a; pip install PyQt5-tools 安装完毕后&#xff0c;可在如下目录找到此工具软件&#xff1a; %LOCALAPPDATA%\Programs\Python\…

2024人工智能“百模大战“,竞争格局分析

中国“百模大战”竞争格局分析 大模型是一个重资源禀赋和高进入门槛的赛道&#xff0c;“百模大战”是一场重投入和高消耗的持久战役。“百模大战”的上半场是资源和技术的碰撞&#xff0c;入局企业需要长久的资源支持获得高密度的人才、高质量的数据和大规模的算力&#xff0c…

Vue.js课后练习(登录注册和大小比较)

第一题 请编写登录页面和注册页面&#xff0c;通过动态组件实现动态切换页面中显示的组件&#xff0c;效果如图1和图2所示。 图1 登录页面 图2 注册页面 代码&#xff1a; my.vue代码: <template>登录 </template><script setup> </script><st…

再谈有效地访问Github

文章目录 1. 知识回顾2. 问题描述3. 问题解决3.1 Mac系统3.2 Windows系统4. 内容总结1. 知识回顾 我们在之前的内容中介绍过如何有效地访问Github。如果大家忘记的话可以点击这里查看。之前的内容主要偏重于问题的分析和解决的思路,有些朋友看了后还是不清楚如何解决问题。 …

半监督节点分类:标签传播和消息传递

基础概念回顾 传统图机器学习的特征工程——节点层面&#xff0c;连接层面&#xff0c;全图层面 节点层面&#xff1a;信用卡欺诈 连接层面&#xff1a;推荐可能认识的人 全图层面&#xff1a;预测分子结构 半监督节点分类 半监督节点分类&#xff1a;用已知标签节点预测未…

【Java EE】多线程(二)Thread 类与常用方法

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

低代码工业组态数字孪生平台

2024 两会热词「新质生产力」凭借其主要特征——高科技、高效能及高质量&#xff0c;引发各界关注。在探索构建新质生产力的重要议题中&#xff0c;数据要素被视为土地、劳动力、资本和技术之后的第五大生产要素。数据要素赋能新质生产力发展主要体现为&#xff1a;生产力由生产…

linux安装Redis 7.2.4笔记

一.保姆级安装 1.下载Redis 7.2.4安装包 sudo wget https://download.redis.io/releases/redis-7.2.4.tar.gz2.解压&#xff0c;可以指定 sudo tar -zvxf redis-7.2.4.tar.gz 3.检测并安装 GCC 编译器&#xff1a; yum 是基于 Red Hat 的 Linux 发行版&#xff08;如 CentOS、…

问卷新项目新玩法,一个2-5元,零基础,日赚50-200元零花钱,适合宝妈

问卷调研是许多机构或企业为了获取大数据技术结论&#xff0c;进行抽样调查&#xff0c;进而针对特定人群进行付费调查个人行为。问卷调查内容通常涉及新产品&#xff0c;例如通过比较不同类别的商品&#xff0c;展示某些产品的优势和劣势。我们都喜欢某款手机&#xff0c;究竟…

Docker在linux安装步骤超详细

官网 Install Docker Engine on CentOS | Docker Docs yum -y install gcc yum -y install gcc-c 安装工具 sudo yum install -y yum-utils 设置国内的镜像 yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yu…

【配置】Docker搭建JSON在线解析网站

云服务器打开端口8787 连接上docker运行 docker run -id --name jsonhero -p 8787:8787 -e SESSION_SECRETabc123 henryclw/jsonhero-webhttp://ip:8787访问 Github&#xff1a;地址

AutoCAD 2025 for mac/win:设计未来,触手可及

在数字化时代&#xff0c;设计不再局限于纸笔之间&#xff0c;而是跃然于屏幕之上&#xff0c;AutoCAD 2025正是这一变革的杰出代表。无论是Mac用户还是Windows用户&#xff0c;AutoCAD 2025都以其卓越的性能和出色的用户体验&#xff0c;成为了CAD设计绘图领域的佼佼者。 Aut…

Linux修改文件权限命令 chmod

【例子引入】 以下面命令为例&#xff1a; chmod 777 Random.py 当写入下面名为Random.py的代码后&#xff1a; 如果直接运行&#xff0c;会显示权限不够 当输入 chmod 777 Random.py 更改权限后&#xff0c;才能够正常运行 在终端中输入 这条命令是关于Linux或Unix-like系…

一周学会Django5 Python Web开发 - Django5 ORM数据库事务

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计50条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Linux基础part-3

1、Linux一般系统查看类命令 【stat】命令 格式&#xff1a;stat [option] file显示文件的元数据信息&#xff0c;包括文件的权限、拥有者、大小、修改时间等。eg&#xff1a;stat myfile.txt 【file】命令 用于确定文件类型格式&#xff1a;file [option] filefile myfile.t…

逻辑漏洞:初识水平越权与垂直越权

目录 1、什么是越权漏洞呢&#xff1f; 2、水平越权 3、垂直越权 4、burpsuite autorize插件 最近在学习逻辑漏洞的相关知识和技能&#xff0c;这里pikachu靶场作为演示进行学习一下&#xff1a; pikachu靶场&#xff1a;GitHub - zhuifengshaonianhanlu/pikachu: 一个好玩…

【Web】2024XYCTF题解(全)

目录 ezhttp ezmd5 warm up ezMake ez?Make εZ?мKε? 我是一个复读机 牢牢记住&#xff0c;逝者为大 ezRCE ezPOP ezSerialize ezClass pharme 连连看到底是连连什么看 ezLFI login give me flag baby_unserialize ezhttp 访问./robots.txt 继…

运行DeepSORT_YOLOv5_Pytorch时出现的问题

文章目录 前言问题1&#xff1a;Loaderyaml.FullLoader问题2&#xff1a;utils. -> yolov5.utils.问题3&#xff1a;np.float -> float问题4&#xff1a;np.int -> int问题5&#xff1a;ImportError: cannot import name time_synchronized from yolov5.utils.torch_u…

ip ssl证书无限端口网站

IP SSL证书是由CA认证机构颁发的一种特殊数字证书。大部分SSL数字证书都需要用户使用域名进行申请&#xff0c;想要对公网IP地址加密实现https访问就需要申请IP SSL证书。IP SSL证书采用了强大的加密算法&#xff0c;可以有效地防止数据在传输过程中被窃取或篡改&#xff0c;具…