当前位置: 首页 > news >正文

数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解

单链表理论知识详解

文章目录

  • 单链表理论知识详解
  • 1.单链表的定义
  • 2.单链表的初始化
  • 3.单链表的插入和删除
    • 3.1 单链表的插入
      • 3.1.1 按位序插入
      • 3.1.2 在指定结点的前后插入
        • 一.后插操作
        • 二.前插操作
  • 4.单链表的删除
    • 4.1 按位序删除
      • 4.2 指定结点的删除
  • 5.单链表的查找
    • 5.1 按位序查找
    • 5.2 按值查找
    • 补充一个:求表的长度
  • 6. 单链表的建立(带头结点的建立)
    • 6.1 尾插法建立单链表
    • 6.2 头插法建立单链表
  • 本文完整代码

1.单链表的定义

线性表的链式存储.
优点:不要求大片连续空间,改变容量方便
缺点:不可随机存取,要耗费一定空间存放指针

typedef struct LNode{int data;struct LNode *next;
}LNode, *LinkList;

typedef 取别名
将struct LNode 取别名为别的,方便书写
比如我们要声明一个该结构体的时候
由原先的struct LNode a; 可以直接写为LNode a;
由原先的struct LNode *p; 可以直接写为LinkList a;

2.单链表的初始化

带头结点的初始化,头结点就是多一个结点,指向第一个存放数据的结点.
不带头结点,会使处理数据的逻辑更复杂,对空表和非空表需要不同的代码逻辑.
单链表的初始化本质:为头结点分配一个堆空间,将头结点指针域置为空,加上判断内存是否能分配

#include <stdio.h>
#include <stdlib.h>
//这是带有头结点的单链表初始化
void InitList() {LinkList L;//定义头指针变量 L=(LNode*)malloc(sizeof(LNode));//头指针指向分配的头结点内存空间 L->next=NULL;return true;
}
int main()
{InitList( );
}

3.单链表的插入和删除

3.1 单链表的插入

3.1.1 按位序插入

按位序插入,比如说有5个元素,插入到第三个元素的位置
注意在有头结点时,位序5,意味着是结点6
假如我们要插入的位序是3,意味着我们要寻找的是位序2,也就是结点3,当j=i-1时我们跳出循环,先操作,后j++,j代表当前结点值从0开始,也就是我们在j=3的时候应该跳出循环,所以先操作,后j++,就是j<i-1,j=i的时候就跳出循环

传入什么? 表+插入位置+插入的值
分为几步?
首先是非法操作的判断,是否合法.
第二步是,寻找要插入的位置,插入第几个位置,就找到他前一个位置即i-1,让此时的指针p落在该点处,即我们可以操作他的next域
第三步,先判断吐过p指向空,插入操作不合法,若合法,分配堆空间给一个新的结点s,s的数据域是传入值e,s的指针域指向原先的i(i-1的next域,即p当前的next域),然后将i-1的next域指向新的i

核心思想:先连后断

bool ListInsert(LinkList L,int i,int e)
{if(i<1)return false;LNode *p=L;  //为什么需要p指针,因为我们不能动表头指针int j=0;    //用来判断当前指针在第几个结点处,j=0,意思是在头结点处while(p!=NULL&&j<i-1) //P不能为空,为空咋插入啊,操作不合法,i=j的时候跳出循环{p=p->next; j++; }    //通过这个循环,我们就能找到A的指向B的next域,在他俩中间插入Cif(p==NULL)return false;  //上个循环判断它是否为空,为空不执行,为空的具体操作写在了这,为空就结束LNode *s=(LNode *)malloc(sizeof(LNode));s->data=e;s->next=p->next;p->next=s;return true; 
}

3.1.2 在指定结点的前后插入

一.后插操作

分两步
判断操作是否合法(p指针是否为空+s是否能分配)
插入元素操作

InsertNextNode(LNode *p,int e)
{if(p==NULL)return false;LNode *s=(LNode *)malloc(sizeof(LNode));	if(s==NULL)return false;s->data=e;s->next=p->next;p->next=s;return true; 
}
二.前插操作

前插操作我们这里不讨论从前遍历一遍,到最后的那种方法
而是考虑,用后插法再交换他们的数据域这种形式可以将时间复杂度降低到o(1)

bool InsertPriorNode(LNode *p,int e)
{if(p==NULL)return false;LNode *s=(LNode *)malloc(sizeof(LNode));	if(s==NULL)return false;s->next=p->next;p->next=s;s->data=p->data;p->data=e;return true; 
}

4.单链表的删除

4.1 按位序删除

第一步与之前的查找的相同的,现查找位序-1的点
然后再进行删除操作

