【数据结构】单链表的使用

单链表的使用

    • 1、基本概念
    • 2、链表的分类
    • 3、链表的基本操作
      • a、单链表节点设计
      • b、单链表初始化
      • c、单链表增删节点
        • **节点头插:**
        • **节点尾插:**
        • **新节点插入指定节点后:**
        • 节点删除:
      • d、单链表修改节点
      • e、单链表遍历,并打印数据
    • 4、链表优缺点
    • 5、完整示例代码

1、基本概念

  • 顺序表:顺序存储的线性表。
  • 链式表:链式存储的线性表,简称链表。
    既然顺序存储中的数据因为挤在一起而导致需要成片移动,那很容易想到的解决方案是将数据离散地存储在不同内存块中,然后在用来指针将它们串起来。这种朴素的思路所形成的链式线性表,就是所谓的链表。

顺序表和链表在内存在的基本样态如下图所示:

  • 顺序表:

在这里插入图片描述
链表:
在这里插入图片描述

2、链表的分类

\quad 根据链表中各个节点之间使用指针的个数,以及首尾节点是否相连,可以将链表细分为如下种类:
1.单向链表
2.单向循环链表
3.双向循环链表
\quad 这些不同链表的操作都是差不多的,只是指针数目的异同。以最简单的单向链表为例,其基本示意图如下所示:
在这里插入图片描述上图中,所有的节点均保存一个指针,指向其逻辑上相邻的下一个节点(末尾节点指向空)。
另外注意到,整条链表用一个所谓的头指针 head 来指向,由 head 开始可以找到链表中的任意一个节点。head 通常被称为头指针

3、链表的基本操作

  1. 节点设计
  2. 初始化空链表
  3. 增删节点
  4. 链表遍历(改查)
  5. 销毁链表

下面着重针对这几项常见操作,讲解单向链表的处理。

a、单链表节点设计

单向链表的节点非常简单,节点中除了要保存用户数据之外(这里以整型数据为例),只需要增加一个指向本类节点的指针即可,如下所示:

typedef struct single_list{// 数据域--》真实的数据int data;    				// 以整型数据为例// 指针域struct single_list *next; 	// //用来指向下一个元素在内存中的首地址
}single_list_t;

b、单链表初始化

\quad 首先,空链表有两种常见的形式。一种是带头结点的,一种是不带头结点的。所谓的头结点是不存放有效数据的节点,仅仅用来方便操作,如下:
在这里插入图片描述
而不带头结点的空链表如下所示:
在这里插入图片描述
\quad 由于头结点是不存放有效数据的,因此如果空链表中带有头结点,那么头指针 head 将永远不变,这会给以后的链表操作带来些许便捷。
下面以带头结点的链表为例,展示单向链表的初始化的示例代码:

single_list_t *single_list_init()
{single_list_t *head_node = malloc(sizeof(single_list_t));if (head_node != NULL){head_node->next = NULL;}return head_node;
}

c、单链表增删节点

\quad 相对于顺序表需要整片移动数据,链表增删节点只需要修改几个相关指针的指向,动作非常快速。
\quad 与顺序表类似,可以对一条链表中的任意节点进行增删操作,示例代码:

