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

news2024/11/29 10:43:37

哈喽铁子们,这里是博主鳄鱼皮坡。这篇文章将分享交流双向链表的相关知识,下面正式开始。

1. 双向链表的结构

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

2. 双向链表的实现

以尾插为例:

第一步:assert(phead); 防止为空。

第二步:创建新节点,和单链表一样用LTBuyNode()函数即可。

第三步:先将新节点指向原链表,由双向链表的特性,我们就不需要像单链表一样遍历去找。newnode->prev即为上图的d3。

       (1) newnode->prev = phead->prev;先将新节点的头部指向原链表的最后一个节点,即d3。

       (2) newnode->next = phead;而后将新节点的尾部指向原链表的哨兵位。

第四步:将原链表相应的位置指向新节点

       (1)phead->prev->next = newnode;原链表的最后节点尾部指向新节点

       (2)phead->prev = newnode;原链表的哨兵位头部指向新节点

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
    
	assert(phead);
	LTNode* newnode = LTBuyNode(x);

	//phead phead->prev newnode
	newnode->prev = phead->prev;
	newnode->next = phead;

	phead->prev->next = newnode;
	phead->prev = newnode;
}

只要理清楚双向链表节点的指向关系,之后和单链表结构相似。

双链表的代码如下: 

//List.c
#include"List.h"

void LTPrint(LTNode* phead)
{
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}

//申请节点
LTNode* LTBuyNode(LTDataType x)
{
	LTNode* node = (LTNode*)malloc(sizeof(LTNode));
	if (node == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	node->data = x;
	node->next = node->prev = node;

	return node;
}
//初始化
//void LTInit(LTNode** pphead)
//{
//	//给双向链表创建一个哨兵位
//	*pphead = LTBuyNode(-1);
//}
LTNode* LTInit()
{
	LTNode* phead = LTBuyNode(-1);
	return phead;
}

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* newnode = LTBuyNode(x);

	//phead phead->prev newnode
	newnode->prev = phead->prev;
	newnode->next = phead;

	phead->prev->next = newnode;
	phead->prev = newnode;
}

//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* newnode = LTBuyNode(x);

	//phead newnode phead->next
	newnode->next = phead->next;
	newnode->prev = phead;

	phead->next->prev = newnode;
	phead->next = newnode;
}

//尾删
void LTPopBack(LTNode* phead)
{
	//链表必须有效且链表不能为空(只有一个哨兵位)
	assert(phead && phead->next != phead);

	LTNode* del = phead->prev;
	//phead del->prev del
	del->prev->next = phead;
	phead->prev = del->prev;

	//删除del节点
	free(del);
	del = NULL;
}

//头删
void LTPopFront(LTNode* phead)
{
	assert(phead && phead->next != phead);
	
	LTNode* del = phead->next;
	
	//phead del del->next
	phead->next = del->next;
	del->next->prev = phead;

	//删除del节点
	free(del);
	del = NULL;
}

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

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);

	LTNode* newnode = LTBuyNode(x);
	//pos newnode pos->next
	newnode->next = pos->next;
	newnode->prev = pos;

	pos->next->prev = newnode;
	pos->next = newnode;
}

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

	free(pos);
	pos = NULL;
}

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;
}
//List.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//定义节点的结构
//数据 + 指向下一个节点的指针
typedef int SLTDataType;

typedef struct SListNode {
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);

//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead);

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);

//销毁链表
void SListDesTroy(SLTNode** pphead);

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

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

在接下来我们将会学习利用实现贪吃蛇小游戏等有意思的东西,如果本篇有不理解的地方,欢迎私信我或在评论区指出,期待与你们共同进步。创作不易,望各位大佬一键三连!

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

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

相关文章

【教程】DGL单机多卡分布式GCN训练

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ PyTorch中的DDP会将模型复制到每个GPU中。 梯度同步默认使用Ring-AllReduce进行&#xff0c;重叠了通信和计算。 示例代码&#xff1a; 视频&#xff1…

C++怎么根据变量名称返回变量的值?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 有点好奇你这么做是为了什么。…

[Redis] Redis Desktop Manager 安装包和连接和创建流程

1. 安装流程就是next&#xff0c;就可以。 2. 分别填写好&#xff1a; Name(自定义&#xff0c;redis这个库展示的名字), Host, Port, Auth(Redis 的连接password) 3. 要勾选上Use SSL Protocol 选项&#xff0c; 4. 连接到redis上&#xff0c;展示不同的database&#xff0c;…

cad标注尺寸很简单,这三个方法很好掌握!

在CAD&#xff08;计算机辅助设计&#xff09;的广阔领域中&#xff0c;标注尺寸是至关重要的一环。无论是初入CAD领域的新手&#xff0c;还是经验丰富的设计师&#xff0c;掌握标注尺寸的技巧都是提升工作效率和准确性的关键。今天&#xff0c;我们就来分享三个简单而实用的方…

AIGC数字人视频生成解决方案,赋能广电电视内容生产

AI数字人可以有效加大人工智能在内容生产的应用&#xff0c;推动广电电视节目创意生产&#xff0c;提高生产效率的同时&#xff0c;还能提升节目质量&#xff0c;增强互动呈现&#xff0c;为观众提供更加精彩的视听产品。 广州虚拟动力作为3D、AI数字人技术服务商及方案提供商…

5款非常好用的小众软件,你值得拥有

​ 今天为大家推荐五款不常见但好用的win10软件&#xff0c;它们都有着各自的特色和优势&#xff0c;相信你会喜欢的。 1. 文件夹查看——Folder Size View ​ Folder Size View是一款高效的文件夹大小查看工具&#xff0c;它能够快速扫描并展示文件夹及其子文件夹的占用空间…