bool ListDelete(LinkList L,int i,int &e)
{if(i<1)return false;LNode *p=L;  //为什么需要p指针,因为我们不能动L头指针int j=0;  //用来判断当前指针在第几个结点处,j=0,意思是在头结点处while(p!=NULL&&j<i-1) //P不能为空,为空咋插入啊,操作不合法,i=j的时候跳出循环{p=p->next; j++; } if(p==NULL) return false;if(p->next==NULL) return false;LNode *q=p->next;  //方便操作搞出了一个q,直接用p也行,就是写起来不直观e=q->data;p->next=q->next;free(q);return true; 
}

4.2 指定结点的删除

指定删除结点p,我们思考,给你结点p删除它,需要找到前一个结点,但是那样做太麻烦了,不如交换指定结点和后一个结点的数据域,再删除新的后继结点

bool DeleteNode(LNode *p)
{if(p==NULL)return false;LNode *q=p->next;p->data=q->data;p->next=q->next;free(q);return true;
}

5.单链表的查找

5.1 按位序查找

返回值是位序结点的指针

LNode * GetElem(LinkList L,int i)
{if(i<0)return NULL;LNode *p=L;int j=0;while(p!=NULL&&j<i){p=p->next;j++;}return p;} 

5.2 按值查找

LNode * LocateElem(LinkList L,int e)
{LNode *p=L->next; //从第一个结点处开始查值while(p!=NULL&&p->data!=e){p=p->next;}return p; 
}

补充一个:求表的长度

int Length(LinkList L){int len=0;  //不包括头结点 LNode *p=L;while(p->next!=NULL){p=p->next;len++;}return len;
}

6. 单链表的建立(带头结点的建立)

单链表的建立包括了头结点的建立(初始化)

6.1 尾插法建立单链表

- 在尾插法中,LNode *s,*r=L;这个写法,其实是为了简化代码,实际上*s不需要赋值,
- 因为在接下来的代码中会给结点s分配堆空间,结点s的位置就会变成随机的,
- 实际上,我们只需要让r=L就行,声明一个s即可
  • 声明输入值x,分配头结点,声明s和r指针
  • 循环分配s结点再把它加入链表,再循环的输入x值
  • 链表尾指针置空
LinkList List_Tailnsert(LinkList &L)
{int x;L=(LinkList)malloc(sizeof(LNode)); //初始化头结点LNode *s,*r=L;                     //定义上表尾指针和待随机分配的结点指针scanf("%d",&x);while(x!=9999) //输出9999表示结束{s=(LNode *)malloc(sizeof(LNode));s->data=x;r->next=s;r=s;scanf("%d",&x);}r->next=NULL;return L; 
}

6.2 头插法建立单链表

  • 头插法相比于尾插法,我们要把头指针置空,因为分配的头指针很可能指向神秘的空间有脏数据
LinkList List_Headlnsert(LinkList L)
{int x;L=(LinkList)malloc(sizeof(LNode));L->next=NULL; //初始链表头指针指向NULLLNode *s;scanf("%d",&x);while(x!=9999) //输出9999表示结束{s=(LNode *)malloc(sizeof(LNode));s->data=x;s->next=L->next;L->next=s;scanf("%d",&x);}return L; 
}

本文完整代码

#include <stdio.h>
#include <stdlib.h>
typedef struct LNode{int data;struct LNode *next;
}LNode ,*LinkList;void InitList() {LinkList L;//定义头指针变量 L=(LNode*)malloc(sizeof(LNode));//头指针指向分配的头结点内存空间 L->next=NULL;return true;
}
bool ListInsert(LinkList L,int i,int e)
{if(i<1)return false;LNode *p=L;  //为什么需要p指针,因为我们不能动L头指针int j=0;  //用来判断当前指针在第几个结点处,j=0,意思是在头结点处while(p!=NULL&&j<i-1) //P不能为空,为空咋插入啊,操作不合法,i=j的时候跳出循环{p=p->next; j++; } if(p==NULL)return false;LNode *s=(LNode *)malloc(sizeof(LNode));s->data=e;s->next=p->next;p->next=s;return true; 
}InsertNextNode(LNode *p,int e)
{if(p==NULL)return false;LNode *s=(LNode *)malloc(sizeof(LNode));	if(s==NULL)return false;s->data=e;s->next=p->next;p->next=s;return true; 
}
bool InsertPriorNode(LNode *p,int e)
{if(p==NULL)return false;LNode *s=(LNode *)malloc(sizeof(LNode));	if(s==NULL)return false;s->next=p->next;p->next=s;s->data=p->data;p->data=e;return true; 
}bool ListDelete(LinkList L,int i,int &e)
{if(i<1)return false;LNode *p=L;  //为什么需要p指针,因为我们不能动L头指针int j=0;  //用来判断当前指针在第几个结点处,j=0,意思是在头结点处while(p!=NULL&&j<i-1) //P不能为空,为空咋插入啊,操作不合法,i=j的时候跳出循环{p=p->next; j++; } if(p==NULL) return false;if(p->next==NULL) return false;LNode *q=p->next;  //方便操作搞出了一个q,直接用p也行,就是写起来不直观e=q->data;p->next=q->next;free(q);return true; 
}bool DeleteNode(LNode *p)
{if(p==NULL)return false;LNode *q=p->next;p->data=q->data;p->next=q->next;free(q);return true;
}LNode * GetElem(LinkList L,int i)
{if(i<0)return NULL;LNode *p=L;int j=0;while(p!=NULL&&j<i){p=p->next;j++;}return p;
} 
LNode * LocateElem(LinkList L,int e)
{LNode *p=L->next; //从第一个结点处开始查值while(p!=NULL&&p->data!=e){p=p->next;}return p; 
}int Length(LinkList L){int len=0;  //不包括头结点 LNode *p=L;while(p->next!=NULL){p=p->next;len++;}return len;
}
LinkList List_Tailnsert(LinkList L)
{int x;L=(LinkList)malloc(sizeof(LNode));LNode *s,*r=L;scanf("%d",&x);while(x!=9999) //输出9999表示结束{s=(LNode *)malloc(sizeof(LNode));s->data=x;r->next=s;r=s;scanf("%d",&x);}r->next=NULL;return L; 
}LinkList List_Headlnsert(LinkList L)
{int x;L=(LinkList)malloc(sizeof(LNode));LNode *s;scanf("%d",&x);while(x!=9999) //输出9999表示结束{s=(LNode *)malloc(sizeof(LNode));s->data=x;s->next=L->next;L->next=s;scanf("%d",&x);}return L; 
}int main()
{InitList();int e=-1;
}

