C语言_数据结构总结4:不带头结点的单链表

纯C语言代码,不涉及C++

0. 结点结构

typedef int ElemType;
typedef struct LNode {
    ElemType data;  //数据域
    struct LNode* next;  //指针域
}LNode, * LinkList;

1. 初始化

不带头结点的初始化,即只需将头指针初始化为NULL即可

void InitLink2(LinkList* L) {*L = NULL;
}

2. 头插法

对于不带头结点的单链表,头插法的核心思想是:
每次插入新节点时,将新节点的 next 指针指向当前链表的头节点,然后更新链表的头指针,使其指向新节点。
这样新节点就成为了链表的第一个节点,插入操作的时间复杂度为 O(1)。

int headInsert(LinkList* L, ElemType value) {LinkList s = (LinkList)malloc(sizeof(LNode));if (s == NULL){printf("内存分配失败!\n");return -2;}s->data = value;s->next = *L;*L = s;  //更新头结点指向新结点return 0;  //插入成功
}

3. 尾插法

尾插法的核心思路是每次都将新节点插入到链表的末尾。
对于不带头结点的单链表,需要考虑链表为空的特殊情况。
当链表为空时,新插入的节点就是链表的头节点;
当链表不为空时,需要先遍历到链表的尾部,然后将新节点连接到尾部节点的后面。

int tailInsert(LinkList* L, ElemType value) {LinkList s = (LinkList)malloc(sizeof(LNode));if (s == NULL){printf("内存分配失败!\n");return -2;}s->data = value;s->next = NULL;  //因为新结点s要插入到链表尾部//若链表为空,新结点就是头结点if (*L == NULL){*L = s;}else{//1.找到链表的尾结点LinkList p = *L;while (p->next != NULL) {p = p->next;}p->next = s;  //将新节点插入到尾结点后面}return 0; //插入成功
}

4. 插入

int insertLNode2(LinkList* L, int pos, ElemType value) {if (pos < 1) {printf("插入位置不合法!\n");return -1;}LinkList s = (LinkList)malloc(sizeof(LNode));if (s == NULL) {printf("内存分配失败!\n");return -2;}s->data = value;if (pos == 1) {s->next = *L;*L = s;}else {LinkList p = *L;int i = 1;while (p != NULL && i < pos - 1) {p = p->next;i++;}if (p == NULL) {printf("插入位置不合法!\n");free(s);return -1;}s->next = p->next;p->next = s;}return 0;
}

5. 删除

!不带头结点的单链表进行删除结点操作需要分情况考虑:

若要删除的是头节点,需要直接更新头指针;
若删除的是其他节点,需要找到该节点的前一个节点。

int deleteNode(LinkList* L, int pos) {if (pos < 1){printf("删除位置无效!\n");return -1;}if (*L == NULL){printf("当前链表为空!\n");return -2;}if (pos == 1)  //即删除头结点,(更新头结点){LinkList temp = *L;*L = (*L)->next;free(temp);}else{LinkList p = *L;int i = 1;//找到第pos个结点while (p != NULL && i < pos - 1) {p = p->next;i++;}if (p == NULL || p->next == NULL){printf("删除位置不合法!\n");return -1;}LinkList temp = p->next;p->next = temp->next;free(temp);}return 0;  //删除成功
}

6. 按位查找

即:查找第pos个位置上的value值

int findValueByPos(LinkList L, int pos, ElemType* value) {if (pos < 1){printf("查找位置不合法!\n");return -1;}LinkList p = L;int i = 1;while (p != NULL && i < pos) {p = p->next;i++;}if (p == NULL){printf("查找位置超出链表长度!\n");return -1;}*value = p->data;return 0;
}

7. 按值查找

即:查找value值在链表的第pos个位置

int findPosByvalue(LinkList L,ElemType value) {LinkList p = L;int pos = 1;while (p != NULL) {if (p->data == value){return pos;}p = p->next;pos++;}return -1;  //查找失败,未在该链表中找到该value值
}

8. 链表打印

void printLink2(LinkList L) {if (L == NULL) {printf("链表为空!\n");return;}LinkList s = L;while (s != NULL) {printf("%d ", s->data);s = s->next;}printf("\n--------------------------------\n");
}

9. 释放空间

void freeList2(LinkList L) {LinkList p = L;while (p != NULL) {LinkList temp = p;p = p->next;free(temp);}
}

10. 测试代码