节点头插:
int insert_list_head(int newdata, single_list_t *list)
{// 申请一个节点 -堆空间single_list_t *new_node = malloc(sizeof(single_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;// 插入节点new_node->next = list->next;list->next = new_node;return 0;
}
节点尾插:
int insert_list(int newdata, single_list_t *list)
{// 申请一个节点 -堆空间single_list_t *new_node = malloc(sizeof(single_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;// 定义指针p去找到链表的尾部single_list_t *p = list;while (p->next != NULL){p = p->next;}// 此时p已经到最后一个节点的位置p->next = new_node;return 0;
}
新节点插入指定节点后:
int insert_list_mid(int olddata, int newdata, single_list_t *list)
{// 找到要插入的节点single_list_t *p = list;while (p->next != NULL){p = p->next;if (p->data == olddata) // 待插入的节点在链表中间{break;}}// 申请一个新的节点 single_list_t *new_node = malloc(sizeof(single_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;// p指向最后一个节点if (p->next == NULL){// 最后一个节点是要插入的节点if (p->data == olddata){new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点p->next = new_node;   // 再将该节点指向新增加的节点}else{printf("要插入的数据不存在\n");return -1;}}else // 遍历到中间找到需要插入的节点{new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点p->next = new_node;   // 再将该节点指向新增加的节点}return 0;
}
节点删除:
int list_delnode(int deldata, single_list_t *list)
{single_list_t *q = list;single_list_t *p = list->next;while (p->next != NULL){// 找到要删除的节点并进行删除if (p->data == deldata){q->next = p->next;  // 将q指向的节点指向被删除节点的下一个节点p->next = NULL;     // p节点的next指针指向NULLfree(p);    // 释放p后此时p是野指针p = q->next;// 将p指向被删除节点的下一个节点}else{p = p->next;q = q->next;}  }// 遍历到最后一个节点if (p->next == NULL){// 若最后一个节点是要删除的节点,则删除if (p->data == deldata){q->next = p->next;p->next = NULL;free(p);}else{printf("最后一个节点不是要删除的节点\n");return 0;}}
}

d、单链表修改节点

int list_update_node(int old_data, int new_data, single_list_t *list)
{single_list_t *p = list;while (p->next != NULL){p = p->next;  // p指向下一个节点if (p->data == old_data){p->data = new_data;}}return 0;
}

e、单链表遍历,并打印数据

int list_show(single_list_t *list)
{single_list_t *p = list;while (p->next != NULL){p = p->next;printf("当前p指向的节点数据:%d\n", p->data);}
}

4、链表优缺点

\quad 链式存储中,所有节点的存储位置是随机的,他们之间的逻辑关系用指针来确定,跟物理存储位置无关,因此从上述示例代码可以很清楚看到,增删数据都非常迅速,不需要移动任何数据。另外,又由于位置与逻辑关系无关,因此也无法直接访问某一个指定的节点,只能从头到尾按遍历的方式一个个找到想要的节点。简单讲,链式存储的优缺点跟顺序存储几乎是相对的。
总结其特点如下:

  • 优点
    a.插入、删除时只需要调整几个指针,无需移动任何数据
    b.当数据节点数量较多时,无需一整片较大的连续内存空间,可以灵活利用离散的内存
    c.当数据节点数量变化剧烈时,内存的释放和分配灵活,速度快
  • 缺点
    a.在节点中,需要多余的指针来记录节点之间的关联
    b.所有数据都是随机存储的,不支持立即访问任意一个随机数据。

5、完整示例代码

#include <stdio.h>
#include <stdlib.h>// 1.封装一个结构体来表示单链表
typedef struct single_list{int data;struct single_list *next;
}single_list_t;// 2.初始化单链表-->定义结构体变量 创建头节点
single_list_t *single_list_init()
{single_list_t *head_node = malloc(sizeof(single_list_t));if (head_node != NULL){head_node->next = NULL;}return head_node;
}// 头插
int insert_list_head(int newdata, single_list_t *list)
{// 申请一个节点 -堆空间single_list_t *new_node = malloc(sizeof(single_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;// 插入节点new_node->next = list->next;list->next = new_node;return 0;
}
/*@brief:3.插入数据-->尾插(在最后一个有效成员的后面插入数据)*@param(in):  newdata :待插入的数据  list:待插入的链表*@param(out):  *@retval:    
*/
int insert_list(int newdata, single_list_t *list)
{// 申请一个节点 -堆空间single_list_t *new_node = malloc(sizeof(single_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;// 定义指针p去找到链表的尾部single_list_t *p = list;while (p->next != NULL){p = p->next;}// 此时p已经到最后一个节点的位置p->next = new_node;return 0;
}// 中间插入
int insert_list_mid(int olddata, int newdata, single_list_t *list)
{// 找到要插入的节点single_list_t *p = list;while (p->next != NULL){p = p->next;if (p->data == olddata){break;}}// 申请一个节点 -堆空间single_list_t *new_node = malloc(sizeof(single_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;// p指向最后一个节点if (p->next == NULL){if (p->data == olddata){new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点p->next = new_node;   // 再将该节点指向新增加的节点}else{printf("要插入的数据不存在\n");return -1;}}else // 遍历到中间找到需要插入的节点{new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点p->next = new_node;   // 再将该节点指向新增加的节点}return 0;
}
// 删除节点
int list_delnode(int deldata, single_list_t *list)
{single_list_t *q = list;single_list_t *p = list->next;while (p->next != NULL){// 找到要删除的节点并进行删除if (p->data == deldata){q->next = p->next;  // 将q指向的节点指向被删除节点的下一个节点p->next = NULL;     // p节点的next指针指向NULLfree(p);    // 释放p后此时p是野指针p = q->next;// 将p指向被删除节点的下一个节点}else{p = p->next;q = q->next;}  }// 遍历到最后一个节点if (p->next == NULL){// 若最后一个节点是要删除的节点,则删除if (p->data == deldata){q->next = p->next;p->next = NULL;free(p);}else{printf("最后一个节点不是要删除的节点\n");return 0;}}
}
// 修改节点
int list_update_node(int old_data, int new_data, single_list_t *list)
{single_list_t *p = list;while (p->next != NULL){p = p->next;  // p往后移动if (p->data == old_data){p->data = new_data;}}return 0;
}// 4.遍历链表,打印节点数据
int list_show(single_list_t *list)
{single_list_t *p = list;while (p->next != NULL){p = p->next;printf("当前p指向的节点数据:%d\n", p->data);}
}int main(int argc, char const *argv[])
{// 初始化单链表single_list_t *my_list = single_list_init();// 往链表插入数据insert_list(15, my_list);insert_list(18, my_list);insert_list(15, my_list);insert_list(25, my_list);insert_list(666, my_list);insert_list(123, my_list);insert_list(11111111, my_list);insert_list_mid(666, 777, my_list);insert_list_mid(1, 222, my_list);insert_list_head(15, my_list);printf("============插入的节点============\n");list_show(my_list);printf("============插入的节点============\n");// 删除节点list_delnode(25,my_list);printf("============删除后的节点============\n");list_show(my_list); // 打印数据printf("============删除后的节点============\n");// 修改数据list_update_node(123, 234, my_list);printf("============修改后的节点============\n");list_show(my_list); // 打印数据printf("============修改后的节点============\n");return 0;
}
/*
执行结果:
要插入的数据不存在
============插入的节点============
当前p指向的节点数据:15
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:25
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:123
当前p指向的节点数据:11111111
============插入的节点============
最后一个节点不是要删除的节点
============删除后的节点============
当前p指向的节点数据:15
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:123
当前p指向的节点数据:11111111
============删除后的节点============
============修改后的节点============
当前p指向的节点数据:15
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:234
当前p指向的节点数据:11111111
============修改后的节点============
*/

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

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

相关文章

虚幻引擎是什么?

Unreal Engine&#xff0c;是一款由Epic Games开发的游戏引擎。该引擎主要是为了开发第一人称射击游戏而设计&#xff0c;但现在已经被成功地应用于开发模拟游戏、恐怖游戏、角色扮演游戏等多种不同类型的游戏。虚幻引擎除了被用于开发游戏&#xff0c;现在也用于电影的虚拟制片…

Linux(Centos 7.6)yum源配置

yum是rpm包的管理工具&#xff0c;可以自动安装、升级、删除软件包的功能&#xff0c;可以自动解决软件包之间的依赖关系&#xff0c;使得用户更方便软件包的管理。要使用yum必须要进行配置&#xff0c;个人将其分为三类&#xff0c;本地yum源、局域网yum源、第三方yum源&#…

Linux上更新jar包里的某个class文件

目标&#xff1a;替换voice-1.0.jar里的TrackHandler.class文件 一.查询jar包里TrackHandler.class所在的路径 jar -tvf voice-1.0.jar |grep TrackHandler 二.解压出TrackHandler.class文件 jar -xvf voice-1.0.jar BOOT-INF/classes/com/yf/rj/handler/TrackHandler.cla…

机器学习中回归预测模型中常用四个评价指标MBE、MAE、RMSE、R2解释

在机器学习中&#xff0c;评估模型性能时常用的四个指标包括平均绝对误差&#xff08;Mean Absolute Error, MAE&#xff09;、均方误差&#xff08;Mean Squared Error, MSE&#xff09;、均方根误差&#xff08;Root Mean Squared Error, RMSE&#xff09;和决定系数&#xf…

基于SpringBoot的Jwt认证以及密码aes加密解密技术

目录 前言 1.SpringBoot项目的创建 2.相关技术 3.项目架构 4.项目关键代码 5.项目最终的运行效果 ​编辑 6.PostMan测试接口结果 前言 学习了SpringBoot之后&#xff0c;才觉得SpringBoot真的很方便&#xff0c;相比传统的SSH&#xff0c;SSM&#xff0c;SpringBo…

Spark SQL DML语句

【图书介绍】《Spark SQL大数据分析快速上手》-CSDN博客 《Spark SQL大数据分析快速上手》【摘要 书评 试读】- 京东图书 Spark本地模式安装_spark3.2.2本地模式安装-CSDN博客 DML&#xff08;Data Manipulation Language&#xff0c;数据操作语言&#xff09;操作主要用来对…

线性直流电流

电阻网络的等效 等效是指被化简的电阻网络与等效电阻具有相同的 u-i 关系 (即端口方程)&#xff0c;从而用等效电阻代替电阻网络之后&#xff0c;不 改变其余部分的电压和电流。 串联等效&#xff1a; 并联等效&#xff1a; 星角变换 若这两个三端网络是等效的&#xff0c;从任…

B站推荐模型数据流的一致性架构

01 背景 推荐系统的模型&#xff0c;通过学习用户历史行为来达到个性化精准推荐的目的&#xff0c;因此模型训练依赖的样本数据&#xff0c;需要包括用户特征、服务端推荐的视频特征&#xff0c;以及用户在推荐视频上是否有一系列的消费行为。 推荐模型数据流&#xff0c;即为…

【LeetCode】839、相似字符串组

【LeetCode】839、相似字符串组 文章目录 一、并查集1.1 并查集 二、多语言解法 一、并查集 1.1 并查集 求共有几组, 联想到并查集, 即并查集有几个集合 字符串相似: 相差0个字符, 或2个字符 其中所有字符串长度都相同, 是比较方便处理的 // go var sets int var father […

官宣!低空经济司,挂牌成立!

近日&#xff0c;国家发展改革委网站“机关司局”栏目悄然更新&#xff0c;一个新设立的部门——低空经济发展司&#xff08;简称“低空司”&#xff09;正式进入公众视野。低空司的成立&#xff0c;无疑是对当前国家经济发展形势的深刻把握和前瞻布局。 低空经济是以各类低空飞…

不安全物联网的轻量级加密:综述

Abstract 本文综述了针对物联网&#xff08;IoT&#xff09;的轻量级加密解决方案。这项综述全面覆盖了从轻量级加密方案到不同类型分组密码的比较等多个方面。同时&#xff0c;还对硬件与软件解决方案之间的比较进行了讨论&#xff0c;并分析了当前最受信赖且研究最深入的分组…

【小程序】全局数据共享

目录 全局数据共享 1. 什么是全局数据共享 2. 小程序中的全局数据共享方案 全局数据共享 - MobX 1. 安装 MobX 相关的包 2. 创建 MobX 的 Store 实例 3. 将 Store 中的成员绑定到页面中 4. 在页面上使用 Store 中的成员 ​5. 将 Store 中的成员绑定到组件中 6. 在组件中…

自动化测试- 自动化测试模型

目录 自动化测试模型简介 1、线性模型 举例 测试页面html文件 测试脚本 2. 关键字驱动测试&#xff08;Keyword-Driven Testing&#xff09; 需测试内容 关键字驱动测试框架 创建测试用例文件 运行测试 3. 数据驱动测试&#xff08;Data-Driven Testing&#xff09; …

【GlobalMapper精品教程】091:根据指定字段融合图斑(字段值相同融合到一起)

文章目录 一、加载数据二、符号化三、融合图斑1. 根据图斑位置进行融合2. 根据指定字段四、注意事项一、加载数据 订阅专栏后,从私信中查收配套实验数据包,找到data091.rar,解压并加载,如下图所示: 属性表如下: 二、符号化 为了便于比对不同的融合结果,查看属性表根据…

strace工具使用

下载地址&#xff1a; https://github.com/strace/strace/releases/tag/v6.12 解压后执行以下命令 ./configure --hostarm-linux --prefix/home/wei/Code/strace/strace-6.12/out CC/home/wei/Code/firmware/prebuilts/host/gcc/gcc-arm-10.2-2020.11-x86_64-arm-none-linux…

图像处理-Ch2-空间域的图像增强

Ch2 空间域的图像增强 文章目录 Ch2 空间域的图像增强Background灰度变换函数(Gray-level Transformation)对数变换(Logarithmic)幂律变换(Power-Law)分段线性变换函数(Piecewise-Linear)对比度拉伸(Contrast-Stretching)灰度级分层(Gray-level Slicing) 直方图处理(Histogram …

Linux | Ubuntu零基础安装学习cURL文件传输工具

目录 介绍 检查安装包 下载安装 手册 介绍 ‌cURL是一个利用URL语法在命令行下工作的文件传输工具&#xff0c;首次发行于1997年‌‌12。cURL支持多种协议&#xff0c;包括FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3…

cesium通过经纬度获取3dtiles 得feature信息

找到这里3dtiles的两种访问方式&#xff1a; 1.1 3DTileContent#getFeature 这里涉及3DTile 数据结构&#xff0c;暂不了解3DTile 数据结构&#xff0c;因此暂不使用。 1.2 scene.pick 本次使用 scene表示虚拟场景中所有 3D 图形对象和状态的容器&#xff1b;scene中…

内置ALC的前置放大器D2538A/D3308

一、概述 D2538A/D3308是芯谷科技推出的带有ALC&#xff08;自动电平控制&#xff09;的前置音频放大器芯片&#xff0c;最初产品为单声道/立体声收录机及盒式录音机而开发&#xff0c;作为录音/回放的磁头放大器使用&#xff1b;由于产品的高增益、低噪声及ALC外部可调的特性&…

基于SSM的“快递管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SSM的“快递管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 登陆页面 注册页面 快递员页面 派单员订单管理页面 派单员订单添…