相关文章:

数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解

单链表理论知识详解 文章目录 单链表理论知识详解1.单链表的定义2.单链表的初始化3.单链表的插入和删除3.1 单链表的插入3.1.1 按位序插入3.1.2 在指定结点的前后插入一.后插操作二.前插操作 4.单链表的删除4.1 按位序删除4.2 指定结点的删除 5.单链表的查找5.1 按位序查找5.2 …...

【智能时代的创新工具】LangChain快速入门指南:轻松掌握语言模型的集成与运用

一、LangChain&#xff1a;连接语言模型与现实世界的桥梁 1.1 LangChain的定义与重要性 LangChain是一个开源的Python库&#xff0c;它旨在为开发人员提供一种简便的方式来集成和运用语言模型。它不仅仅是一个简单的API调用工具&#xff0c;而是一个具有丰富功能的框架&#x…...

文献阅读:细胞分辨率全脑图谱的交互式框架

文献介绍 文献题目&#xff1a; An interactive framework for whole-brain maps at cellular resolution 研究团队&#xff1a; Daniel Frth&#xff08;瑞典卡罗林斯卡学院&#xff09;、Konstantinos Meletis&#xff08;瑞典卡罗林斯卡学院&#xff09; 发表时间&#xff…...

YAML基础语言深度解析

引言 YAML&#xff08;YAML Aint Markup Language&#xff0c;即YAML不是一种标记语言&#xff09;是一种直观、易于阅读的数据序列化格式&#xff0c;常用于配置文件、数据交换和程序间的通信。其设计目标是易于人类阅读和编写&#xff0c;同时也便于机器解析和生成。在本文中…...

xcode使用

1. 界面 1.1. Build Settings,Build Phases和Build Rules三个设置项 Build Settings(编译设置): 每个选项由标题(Title)和定义(Definition)组成。这里主要定义了Xcode在编译项目时的一些具体配置 Build Phases(编译资源):用于指定编译过程中项目所链接的原文件,依赖对象,库…...

OV2640引脚的定义(OV2640 FPC模组规格书(接口线序))

OV2640是一款由Omni Vision公司生产的1/4寸CMOS UXGA&#xff08;1632x1222&#xff09;图像传感器。这款传感器以其小巧的体积、低工作电压和强大的功能而著称&#xff0c;它集成了单片UXGA摄像头和影像处理器&#xff0c;能够通过SCCB总线控制输出各种分辨率的8/10位影像数据…...

CTFSHOW 萌新 web10 解题思路和方法(passthru执行命令)

点击题目链接&#xff0c;分析页面代码。发现代码中过滤了system、exec 函数&#xff0c;这意味着我们不能通过system(cmd命令)、exec&#xff08;cmd命令&#xff09;的方式运行命令。 在命令执行中&#xff0c;常用的命令执行函数有&#xff1a; system(cmd_code);exec(cmd_…...

深入Java数据库连接和JDBC

引言 Java数据库连接(JDBC)是Java语言中用于执行SQL语句的标准API。通过JDBC,开发者可以方便地与关系型数据库进行交互。然而,直接使用JDBC API面临着数据库连接管理复杂、性能瓶颈等问题。数据库连接池作为一种解决方案,可以有效地管理数据库连接,提高应用程序的性能。…...