int main() {//测试插入方法LinkList L1;InitLink2(&L1);insertLNode2(&L1, 1, 11);insertLNode2(&L1, 2, 22);insertLNode2(&L1, 3, 33);printLink2(L1);  // 11 22 33 freeList2(L1);// 测试头插法LinkList L2;InitLink2(&L2);headInsert(&L2, 1);headInsert(&L2, 2);headInsert(&L2, 3);printLink2(L2);  // 3 2 1freeList2(L2);// 测试尾插法LinkList L3;InitLink2(&L3);tailInsert(&L3, 1);tailInsert(&L3, 2);tailInsert(&L3, 3);printLink2(L3);  // 1 2 3// 测试删除deleteNode(&L3, 3);printf("删除第三个结点后:");printLink2(L3);  //删除第三个结点后:1 2//测试按值查找printf("数值1在第%d个位置\n", findPosByvalue(L3, 1));  // 数值1在第1个位置//测试按位查找ElemType value;findValueByPos(L3, 1, &value);printf("第1个位置的值为%d\n", value);  // 第1个位置的值为1freeList2(L3);return 0;
}

11. 完整代码

#include<stdio.h>
#include<stdlib.h>
/*不带头结点的单链表
*/typedef int ElemType;
typedef struct LNode {ElemType data;  //数据域struct LNode* next;  //指针域
}LNode, * LinkList;// 操作1——不带头结点的初始化,即只需将头指针初始化为NULL即可
void InitLink2(LinkList* L) {*L = NULL;
}// 操作2——不带头结点的插入操作
int insertLNode2(LinkList* L, int pos, ElemType value) {if (pos < 1) {printf("插入位置不合法!\n");return -1;}LinkList s = (LinkList)malloc(sizeof(LNode));if (s == NULL) {printf("内存分配失败!\n");return -2;}s->data = value;if (pos == 1) {s->next = *L;*L = s;}else {LinkList p = *L;int i = 1;while (p != NULL && i < pos - 1) {p = p->next;i++;}if (p == NULL) {printf("插入位置不合法!\n");free(s);return -1;}s->next = p->next;p->next = s;}return 0;
}//操作2.1——不带头结点的头插法建立单链表方法
int headInsert(LinkList* L, ElemType value) {LinkList s = (LinkList)malloc(sizeof(LNode));if (s == NULL){printf("内存分配失败!\n");return -2;}s->data = value;s->next = *L;*L = s;  //更新头结点指向新结点return 0;  //插入成功
}//操作2.3——不带头结点的尾插法建立单链表方法
/*
尾插法的核心思路是每次都将新节点插入到链表的末尾。
对于不带头结点的单链表,需要考虑链表为空的特殊情况。
当链表为空时,新插入的节点就是链表的头节点;
当链表不为空时,需要先遍历到链表的尾部,然后将新节点连接到尾部节点的后面。
*/
int tailInsert(LinkList* L, ElemType value) {LinkList s = (LinkList)malloc(sizeof(LNode));if (s == NULL){printf("内存分配失败!\n");return -2;}s->data = value;s->next = NULL;  //因为新结点s要插入到链表尾部//若链表为空,新结点就是头结点if (*L == NULL){*L = s;}else{//1.找到链表的尾结点LinkList p = *L;while (p->next != NULL) {p = p->next;}p->next = s;  //将新节点插入到尾结点后面}return 0; //插入成功
}// 操作3——删除第pos个位置的值
/*
删除操作需要分情况考虑,若要删除的是头节点,需要直接更新头指针;
若删除的是其他节点,需要找到该节点的前一个节点。
*/
int deleteNode(LinkList* L, int pos) {if (pos < 1){printf("删除位置无效!\n");return -1;}if (*L == NULL){printf("当前链表为空!\n");return -2;}if (pos == 1)  //即删除头结点,(更新头结点){LinkList temp = *L;*L = (*L)->next;free(temp);}else{LinkList p = *L;int i = 1;//找到第pos个结点while (p != NULL && i < pos - 1) {p = p->next;i++;}if (p == NULL || p->next == NULL){printf("删除位置不合法!\n");return -1;}LinkList temp = p->next;p->next = temp->next;free(temp);}return 0;  //删除成功
}// 操作4——按位查找:查找第pos个位置上的value值
int findValueByPos(LinkList L, int pos, ElemType* value) {if (pos < 1){printf("查找位置不合法!\n");return -1;}LinkList p = L;int i = 1;while (p != NULL && i < pos) {p = p->next;i++;}if (p == NULL){printf("查找位置超出链表长度!\n");return -1;}*value = p->data;return 0;
}// 操作5——按值查找:查找value值在链表的第pos个位置
int findPosByvalue(LinkList L,ElemType value) {LinkList p = L;int pos = 1;while (p != NULL) {if (p->data == value){return pos;}p = p->next;pos++;}return -1;  //查找失败,未在该链表中找到该value值
}// 操作6——不带头结点的单链表打印操作
void printLink2(LinkList L) {if (L == NULL) {printf("链表为空!\n");return;}LinkList s = L;while (s != NULL) {printf("%d ", s->data);s = s->next;}printf("\n--------------------------------\n");
}// 操作7——释放不带头结点链表内存
void freeList2(LinkList L) {LinkList p = L;while (p != NULL) {LinkList temp = p;p = p->next;free(temp);}
}int main() {//测试插入方法LinkList L1;InitLink2(&L1);insertLNode2(&L1, 1, 11);insertLNode2(&L1, 2, 22);insertLNode2(&L1, 3, 33);printLink2(L1);  // 11 22 33 freeList2(L1);// 测试头插法LinkList L2;InitLink2(&L2);headInsert(&L2, 1);headInsert(&L2, 2);headInsert(&L2, 3);printLink2(L2);  // 3 2 1freeList2(L2);// 测试尾插法LinkList L3;InitLink2(&L3);tailInsert(&L3, 1);tailInsert(&L3, 2);tailInsert(&L3, 3);printLink2(L3);  // 1 2 3// 测试删除deleteNode(&L3, 3);printf("删除第三个结点后:");printLink2(L3);  //删除第三个结点后:1 2//测试按值查找printf("数值1在第%d个位置\n", findPosByvalue(L3, 1));  // 数值1在第1个位置//测试按位查找ElemType value;findValueByPos(L3, 1, &value);printf("第1个位置的值为%d\n", value);  // 第1个位置的值为1freeList2(L3);return 0;
}

