1.2 单链表定义及操作实现(链式结构)

1.单链表定义

链式存储:用一组任意的存储单元存储线性表中的数据元素。用这种方法存储的线性
表简称线性链表。
        为了正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其直接
后继结点的地址(或位置),称为指针( pointer )或链( link ),这两部分组成了链表中
的结点结构。
data :数据域,存放结点的值。
next :指针域,存放结点的直接后继的地址。
链表是通过每个结点的指针域将线性表的 n 个结点按其逻辑次序链接在一起的。
每一个结只包含一个指针域的链表,称为单链表。
注意:
1)存储链表中结点的一组任意的存储单元 可以是连续的, 也可以是不连续的,甚至是零散分布在内存中的任意位置上的。
2)链表中结点的逻辑顺序和物理顺序不一定相同。
3) 为操作方便 ,总是在链表的第一个结点之前 附设一个头结点(头指针)head 指向第一个结点 。头结点的数据域可以不存储任何信息(或链表长度等信息)。

2.结点的实现

typedef struct LNode {int data;//数据域struct LNode *next;//指针域
}LNode, *LinkList;
结点是通过动态分配和释放来的实现,即需要时分配,不需要时释放。实现时是分别
使用 C 语言提供的标准函数: malloc () , realloc (), sizeof () , free () 。
动态分配 p= LNode* malloc sizeof LNode ));

3.单链表操作

3.1.创建结点

LNode* node_create(int value, LNode* next) {LNode* node = (LNode*)malloc(sizeof(LNode));if (node != nullptr) {node->data = value;node->next = next;}return node;
}

3.2.创建链表

/*** 创建一个空链表,只包含头结点head*/
LinkList list_create() {return node_create(0, nullptr);//return head node
}
/*** 创建链表,并以形参列表初始化调用方法:LinkList list = list_create({1,2,3,4});*/
LinkList list_create(std::initializer_list<int> args) {LinkList list = node_create(0, nullptr);//create head nodeLNode* curr = list;for (int i : args) {curr->next = node_create(i, nullptr);curr = curr->next;}return list;
}/*** 释放链表占用内存空间*/
bool list_free(LinkList list) {if (list == nullptr) {return false;}for (LNode* curr = list; curr != nullptr; ) {LNode* next = curr->next;free(curr);curr = next;}return true;
}

3.3.查找元素

3.3.1.按序号查找