np.array()按权重求平均值详解

代码如下&#xff1a; a np.array([[1, 4, 2, 6],[10, 41, 7, 3],[9, 1, 6, 2]]) v1 np.average(a, weights[3, 3, 4], axis0) print(v1) 运行结果 当执行这段代码时&#xff0c;np.average(a, weights[3, 3, 4], axis0)会根据指定的权重在列方向上计算加权平均值。 具体计…

告别枯燥:Python数据处理也可以很有趣

想要成为数据处理的超级英雄吗&#xff1f;阿佑将带你一探究竟&#xff01;我们将深入数据村&#xff0c;学习如何使用Python的超能力处理各种复杂的数据格式。从解码错误和字符集问题的解决&#xff0c;到大数据量的性能优化&#xff0c;再到数据验证与清洗&#xff0c;每一个…

git clone 项目报“鉴权失败”的解决办法

#问题展示# git clone https://gitee.com/soaringsoft/.....git 正克隆到...... Username for https://gitee.com:...... Password for https://.....gitee.com:...... remote: [session-1440f183] Unauthorized fatal: git clone https://gitee.com/soaringsoft/.....gi…

SpringMVC框架学习笔记(七):处理 json 和 HttpMessageConverter 以及文件的下载和上传

1 处理 JSON-ResponseBody 说明: 项目开发中&#xff0c;我们往往需要服务器返回的数据格式是按照 json 来返回的 下面通过一个案例来演示SpringMVC 是如何处理的 &#xff08;1&#xff09; 在web/WEB-INF/lib 目录下引入处理 json 需要的 jar 包&#xff0c;注意 spring5.x…

推荐网站(22)GeoSpy,根据图片显示地理位置

今天推荐一款名为GeoSpy的AI工具。它利用人工智能技术&#xff0c;通过分析照片中的光线、植被、建筑风格等细节线索&#xff0c;实现对拍摄地点的精确定位。令人难以置信的是,它对位置的定位准确度非常高。 GeoSpy之所以智能如此,是因为它将输入的照片与大量的街景和地理图像…

夹层辊能否解决智能测径仪量程不足的问题?

关键字:智能测径仪,测径仪夹层辊,测径仪量程,夹层辊作用,测径仪量程不足, 智能测径仪是一种高精度的测量设备&#xff0c;主要用于检测线材、管材等圆柱形物体的直径尺寸。在测径仪中&#xff0c;夹层辊是测径仪的关键部件之一&#xff0c;它负责引导和支撑被测物体&#xff0c…

Astar路径规划算法复现-python实现

# -*- coding: utf-8 -*- """ Created on Fri May 24 09:04:23 2024"""import os import sys import math import heapq import matplotlib.pyplot as plt import time 传统A*算法 class Astar:AStar set the cost heuristics as the priorityA…

企业里面最常用的6大管理系统!附6个模板下载!

企业管理系统旨在帮助企业优化工作流程&#xff0c;提高工作效率的信息化系统。它通过对一些流程的规范&#xff0c;可以极大地减少企业存在的一些流程重复造成的浪费&#xff0c;并通过规范每个员工的动作来提高效率。企业在选择管理系统时&#xff0c;注重功能的全面性、流程…

CentOS7下快速升级至OpenSSH9.7p2安全版本

一、CentOS7服务器上编译生成OpenSSH9.3p2的RPM包 1、编译打包的shell脚本来源于该项目 https://github.com/boypt/openssh-rpms解压zip项目包 unzip openssh-rpms-main.zip -d /opt cd /opt/openssh-rpms-main/ vim pullsrc.sh 修改第23行为source ./version.env 2、sh pull…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(三十一)- 微服务(11)

12.7 DSL查询语法 查询的基本语法 GET /indexName/_search{"query": {"查询类型": {"查询条件": "条件值"}}} 查询所有 GET /hotel/_search{"query": {"match_all": {}}} 12.7.1 全文检索查询 全文检索查询,会…

OZON云仓靠谱吗,OZON云仓垫资提货模式

在电商飞速发展的今天&#xff0c;物流仓储成为了支撑整个电商生态的重要基石。OZON云仓作为市场上新兴的仓储物流服务提供商&#xff0c;凭借其先进的技术和灵活的服务模式&#xff0c;受到了不少电商卖家和消费者的关注。但随之而来的是一系列疑问&#xff1a;OZON云仓靠谱吗…

【八股系列】react里组件通信有几种方式,分别怎样进行通信?

文章目录 1. props传递&#xff08;父向子通信&#xff09;:2. 回调函数作为props&#xff08;子向父通信&#xff09;:3. Context API&#xff1a;4. Redux或MobX等状态管理库&#xff1a;4.1 Redux使用示例 5. refs&#xff1a; 1. props传递&#xff08;父向子通信&#xff…

社区新标准发布!龙蜥社区标准化 SIG MeetUp 圆满结束

5 月 31 日&#xff0c;「龙蜥社区“走进系列”」第 9 期之走进阿里云于北京圆满结束。来自阿里云、浪潮信息、红旗软件、中兴通讯|中兴新支点、中科曙光、中科方德、统信软件、麒麟软件、万里红、普华基础软件、飞腾信息、凝思、申威、新华三等公司的 30 余位专家出席会议。会…

C#开源软件:OneNote组件oneMore轻松打造自己的公众号编辑器

OneMore是一款为Microsoft OneNote设计的插件&#xff0c;它提供了许多扩展功能来增强OneNote的使用体验。 插件功能概述&#xff1a; OneMore插件拥有多达一百多个扩展功能&#xff0c;这些功能覆盖了笔记编辑、搜索、导出等多个方面&#xff0c;为用户提供了更加便捷和高效的…