12. 运行截图

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

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

相关文章

78.StringBuilder简单示例 C#例子 WPF例子

利用 StringBuilder 提升字符串操作性能 在 C# 中&#xff0c;字符串是不可变的&#xff0c;这意味着每次修改字符串时都会创建一个新的对象。这种特性虽然保证了安全性&#xff0c;但在频繁修改字符串的场景中会导致性能问题。StringBuilder 正是为解决这一问题而设计的。 什…

【数据集】社区天气资讯网络CoWIN-香港小时尺度气象数据(含MATLAB处理代码)

社区天气资讯网络CoWIN-香港小时尺度气象数据 数据概述气象变量说明数据提取(MATLAB全代码)输出WRF所需站点气温数据参考数据概述 官网-Community Weather Information Network (CoWIN) data policy CoWIN 提供 2010 - 2024 年 的数据下载,每年数据均可单独下载。下载数据…

【JAVA架构师成长之路】【Redis】第14集:Redis缓存穿透原理、规避、解决方案

30分钟自学教程&#xff1a;Redis缓存穿透原理与解决方案 目标 理解缓存穿透的成因及危害。掌握布隆过滤器、空值缓存等核心防御技术。能够通过代码实现请求拦截与缓存保护。学会限流降级、异步加载等应急方案。 教程内容 0~2分钟&#xff1a;缓存穿透的定义与核心原因 定义…

尚硅谷爬虫note15

一、当当网 1. 保存数据 数据交给pipelines保存 items中的类名&#xff1a; DemoNddwItem class DemoNddwItem(scrapy.Item): 变量名 类名&#xff08;&#xff09; book DemoNddwItem(src src, name name, price price)导入&#xff1a; from 项目名.items import 类…

LVGL直接解码png图片的方法

通过把png文件解码为.C文件&#xff0c;再放到工程中的供使用&#xff0c;这种方式随时速度快&#xff08;应为已经解码&#xff0c;代码中只要直接加载图片数据显示出来即可&#xff09;&#xff0c;但是不够灵活&#xff0c;适用于哪些简单又不经常需要更换UI的场景下使用。如…

【计算机网络】Socket

Socket 是网络通信的核心技术之一&#xff0c;充当应用程序与网络协议栈之间的接口。 1. Socket 定义 Socket&#xff08;套接字&#xff09;是操作系统提供的 网络通信抽象层&#xff0c;允许应用程序通过标准接口&#xff08;如 TCP/IP 或 UDP&#xff09;进行数据传输。它…

Apache XTable:在数据湖仓一体中推进数据互作性

Apache XTable 通过以多种开放表格式提供对数据的访问&#xff0c;在增强互作性方面迈出了一大步。移动数据很困难&#xff0c;在过去&#xff0c;这意味着在为数据湖仓一体选择开放表格式时&#xff0c;您被锁定在该选择中。一个令人兴奋的项目当在数据堆栈的这一层引入互作性…

anolis8.9-k8s1.32-node-二进制部署

