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

数据结构-单链表(C语言简单实现)

简介

以顺序结构进行数据存储时,它的特点就是可以用一组任意的存储单元存储数据元素,这组存储单元可以是连续的,也可以是不连续的,这些数据可以存在内存未被占用的任意位置。它也是有缺点的,就是在插入和删除时需要移动大量的元素,需要耗费一点时间

以下是它的一个示意图

单链表

想要创建这样的数据结构,首先需要使用结构体先定义一个节点:

typedef struct node
{int data;  // 数据struct node *next;  // 指向下一个节点的地址
}node_t;

然后需要使用结构体定义单链表:

typedef struct list
{struct node *head;  // 头部struct node *tail;  // 尾部
}list_t;

相关函数

  • 首先需要定义一个静态函数用于创建节点
static node_t *create_node(int data)
{node_t *pnew = malloc(sizeof(node_t));  // 分配内存空间pnew->data  = data;  // 分配数据pnew->next = NULL;  // 默认指向空return pnew;  // 返回地址
}
  • 初始化函数

图片.png

void list_init(list_t *plist)
{plist->head = create_node(0);  // 为头部创建一个节点plist->tail = create_node(0);  // 为尾部创建一个节点plist->head->next = plist->tail;  // 头部的next指向尾部plist->tail->next = NULL;  // 尾部的next指向NULL
}
  • 释放单链表的函数

图片.png

void list_deinit(list_t *plist)
{node_t *pnode = plist->head;  // 将pnode指向头部// 当pnode非空时,进行循环,说明还有数据while(pnode){node_t *ptmp = pnode->next;  // 备份pnode的nextfree(pnode);  // 释放pnodepnode = ptmp;  // 将之前pnode的next指向现在的pnode}
}
  • 遍历单链表

图片.png

void list_travel(list_t *plist)
{// 遍历: 首先将pnode指向head,直到pnode指向tail结束,pnode每次往后移一位for(node_t *pnode = plist->head; pnode != pnode->tail; pnode = pnode->next){// 三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;if(pmid != pnode->tail)printf("%d ", pmid->data);}printf("\n");
}
  • 按照顺序添加数据到单链表中

图片.png

void list_add(list_t *plist, int data)
{// 1. 创建一个新的节点node_t *pnew = create_node(data);// 2. 遍历链表for(node_t *pnode = plist->head; pnode != plist->tail; pnode = pnode->next){// 2.1 三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;// 2.2 当找到比data大的数据,就插入到它后面,或者找到最后都没找到比它大的,就插到最后if(pmid->data > pnew->data || pmid == plist->tail){pfirst->next = pnew;pnew->next = pmid;break;}}
}
  • 前插函数(将数据插到最前面)

图片.png

void list_add_first(list_t *plist, int data)
{// 1. 创建一个新的节点node_t *pnew = create_node(data);// 2. 备份头部的nextnode_t *ptmp = plist->head->next;// 3. 将头部的next指向新节点plist->head->next = pnew;// 4. 将新节点的next指向之前头部指向nextpnew->next = ptmp;
}
  • 后插函数(将数据插到最后面)

图片.png

void list_add_last(list_t *plist, int data)
{// 1. 创建一个新的节点node_t *pnew = create_node(data);// 2. 遍历链表for(node_t *pnode = plist->head; pnode != plist->tail; pnode = pnode->next){// 2.1 三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;// 2.2 当pmid执行plist->tail时,插入if(pmid == plist->tail){pfirst->next = pnew;pnew->next = pmid;break;}}
}
  • 删除指定数据所在的节点

图片.png

void list_del(list_t *plist, int data)
{// 1. 遍历链表for(node_t *pnode = plist->head; pnode != plist->tail; pnode = pnode->next){// 1.1 三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;// 1.2 当找到数据相等的,并且此数据不是尾节点,因为尾节点是初始化定义的if(data == pmid->data && pmid != plist->tail){pfirst->next = plast;free(pmid);  // 此时pmid就是要删除的那个节点break;}}
}

示例代码

创建三个文件: list.c、list.h、main.c,实现上面的相关函数

  • list.c
