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.rhkb.cn/news/384569.html

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

相关文章

内网渗透—内网穿透工具NgrokFRPNPSSPP

前言 主要介绍一下常见的隧道搭建工具&#xff0c;以此来达到一个内网穿透的目的。简单说一下实验滴环境吧&#xff0c;kali作为攻击机&#xff0c;winserver2016作为目标靶机。 kali 192.168.145.171 winserver2016 10.236.44.127 显然它们处于两个不同的局域网&#xff0c…

基于迁移学习的手势分类模型训练

1、基本原理介绍 这里介绍的单指模型迁移。一般我们训练模型时&#xff0c;往往会自定义一个模型类&#xff0c;这个类中定义了神经网络的结构&#xff0c;训练时将数据集输入&#xff0c;从0开始训练&#xff1b;而迁移学习中&#xff08;单指模型迁移策略&#xff09;&#x…

如何查看jvm资源占用情况

如何设置jar的内存 java -XX:MetaspaceSize256M -XX:MaxMetaspaceSize256M -XX:AlwaysPreTouch -XX:ReservedCodeCacheSize128m -XX:InitialCodeCacheSize128m -Xss512k -Xmx2g -Xms2g -XX:UseG1GC -XX:G1HeapRegionSize4M -jar your-application.jar以上配置为堆内存4G jar项…

二叉树详解-第四篇 二叉树链式结构的实现

目录 1.二叉树的遍历 1.1前序遍历&#xff1a; 1.2 中序遍历&#xff1a; 1.3 后序遍历&#xff1a; 2.二叉树链式结构的实现 2.1 Tree.h 2.2 Tree.cpp 2.2.1 前序遍历 void PreOrder(TNode* Root) 2.2.2 中序遍历 void InOrder(TNode* Root) 2.2.3 后序遍历 void Bac…

基于opencv[python]的人脸检测

1 图片爬虫 这里的代码转载自&#xff1a;http://t.csdnimg.cn/T4R4F # 获取图片数据 import os.path import fake_useragent import requests from lxml import etree# UA伪装 head {"User-Agent": fake_useragent.UserAgent().random}pic_name 0 def request_pic…

DVWA的安装和使用

背景介绍 DVWA是Damn Vulnerable Web Application的缩写&#xff0c;是一个用于安全脆弱性检测的开源Web应用。它旨在为安全专业人员提供一个合法的测试环境&#xff0c;帮助他们测试自己的专业技能和工具&#xff0c;同时也帮助web开发者更好地理解web应用安全防范的过程。DV…

微信小程序-本地部署(前端)

遇到问题&#xff1a;因为是游客模式所以不能修改appID. 参考链接&#xff1a;微信开发者工具如何从游客模式切换为开发者模式&#xff1f;_微信开发者工具如何修改游客模式-CSDN博客 其余参考&#xff1a;Ego微商项目部署&#xff08;小程序项目&#xff09;&#xff08;全网…

Wonder3D 论文学习

论文链接&#xff1a;https://arxiv.org/abs/2310.15008 代码链接&#xff1a;https://github.com/xxlong0/Wonder3D 解决了什么问题&#xff1f; 随着扩散模型的提出&#xff0c;3D 生成领域取得了长足进步。从单张图片重建出 3D 几何是计算机图形学和 3D 视觉的基础任务&am…

k8s安装

说明 本事件适合刚刚装系统的新机子&#xff0c;前提是可以ping通www.baidu。yum可以下载软件 本实验模拟单机k8s&#xff0c;主机ip为172.26.50.222 关闭防火墙 systemctl status firewalld systemctl stop firewalld systemctl disable firewalld getenforce setenforce …

【React】详解样式控制:从基础到进阶应用的全面指南

文章目录 一、内联样式1. 什么是内联样式&#xff1f;2. 内联样式的定义3. 基本示例4. 动态内联样式 二、CSS模块1. 什么是CSS模块&#xff1f;2. CSS模块的定义3. 基本示例4. 动态应用样式 三、CSS-in-JS1. 什么是CSS-in-JS&#xff1f;2. styled-components的定义3. 基本示例…