一、系统 # cat /etc/anolis-release Anolis OS release 8.9 # uname -r 5.10.134-18.an8.x86_64 二、从master上拷贝dockers及cri-docker相关文件 # groupadd docker # mkdir /etc/docker# scp -P 4033 root192.168.7.201:/etc/systemd/system/containerd.service /etc/s…

《AJAX:前端异步交互的魔法指南》

什么是AJAX AJAX&#xff08;Asynchronous JavaScript and XML&#xff0c;异步 JavaScript 和 XML&#xff09; 是一种用于创建异步网页应用的技术&#xff0c;允许网页在不重新加载整个页面的情况下&#xff0c;与服务器交换数据并局部更新页面内容。尽管名称中包含 XML&…

Python 性能优化:从入门到精通的实用指南

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

利用 requestrepo 工具验证 XML外部实体注入漏洞

1. 前言 在数字化浪潮席卷的当下&#xff0c;网络安全的重要性愈发凸显。应用程序在便捷生活与工作的同时&#xff0c;也可能暗藏安全风险。XXE&#xff08;XML外部实体&#xff09;漏洞作为其中的典型代表&#xff0c;攻击者一旦利用它&#xff0c;便能窃取敏感信息、掌控服务…

FreeRTOS第17篇:FreeRTOS链表实现细节05_MiniListItem_t:FreeRTOS内存优化

文/指尖动听知识库-星愿 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:深入FreeRTOS内核:从原理到实战的嵌入式开发指南 1 为什么需要迷你列表项? 在嵌入式系统中,内存资源极其宝贵。FreeRTOS为满足不同场景需求,设计了标准列表项(ListItem_…

Spring 无法解决循环依赖的 5 种场景

一、构造器注入引发的循环依赖 1. 问题复现 Component public class ServiceA {private final ServiceB serviceB;Autowiredpublic ServiceA(ServiceB serviceB) { // 构造器注入this.serviceB serviceB;} }Component public class ServiceB {private final ServiceA servic…

Core Vision Kit(基础视觉服务)

文章目录 一、Core Vision Kit简介场景介绍约束与限制二、通用文字识别三、人脸检测一、Core Vision Kit简介 Core Vision Kit(基础视觉服务)是机器视觉相关的基础能力,例如通用文字识别(即OCR,Optical Character Recognition,也称为光学字符识别)、人脸检测、人脸比对…

第TR3周:Pytorch复现Transformer

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 Transformer通过自注意力机制&#xff0c;改变了序列建模的方式&#xff0c;成为AI领域的基础架构 编码器&#xff1a;理解输入&#xff0c;提取上下文特征…

FreeRTOS 任务间通信机制:队列、信号量、事件标志组详解与实验

1. FreeRTOS 消息队列 1.1 简介 ​ 队列是 任务间通信的主要形式&#xff0c;可用于在任务之间以及中断与任务之间传递消息。队列在 FreeRTOS 中具有以下关键特点&#xff1a; 队列默认采用 先进先出 FIFO 方式&#xff0c;也可以使用 xQueueSendToFront()实现 LIFO。FreeRT…

【虚拟化】Docker Desktop 架构简介

在阅读前您需要了解 docker 架构&#xff1a;Docker architecture WSL 技术&#xff1a;什么是 WSL 2 1.Hyper-V backend 我们知道&#xff0c;Docker Desktop 最开始的架构的后端是采用的 Hyper-V。 Docker daemon (dockerd) 运行在一个 Linux distro (LinuxKit build) 中&…

Unity光照之Halo组件

简介 Halo 组件 是一种用于在游戏中创建光晕效果的工具&#xff0c;主要用于模拟光源周围的发光区域&#xff08;如太阳、灯泡等&#xff09;或物体表面的光线反射扩散效果。 核心功能 1.光晕生成 Halo 组件会在光源或物体的周围生成一个圆形光晕&#xff0c;模拟光线在空气…

Flink深入浅出之01:应用场景、基本架构、部署模式

Flink 1️⃣ 一 、知识要点 &#x1f4d6; 1. Flink简介 Apache Flink — Stateful Computations over Data StreamsApache Flink 是一个分布式大数据处理引擎&#xff0c;可对有界数据流和无界数据流进行有状态的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以…

2025年【高压电工】报名考试及高压电工考试总结

随着电力行业的快速发展&#xff0c;高压电工成为确保电力系统安全稳定运行的重要一环。为了提高高压电工的专业技能和安全意识&#xff0c;“安全生产模拟考试一点通”平台特别整理了2025年高压电工报名考试的相关信息及考试总结&#xff0c;并提供了一套完整的题库&#xff0…