#include "list.h"// 定义分配节点内存函数
static node_t *create_node(int data)
{node_t *pnew = malloc(sizeof(node_t));pnew->data = data;pnew->next = NULL;return pnew;
}// 初始化
void list_init(list_t *plist)
{// 1. 给首尾分配内存plist->head = create_node(0);plist->tail = create_node(0);// 2. 头指向尾plist->head->next = plist->tail;// 3. 尾指向空plist->tail->next = NULL;
}// 释放
void list_deinit(list_t *plist)
{// 1. 取到单链表的头部node_t *pnode = plist->head;// 2. 当头部不为空的时候,说明还有数据,继续循环while (pnode){// 2.1 备份pnode->nextnode_t *ptmp = pnode->next;// 2.2 释放pnodefree(pnode);// 2.3 重新指定pnode是ptmppnode = ptmp;}
}// 遍历数据单链表
void list_travel(list_t *plist)
{for (node_t *pnode = plist->head; pnode != plist->tail; pnode = pnode->next){// 创建三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;// 判断pmid是有效节点if (pmid != plist->tail){printf("%d ", pmid->data);}}printf("\n");
}// 按顺序添加数据到单链表中
void list_add(list_t *plist, int data)
{// 1. 创建新的节点node_t *pnew = create_node(data);// 2. 遍历单链表for (node_t *pnode = plist->head; pnode != plist->tail; pnode = pnode->next){// 2.1 创建三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;// 2.2 判断当找到pmid的数据大于等于data或者找到最后都没找到比data大的,就插到最后if (pmid->data >= pnew->data || pmid == plist->tail){// 2.2.1 放在pmid后面,pfirst的前面pfirst->next = pnew;pnew->next = pmid;break;}}
}// 前插函数
void list_add_first(list_t *plist, int data)
{// 1. 创建新的节点node_t *pnew = create_node(data);// 2. 备份头部的nextnode_t *ptmp = plist->head->next;// 3. 将头部的next指向新的节点plist->head->next = pnew;// 4. 将新的节点next指向之前头部的nextpnew->next = ptmp;
}// 后插函数
void list_add_last(list_t *plist, int data)
{// 1. 创建新的节点node_t *pnew = create_node(data);// 2. 遍历节点,找到tail前面的节点for (node_t *pnode = plist->head; pnode != plist->tail; pnode = pnode->next){// 2.1 创建三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;// 2.2 当pmid==tail时,说明pfirst是tail前面的节点if (pmid == plist->tail){// 2.2.1 将pfirst的next指向pnewpfirst->next = pnew;// 2.2.2 将pnew的next执行tail(pmid)pnew->next = pmid;break;}}
}// 删除指定数字所在所在的节点
void list_del(list_t *plist, int data)
{// 1. 遍历单链表for (node_t *pnode = plist->head; pnode != plist->tail; pnode = pnode->next){// 1.1 三个游标node_t *pfirst = pnode;node_t *pmid = pfirst->next;node_t *plast = pmid->next;// 1.2 当找到数据相等的,并且此数据不是尾节点,因为尾节点是初始化定义的if (data == pmid->data && pmid != plist->tail){// 1.2.1 将pfirst的next指向plastpfirst->next = plast;// 1.2.2 释放pmidfree(pmid);break;}}
}
  • list.h声明单链表的相关函数和定义节点和单链表
#ifndef __LIST_H
#define __LIST_H#include <stdio.h>
#include <stdlib.h>// 定义节点
typedef struct node
{int data;struct node *next;
} node_t;// 声明单链表的结构体
typedef struct list
{node_t *head; // 保存头节点的地址node_t *tail; // 保存尾节点的地址
} list_t;extern void list_init(list_t *plist);
extern void list_deinit(list_t *plist);
extern void list_travel(list_t *plist);
extern void list_add(list_t *plist, int data);
extern void list_add_first(list_t *plist, int data);
extern void list_add_last(list_t *plist, int data);
extern void list_del(list_t *plist, int data);#endif
  • main.c主函数使用单链表
#include "list.h"int main(void)
{// 1. 创建单链表list_t list;// 2. 初始化单链表list_init(&list);// 3. 插入三个数据10 30 20printf("插入三个数据10 30 20,结果应该排好顺序的: ");list_add(&list, 10);list_add(&list, 30);list_add(&list, 20);// 4. 循环遍历输出单链表list_travel(&list);// 5. 在头部插入一个15printf("在头部插入15: ");list_add_first(&list, 15);// 6.遍历输出单链表list_travel(&list);// 7. 在尾部插入一个1printf("在尾部插入一个1: ");list_add_last(&list, 1);// 8. 遍历输出list_travel(&list);// 9. 删除一个20printf("删除一个20: ");list_del(&list, 20);// 10. 遍历输出list_travel(&list);// 11. 释放整个链表list_deinit(&list);return 0;
}

相关文章:

数据结构-单链表(C语言简单实现)

简介 以顺序结构进行数据存储时&#xff0c;它的特点就是可以用一组任意的存储单元存储数据元素&#xff0c;这组存储单元可以是连续的&#xff0c;也可以是不连续的&#xff0c;这些数据可以存在内存未被占用的任意位置。它也是有缺点的&#xff0c;就是在插入和删除时需要移…...

.netcore grpc身份验证和授权

一、鉴权和授权&#xff08;grpc专栏结束后会开启鉴权授权专栏欢迎大家关注&#xff09; 权限认证这里使用IdentityServer4配合JWT进行认证通过AddAuthentication和AddAuthorization方法进行鉴权授权注入&#xff1b;通过UseAuthentication和UseAuthorization启用鉴权授权增加…...

分布式 - 服务器Nginx:一小时入门系列之负载均衡

文章目录 1. 负载均衡2. 负载均衡策略1. 轮询策略2. 最小连接策略3. IP 哈希策略4. 哈希策略5. 加权轮询策略 1. 负载均衡 跨多个应用程序实例的负载平衡是一种常用技术&#xff0c;用于优化资源利用率、最大化吞吐量、减少延迟和确保容错配置。‎使用 nginx 作为非常有效的HT…...

Linux学习之基本指令二

-----紧接上文 在了解cat指令之前&#xff0c;我们首先要了解到Linux下一切皆文件&#xff0c;在学习c语言时我们就已经了解到了 对文件输入以及读入的操作&#xff08;向显示器打印&#xff0c;从键盘读取数据&#xff09;&#xff0c;对于Linux下文件的操作&#xff0c;也是…...

神经网络基础-神经网络补充概念-41-梯度的数值逼近

概念 梯度的数值逼近是一种用于验证梯度计算正确性的方法&#xff0c;它通过近似计算梯度来与解析计算的梯度进行比较。虽然数值逼近在实际训练中不常用&#xff0c;但它可以用来检查手动或自动求导的实现是否正确。 代码实现 import numpy as np# 定义函数 f(x) x^2 def f…...

tornado在模板中遍历二维数组

要在Tornado模板中遍历一个二维数组&#xff0c;你可以使用Tornado的模板语法来实现迭代和显示数组中的每个元素。 以下是一个示例&#xff0c;演示如何在Tornado模板中遍历和显示二维数组的内容&#xff1a; template.html: <!DOCTYPE html> <html> <head&g…...

前端-初始化Vue3+TypeScript

如果使用如下命令初始化项目&#xff0c;项目很干净&#xff0c;很适合了解项目的各个结构。 npm init vitelatest如果使用如下命令初始化项目&#xff0c;是可以选择你需要的组件 npm init vuelatest...

龙蜥社区安全联盟(OASA)正式成立,启明星辰、绿盟、360 等 23 家厂商重磅加入

7 月 28 日&#xff0c;由启明星辰、绿盟、360、阿里云、统信软件、浪潮信息、中兴通讯&#xff5c;中兴新支点、Intel、中科院软件所等 23 家单位共同发起的龙蜥社区安全联盟&#xff08;OASA&#xff0c;OpenAnolisSecurityAlliance&#xff09;&#xff08;以下简称“安全联…...

Flask-SQLAlchemy

认识Flask-SQLAlchemy Flask-SQLAlchemy 是一个为 Flask 应用增加 SQLAlchemy 支持的扩展。它致力于简化在 Flask 中 SQLAlchemy 的使用。SQLAlchemy 是目前python中最强大的 ORM框架, 功能全面, 使用简单。 ORM优缺点 优点 有语法提示, 省去自己拼写SQL&#xff0c;保证SQL…...

大数据bug-sqoop(二:sqoop同步mysql数据到hive进行字段限制。)

一&#xff1a;sqoop脚本解析。 #&#xff01;/bin/sh mysqlHost$1 mysqlUserName$2 mysqlUserPass$3 mysqlDbName$4 sql$5 split$6 target$7 hiveDbName$8 hiveTbName$9 partFieldName${10} inputDate${11}echo ${mysqlHost} echo ${mysqlUserName} echo ${mysqlUserPass} ec…...

Windows小记

一、域控制器升级的先决条件验证失败。 新建域时&#xff0c;本地 Administrator 帐户将成为域 Administrator 帐户。无法新建域&#xff0c;因为本地 Administrator 帐户密码不符合要求。 目前&#xff0c;本地 Administrator 帐户不需要密码。我们建议你使用网络用户命令行工…...

centos安装elasticsearch7.9

安装es 下载elasticsearch安装包解压安装包,并修改配置文件解压进入目录修改配置文件 添加用户&#xff0c;并修改所有者切换用户&#xff0c;运行es如何迁移旧版本的数据 下载elasticsearch安装包 下载地址如下&#xff0c;版本号可以替换成自己想要的。 这里需要注意一点&am…...

221、仿真-基于51单片机的智能啤酒发酵罐多点温度压力水位排水加水检测报警系统设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 ​编辑 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方…...

C语言好题解析(三)

目录 选择题一选择题二选择题三选择题四编程题一编程题二 选择题一 以下程序段的输出结果是&#xff08;&#xff09;#include<stdio.h> int main() { char s[] "\\123456\123456\t"; printf("%d\n", strlen(s)); return 0; }A: 12 B: 13 …...

OpenCV之remap的使用

OpenCV中使用remap实现图像的重映射。 重映射是指将图像中的某一像素值赋值到指定位置的操作&#xff1a;g(x,y) f ( h(x,y) )&#xff0c; 在这里&#xff0c; g( ) 是目标图像, f() 是源图像, 而h(x,y) 是作用于 (x,y) 的映射方法函数。为了完成映射过程, 需要获得一些插值为…...

leetcode 377. 组合总和 Ⅳ

2023.8.17 本题属于完全背包问题&#xff0c;乍一看和昨天那题 零钱兑换II 类似&#xff0c;但细看题目发现&#xff1a;今天这题是排列问题&#xff0c;而“零钱兑换II”是组合问题。排列问题强调顺序&#xff0c;而组合顺序不强调顺序。 这里先说个结论&#xff1a;先遍历物品…...

C++笔记之花括号和圆括号初始化区别,列表初始化和初始化列表区别

C笔记之花括号和圆括号初始化区别&#xff0c;列表初始化和初始化列表区别 code review! 文章目录 C笔记之花括号和圆括号初始化区别&#xff0c;列表初始化和初始化列表区别1.花括号{}进行初始化和圆括号()进行初始化2.列表初始化&#xff08;list initialization&#xff0…...

git报错Add correct host key

想克隆备份的笔记库&#xff0c;失败。 测试连接github报错如下。 $ ssh -T gitgithub.comWARNING: POSSIBLE DNS SPOOFING DETECTED! The RSA host key for github.com has changed, and the key for the corresponding IP address 140.82.121.4 is unknown. This c…...

Kvm配置ovs网桥

环境&#xff1a;部署在kvm虚拟环境上&#xff08;让虚拟机和宿主机都可以直接从路由器获取到独立ip&#xff09; 1、安装ovs软件安装包并启动服务&#xff08;一般采用源码安装&#xff0c;此处用yum安装&#xff09; yum install openvswitch-2.9.0-3.el7.x86_64.rpm syste…...

AraNet:面向阿拉伯社交媒体的新深度学习工具包

阿拉伯语是互联网上第四大最常用的语言&#xff0c;它在社交媒体上的日益增加为大规模研究阿拉伯语在线社区提供了充足的资源。然而&#xff0c;目前很少有工具可以从这些数据中获得有价值的见解&#xff0c;用于决策、指导政策、协助应对等。这种情况即将改变吗&#xff1f; …...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?

FTP&#xff08;File Transfer Protocol&#xff09;本身是一个基于 TCP 的协议&#xff0c;理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况&#xff0c;主要原因包括&#xff1a; ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...