//查找第i(i>=1)个元素
int get_elem(LinkList list, int i) {if (list == nullptr || i < 1 || i > INT_MAX) {return INT_MIN;//return invalid value}int j = 1;LNode* cur = list->next;while (cur != nullptr && j < i) {cur = cur->next;j += 1;}return i == j ? cur->data : INT_MIN;
}

3.3.2.按值查找

/*** 按值查找* 按值查找是在链表中,查找是否有结点值等于给定值 key 的结点? 若有,则返回首次找到的值为 key 的结点的存储位置;否则返回 NULL	*/
LNode* node_locate(LinkList list, int key) {if (list == nullptr || list->next == nullptr) {return nullptr;}LNode* cur = list->next;for (; cur != nullptr && cur->data != key; cur = cur->next);return cur == nullptr || cur->data != key ? nullptr : cur;
}

3.4.插入元素

/*** 插入运算是将值为 e 的新结点插入到表的第 i 个结点的位置上,即插入到 ai-1 与 ai之间。*/
bool list_insert(LinkList list, int i, int e) {if (list == nullptr) {return false;}LNode* cur = list;//head nodefor (int j = 1; cur != nullptr && j < i; cur = cur->next)j += 1;if (cur == nullptr) {//cur point (i-1) nodereturn false;}LNode* node = node_create(e, cur->next);cur->next = node;return true;
}

3.5.删除元素

3.5.1.按序号删除

/*** 按序号删除* 删除单链表中的第 i 个结点* 时间复杂度也是 O(n)*/
bool list_delete(LinkList list, int i, int* e) {if (list == nullptr || list->next == nullptr) {return false;}LNode* cur = list;for (int j = 1; cur != nullptr && j++ < i; cur = cur->next);//cur结点指向a[i-2]结点if (cur == nullptr || cur->next == nullptr) {return false;}LNode* curi = cur->next;//curi结点指向a[i-1]结点,需要被删除if (e != nullptr) {*e = curi->data;}cur->next = curi->next;free(curi);return true;
}

3.5.2.按值删除

/*** 按值删除* 删除单链表中值为 key 的第一个结点。*/
bool list_delete(LinkList list, int key) {if (list == nullptr || list->next == nullptr) {return false;}LNode* prev = list,*curr = list->next;while(curr != nullptr && curr->data != key) {prev = curr;curr = curr->next;}if (curr == nullptr || curr->data != key) {//未找到,返回失败return false;}prev->next = curr->next;free(curr);//释放被删除元素的内存空间return true;
}

3.5.3.按值删除变形1

/*** 按值删除* 删除单链表中值为 key 的所有结点。*/
bool list_delete_all(LinkList list, int key) {if (list == nullptr || list->next == nullptr) {return false;}LNode *prev = list, *curr = list->next;while (curr != nullptr) {if (curr->data == key) {prev->next = curr->next;free(curr);curr = prev->next;}else {prev = curr;curr = curr->next;}}return true;
}

3.5.4.按值删除变形2

/*** 去重函数* 删除单链表中所有值重复的结点,使得所有结点的值都不相同* 基本思想:从单链表的第一个结点开始,对每个结点进行检查:检查链表中该结点的所有后继结点,只要有值和该结点的值相同,则删除之;然后检查下一个结点,直到所有的结点都检查。*/
bool list_unique(LinkList list) {if (list == nullptr || list->next == nullptr) {return false;}LNode* curr = list->next;while (curr != nullptr) {LNode* pi = curr->next;//内层循环指针LNode* prev = curr;//内层循环指针while (pi != nullptr) {if (curr->data == pi->data) {prev->next = pi->next;free(pi);pi = prev->next;}else {prev = pi;pi = pi->next;}}curr = curr->next;}return true;
}

3.6.链表合并

/*** 设有两个有序的单链表,它们的头指针分别是 La 、Lb,将它们合并为以 Lc 为头指针的有序链表若 La,Lb 两个链表的长度分别是 m,n,则链表合并的时间复杂度为 O(m+n)*/
LinkList merge_linklist(LinkList la, LinkList lb) {if (la == nullptr || la->next == nullptr) {//la为空,直接返回lbreturn lb;}else if (lb == nullptr || lb->next == nullptr) {return la;}LinkList lc = list_create();LNode* pc = lc;LNode* pa = la->next, * pb = lb->next;//[1]每次从la,lb取出数据并比较,将小的数据存入lcwhile (pa != nullptr && pb != nullptr) {if (pa->data <= pb->data) {pc->next = node_create(pa->data, nullptr);pc = pc->next;pa = pa->next;}else {pc->next = node_create(pb->data, nullptr);pc = pc->next;pb = pb->next;}}//[2]lb的数据取完,将剩余la数据全部存入lcwhile (pa != nullptr) {//pb == nullptr pc->next = node_create(pa->data, nullptr);pc = pc->next;pa = pa->next;}//[3]la的数据取完,将剩余lb数据全部存入lcwhile (pb!= nullptr) {//pa == nullptrpc->next = node_create(pb->data, nullptr);pc = pc->next;pb = pb->next;}return lc;
}

3.7.辅助函数

3.7.1.打印链表

/*** 打印单链表(辅助函数)*/
bool list_print(LinkList list) {if (list == nullptr) {return false;}printf("[");for (LNode* cur = list->next; cur != nullptr; cur = cur->next) {printf("%d", cur->data);printf("%s", cur->next == nullptr ? "" : ",");}printf("]\n");
}

3.7.2包含头文件

#ifndef __IOSTREAM_H__
#define __IOSTREAM_H__
#include <iostream>
#endif#ifndef __STDIO_H__
#define __STDIO_H__
#include <stdio.h>
#endif#ifndef __STDARG_H__
#define __STDARG_H__
#include <stdarg.h>
#endif#ifndef __INITIALIZER_LIST__
#define __INITIALIZER_LIST__
#include <initializer_list>
#endif

3.7.3测试函数

void test1() {LinkList list = list_create({1,2,3,4,5});list_print(list);int e = get_elem(list, 3);printf("%d\n", e);printf("len = %d\n", get_length(list));printf("node_locate(list, 3) = %x\n", node_locate(list, 3));printf("node_locate(list, 7) = %x\n", node_locate(list, 7));list_free(list);
}void test2() {LinkList list = list_create({1,2,3,4});list_print(list);list_insert(list, 2, 8);printf("list_insert(list, 2, 8)\n");list_print(list);list_free(list);
}void test3() {LinkList list = list_create({1,2,3,4});list_print(list);list_delete(list, 2, nullptr);list_print(list);list_delete(list, 2, nullptr);list_print(list);list_delete(list, 2, nullptr);list_print(list);list_free(list);
}void test4() {LinkList list = list_create({1,2,3,4});list_print(list);list_delete(list, 2);list_print(list);list_delete(list, 4);list_print(list);list_free(list);
}void test5() {LinkList list = list_create({1,2,3,6,2,2,7,8});list_print(list);list_delete_all(list, 2);list_print(list);list_free(list);
}void test6() {LinkList list = list_create({ 1,2,3,6,2,2,7,8 });list_print(list);list_unique(list);list_print(list);list_free(list);
}void test7() {LinkList la = list_create({1,3,5,9});LinkList lb = list_create({2,4,6,7,8,10});list_print(la);list_print(lb);LinkList lc = merge_linklist(la, lb);list_print(lc);
}

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

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

相关文章

故障诊断 | 基于Transformer故障诊断分类预测(Matlab)

文章目录 预测效果文章概述程序设计参考资料预测效果 文章概述 Transformer故障诊断/分类预测 | 基于Transformer故障诊断分类预测(Matlab) Transformer 模型本质上都是预训练语言模型,大都采用自监督学习 (Self-supervised learning) 的方式在大量生语料上进行训练,也就是…

Java解析epub电子书文件实战demo

如何使用 Java、Spring Boot 和 Epublib 库解析存储在阿里云对象存储服务&#xff08;OSS&#xff09;上的 EPUB 文件。这里将指导您完成设置必要依赖项、配置 OSS 客户端以及编写服务以读取和提取 EPUB 文件章节的全过程。 步骤1&#xff1a;添加依赖项 首先&#xff0c;将 E…

微信小程序消息订阅处理实践

微信小程序提供订阅消息功能&#xff0c;分为一次性订阅消息、长期订阅消息。长期订阅消息目前只针对民生、金融、教育等有线下服务场景的类目开放。这些只是大类&#xff0c;并不表示所包含的所有二级类目都能申请长期订阅消息&#xff0c;具体看官方文档。 另一个长期订阅消…

RNN(一)——循环神经网络的实现

文章目录 一、循环神经网络RNN1.RNN是什么2.RNN的语言模型3.RNN的结构形式 二、完整代码三、代码解读1.参数return_sequences2.调参过程 一、循环神经网络RNN 1.RNN是什么 循环神经网络RNN主要体现在上下文对理解的重要性&#xff0c;他比传统的神经网络&#xff08;传统的神…

04 卷积神经网络

目录 1. 基本概念 1.1 卷积神经网络 1.2 卷积 1.3 汇聚&#xff08;池化&#xff09; 2. CNN网络架构及参数学习 2.1 网络架构 2.2 参数学习 3. 典型的卷积神经网络 3.1 LeNet-5 3.2 AlexNet 3.3 Inception网络 3.4 残差网络 4. 其他卷积方式 1. 基本概念 1.1 …

ReentrantReadWriteLock详解

目录 ReentrantReadWriteLock详解1、ReentrantReadWriteLock简介2、ReentrantReadWriteLock类继承结构和类属性3、ReentrantReadWriteLock的读写锁原理分析4、ReentrantReadWriteLock.WriteLock类的核心方法详解非公平写锁的获取非公平写锁的释放公平写锁的获取公平写锁的释放 …

全网最最实用--模型高效推理:量化基础

文章目录 一、量化基础--计算机中数的表示1. 原码&#xff08;Sign-Magnitude&#xff09;2. 反码&#xff08;Ones Complement&#xff09;3. 补码&#xff08;Twos Complement&#xff09;4. 浮点数&#xff08;Floating Point&#xff09;a.常用的浮点数标准--IEEE 754(FP32…

ElasticSearch核心之DSL查询语句实战

什么是DSL&#xff1f; Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。 DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。目前常用的框架查询方法什么的底层都是构建DSL语句实现的&#xff0c;所以你必…

跨境电商独立站:Shopify/Wordpress/店匠选哪个?

在面对不断增加的平台运营压力时&#xff0c;不少跨境电商的商家逐渐将注意力转向建立自己的独立站。据《中国跨境出口电商发展报告&#xff08;2022&#xff09;》所示&#xff0c;中国拥有的独立站数量在2022年已接近20万个&#xff0c;这表明独立站已成为卖家拓展海外市场的…

IndentationError:unindent does not match any outer indentation level

IndentationError:unindent does not match any outer indentation level 目录 IndentationError:unindent does not match any outer indentation level 【常见模块错误】 【解决方案】 原因分析&#xff1a; 解决方法&#xff1a; 示例&#xff1a; 欢迎来到我的主页&am…

正则采集器——前端搭建

前端使用有名的饿了么管理后台&#xff0c;vue3版本vue3-element-admin&#xff0c;首先从gitee中克隆一个vue3-element-admin模板代码vue3-element-admin: Vue3 Element Admin开箱即用的中后台管理系统前端解决方案&#xff0c;然后在此基础上进行开发。 1、修改vite.config.…

matlab仿真 数字信号载波传输(下)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第七 章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all M8; msg[1 4 3 0 7 5 2 6]; ts0.01; T1; %t0:ts:T; t0:ts:T-ts; %x0:ts:length(msg); x0:ts:length(msg)-ts; f…

使用Dumpbin工具查看C++二进制文件的位数、时间戳及dll库的依赖关系

目录 1、Dumpbin简介 2、使用Dumpbin查看二进制文件的位数与时间戳 3、使用Dumpbin查看二进制文件依赖的dll库 4、最后 C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础入…

几种数据库中保存树的常见存储结构

在数据库中存储树时&#xff0c;常见的存储结构有以下几种&#xff1a; 常见存储结构 邻接列表 每个节点都有一个指向其父节点(pid)的引用。这种方法简单直观&#xff0c;也是最容易理解和常用的&#xff0c;但在获取整棵树或子树时可能需要多次查询。 存储结构 一般表结构…

自动驾驶-机器人-slam-定位面经和面试知识系列05之常考公式推导(02)

这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新&#xff0c;基本涵盖了自己秋招历程被问过的面试内容&#xff08;除了实习和学校项目相关的具体细节&#xff09;。在知乎和牛客&#xff08;牛客上某些文章上会附上内推码&#xff09;也会同步…

Android APP 音视频(03)CameraX预览与MediaCodec编码

说明&#xff1a; 此CameraX预览和编码实操主要针对Android12.0系统。通过CameraX预览获取yuv格式数据&#xff0c;将yuv格式数据通过mediacodec编码输出H264码流&#xff08;使用ffmpeg播放&#xff09;&#xff0c;存储到sd卡上。 1 CameraX 和 MediaCodec简介 1.1 CameraX…

【CN】Argo 持续集成和交付(一)

1.简介 Argo 英 [ˈɑ:ɡəu] 美 [ˈɑrˌɡo] Kubernetes 原生工具&#xff0c;用于运行工作流程、管理集群以及正确执行 GitOps。 Argo 于 2020 年 3 月 26 日被 CNCF 接受为孵化成熟度级别&#xff0c;然后于 2022 年 12 月 6 日转移到毕业成熟度级别。 argoproj.github.i…

基于Xejen框架实现的C# winform鼠标点击器、电脑按键自动点击器的软件开发及介绍

功能演示 文章开始之前&#xff0c;仍然是先来个视频&#xff0c;以便用户知道鼠标连点器的基本功能 软件主界面 多功能鼠标连点器 快速点击&#xff1a; 痕即鼠标点击器可以设定每秒点击次数&#xff0c;让您轻松应对高频点击需求。 切换时长&#xff0c;即每次动作之间的间…

0719_驱动3 printk使用方法

一、printk使用方法 1.应用层打印使用printf&#xff0c;内核层使用printk 2.如何查看内核层中printk如何使用 3.在内核空间执行grep "printk" * -nR 4.在内核空间执行vi -t KERN_INFO 5.printk有8中打印级别&#xff08;0-7&#xff09;&#xff0c;打印级别用来过滤…

数据结构(Java):反射枚举Lambda表达式

目录 1、反射 1.1 反射的定义 1.2 反射机制的原理 1.3 反射相关类 1.4 Class类 1.4.1 相关方法 1.4.1.1 常用获得类相关的方法 ​编辑 1.4.1.2 常用获得类中属性相关的方法 1.4.1.3 获得类中构造器相关的方法 1.4.1.4 获得类中方法相关的方法 1.4.2 获取Class对象 1.…