灰狼优化算法(GWO)与长短期记忆网络(LSTM)结合的预测模型(GWO-LSTM)及其Python和MATLAB实现

#### 一、背景 在现代数据科学和人工智能领域&#xff0c;预测模型的准确性和效率是研究者和工程师不断追求的目标&#xff0c;尤其是在时间序列预测、金融市场分析、气象预测等领域。长短期记忆&#xff08;LSTM&#xff09;网络是一种解决传统递归神经网络&#xff08;RNN&a…...

电路板热仿真覆铜率,功率,结温,热阻率信息计算获取方法总结

🏡《电子元器件学习目录》 目录 1,概述2,覆铜率3,功率4,器件尺寸5,结温6,热阻1,概述 电路板热仿真操作是一个复杂且细致的过程,旨在评估和优化电路板内部的热分布及温度变化,以确保电子元件的可靠性和性能。本文简述在进行电路板的热仿真时,元器件热信息的计算方法…...

C#中多线程编程中的同步、异步、串行、并行及并发及死锁

在C#中&#xff0c;多线程编程是一个强大的功能&#xff0c;它允许程序同时执行多个任务。然而&#xff0c;这也带来了复杂性&#xff0c;特别是在处理同步、异步、串行、并行、并发以及死锁等问题时。下面我将详细解释这些概念&#xff0c;并给出一些C#中的示例和注意事项。 …...

【Lampiao靶场渗透】

文章目录 一、IP地址获取 二、信息收集 三、破解SSH密码 四、漏洞利用 五、提权 一、IP地址获取 netdiscover -i eth0 Arp-scan -l Nmap -sP 192.168.78.0/24 靶机地址&#xff1a;192.168.78.177 Kali地址&#xff1a;192.168.78.128 二、信息收集 nmap -sV -p- 192.…...

使用WebSocket实现log日志流的实时展示-从轮询到通知

场景介绍 最近开发一个系统&#xff0c;其中一个模块需要展示实时的执行过程&#xff0c;过程日志可能比较多。以前的方案都是前端定时轮询&#xff0c;比如每秒查一次后端接口&#xff0c;将拉取回来的日志重新展示。轮询方案简单容易实现&#xff0c;但是比较消耗资源&#…...

UE5 从零开始制作跟随的大鹅

文章目录 二、绑定骨骼三、创建 ControlRig四、创建动画五、创建动画蓝图六、自动寻路七、生成 goose八、碰撞 和 Physics Asset缺点 # 一、下载模型 首先我们需要下载一个静态网格体&#xff0c;这里我们可以从 Sketchfab 中下载&#xff1a;Goose Low Poly - Download Free …...

O’Reilly

--江上往来人&#xff0c;但爱鲈鱼美。 --君看一叶舟&#xff0c;出没风波里。 OReilly OReilly出版社出版的技术类图书 俗称动物系列 应该是每个技术人员的必备手册。 OReilly动物系列&#xff08;中译本&#xff09; 简介" 动物系列作为 OReilly 书籍的典型代表被普遍…...

优盘驱动器未格式化:数据拯救行动指南

优盘困境&#xff1a;驱动器未格式化的挑战 在日常的数据存储与传输中&#xff0c;优盘以其便携性和高容量成为了我们不可或缺的伙伴。然而&#xff0c;当您尝试访问优盘时&#xff0c;突然弹出的“驱动器未被格式化”提示却如同晴天霹雳&#xff0c;让人措手不及。这一状况不…...

4.Handler mappings

处理程序映射 简介 在早期版本的 Spring 中&#xff0c;用户需要在 Web 应用程序上下文中定义一个或多个 HandlerMapping bean 以将传入的 Web 请求映射到适当的处理程序。随着注解控制器的引入&#xff0c;通常不再需要这样做&#xff0c;因为 RequestMappingHandlerMapping…...

《学会 SpringMVC 系列 · 消息转换器 MessageConverters》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…...

深度学习项目 -7-使用 Python 的手写数字识别

一、前言 该文章仅作为个人学习使用 二、正文 项目源代码&#xff1a;深度学习项目 - 使用 Python 进行手写数字识别 - DataFlair (data-flair.training) 数据集&#xff1a;​​​​​​​https://drive.google.com/open?id1hJiOlxctFH3uL2yTqXU_1f6c0zLr8V_K Python 深…...

MySQL —— 库,数据类型 与 表

库与基础操作 1.1 查看数据库 使用 show databases; 可以查看当前 MySQL 目前有多少个数据库 5 rows 表示有 5 行&#xff0c;这里是表示的是有效的数据&#xff0c;不包括 第一行的指引 set 表示结果集合 0.01 sec 表示这个 sql 语句一共运行了0.01 秒&#xff0c;一般情况…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...