llama模型,nano

目录 llama模型 Llama模型性能评测 nano模型是什么 Gemini Nano模型 参数量 MMLU、GPQA、HumanEval 1. MMLU(Massive Multi-task Language Understanding) 2. GPQA(Grade School Physics Question Answering) 3. HumanEval llama模型 Large Language Model AI Ll…

【React】详解 Redux 状态管理

文章目录 一、Redux 的基本概念1. 什么是 Redux&#xff1f;2. Redux 的三大原则 二、Redux 的核心组件1. Store2. Action3. Reducer 三、Redux 的使用流程1. 安装 Redux 及其 React 绑定2. 创建 Action3. 创建 Reducer4. 创建 Store5. 在 React 应用中使用 Store6. 连接 React…

【Redis】主从复制分析-基础

1 主从节点运行数据的存储 在主从复制中, 对于主节点, 从节点就是自身的一个客户端, 所以和普通的客户端一样, 会被组织为一个 client 的结构体。 typedef struct client {// 省略 } client;同时无论是从节点, 还是主节点, 在运行中的数据都存放在一个 redisServer 的结构体中…

使用C#手搓Word插件

WordTools主要功能介绍 编码语言&#xff1a;C#【VSTO】 1、选择 1.1、表格 作用&#xff1a;全选文档中的表格&#xff1b; 1.2、表头 作用&#xff1a;全选文档所有表格的表头【第一行】&#xff1b; 1.3、表正文 全选文档中所有表格的除表头部分【除第一行部分】 1.…

Vue常用指令及其生命周期

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 目录 1.常用指令 1.1 v-bind 1.2 v-model 注意事项 1.3 v-on 注意事项 1.4 v-if / v-else-if / v-else 1.5 v-show 1.6 v-for 无索引 有索引 生命周期 定义 流程 1.常用指令 Vue当中的指令…

福派斯牛肉高脂猫粮,为何成猫舍首选?揭秘其神奇功效!

&#x1f43e; 说到猫咪的伙食&#xff0c;咱们当铲屎官的可是操碎了心&#xff01;想让自家毛孩子吃得健康又开心&#xff0c;选对猫粮真的太重要了。今天就来聊聊为啥福派斯牛肉高脂猫粮能成为众多猫舍的首选&#xff0c;以及它到底能帮咱们的小猫咪哪些忙吧&#xff01; 1️…

数据传输安全--SSL VPN

目录 IPSEC在Client to LAN场景下比较吃力的表现 SSL VPV SSL VPN优势 SSL协议 SSL所在层次 SSL工作原理 SSL握手协议、SSL密码变化协议、SSL警告协议三个协议作用 工作过程 1、进行TCP三次握手、建立网络连接会话 2、客户端先发送Client HELLO包&#xff0c;下图是包…

springboot项目从jdk8升级为jdk17过程记录

背景&#xff1a;公司有升级项目jdk的规划&#xff0c;计划从jdk8升级到jdk11 开始 首先配置本地的java_home 参考文档&#xff1a;Mac环境下切换JDK版本及不同的maven-CSDN博客 将pom.xml中jdk1.8相关的版本全部改为jdk17&#xff0c;主要是maven编译插件之类的&#xff0c…

ubuntu22.04 安装 NVIDIA 驱动以及CUDA

目录 1、事前问题解决 2、安装 nvidia 驱动 3、卸载 nvidia 驱动方法 4、安装 CUDA 5、安装 Anaconda 6、安装 PyTorch 1、事前问题解决 在安装完ubuntu之后&#xff0c;如果进入ubuntu出现黑屏情况&#xff0c;一般就是nvidia驱动与linux自带的不兼容&#xff0c;可以通…

找工作准备刷题Day10 回溯算法 (卡尔41期训练营 7.24)

回溯算法今天这几个题目做过&#xff0c;晚上有面试&#xff0c;今天水一水。 第一题&#xff1a;Leetcode77. 组合 题目描述 解题思路 从题目示例来看&#xff0c;k个数是不能重合的&#xff0c;但是题目没有明确说明这一点。 使用回溯算法解决此问题&#xff0c;利用树形…