【数据结构】链表-1
数组
数组在分配内存的时候需要先告诉系统它有多大,为什么呢?打个比方,我们有以一列的凳子,按顺序排布,一个位置只放一个,数组呢,是一个家庭,数组这个家庭呢,他们得挨着坐,不能分开。如果说,只有一个家庭来的时候,他们想坐哪就可以坐哪,但是呢,倘若在他们来之前就有很多个家庭,那他们就不一定能挨着坐了,他们得先告诉管理员,他们有几个人,管理员才能按照他们的人数多少来给他们分配相应的位置。
链表
同样是坐凳子这一个例子,但列表和数组这个家庭呢不太一样,他们呢,不需要都挨着坐,他们每个人有空位就坐下了。那假如妈妈想要找到她的孩子,又该怎么办呢?机智的妈妈想出了一个好点子,那就是让前一个人记住下一个坐的位置,下一个人再记住下下一个人的位置,通过位置去找寻他们。因此,链表里头每个数据都由两部份组成,分别是自己本身所携带的信息和下一个人的位置,最后一个数据因为没有下一个了,所以它所携带的位置一般为null。
数组VS链表
访问各个元素的成本
- 对于数组而言,我们拿到它的位置,接着按顺序遍历一遍就可以访问到每一个元素了,因此,它的时间复杂度是O(1)
- 对于链表来说,我们通过拿到它第一个位置,按照地址去遍历一遍,假设一共有n个元素,那它的时间复杂度为O(n)
内存的使用
-
对于数组来说,我们想要创建一个大的数组,那我们就得用一块更大的内存空间来承载。假设数组里面的一个数据的大小是4个字节,一共有4个数据,我们的内存空间为7个数据,这就占据了28个字节。还有一种情形就是,内存空间已经填满了,可是数组又想去扩大,那我们只能够创建一块更大的数据空间。
-
对于链表而言,我们不存在什么多余的空间,但每一个数据都要包含一个4字节的地址和一个不知道多少字节的内容。所占内存的大小就是数据量再乘上内容所需的字节与储存地址所需的字节之和。数组和链表两者之间其实并不存在哪一个所占内存大哪一个小,这主要取决于数据量的多少,数组所需内存的字节数,内容所要的字节数,我们进行相应的计算后比对。我们需要根据相应的情形对其进行分析。
插入数据的成本
在开头处进行插入
-
数组:开头插入数据就意味着现有的数据每一个都得后移一个位,因此它的时间复杂度为O(n)
-
链表:开头插入的话,我们就只需要在最前面添加内容,并储存此前第一个数据的位置。
在结尾处插入
-
数组:我们讨论的是动态数组,如果还没填满的话,时间复杂度就是O(1),如果已经填满了,那我们就需要遍历全部数据再在最后的位置添加,此时的时间复杂度是O(N)
-
链表:我们需要遍历一遍数据,再在最后添加一个数据,因此此时的时间复杂度就是O(n)
在中间处插入
无论是数组还是链表,我们都得去遍历到这个数据前面的每一项,因此他们的时间复杂度都为O(n)
简易性
在编程语言中,数组的实现会更为简单,而链表的实现则为比较容易出错和复杂
代码
//创建链表
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<stdio.h>
//定义节点,节点内包含数据和指向下一个数据的地址
struct Node {int data;struct Node* next;//指针
};
//建一个头,有了头就能找到其他的数据
struct Node* head;//全局变量
void insert(int x) {struct Node* temp = (struct Node*)malloc(sizeof(struct Node)); temp->data = x;temp->next = NULL;if (head != NULL)temp->next = head;head = temp;
}
void print() {struct Node* temp = head;printf("List is:");while (temp != NULL){printf("%d", temp->data);temp = temp->next;}printf("\n");
}
int main() {head = NULL; //空链表//做一个交互,知道要填几个数据 printf("How many numbers do yop want to input\n");//拿一个变量n来接住这个填充数int n;//填入数据scanf("%d", &n);int x;for(int i = 0; i < n; i++) {printf("please input the number\n");scanf("%d", &x);insert(x);print();}}
在ds中给出的示例代码为:
#ifndef LIST_H
#define LIST_H#include <algorithm>
using namespace std;template <typename Object>
class List
{private: // The basic doubly linked list node.// Nested inside of List, can be public// because the Node is itself privatestruct Node{Object data;Node *prev;Node *next;Node( const Object & d = Object{ }, Node * p = nullptr, Node * n = nullptr ): data{ d }, prev{ p }, next{ n } { }Node( Object && d, Node * p = nullptr, Node * n = nullptr ): data{ std::move( d ) }, prev{ p }, next{ n } { }};public:class const_iterator{public:// Public constructor for const_iterator.const_iterator( ) : current{ nullptr }{ }// Return the object stored at the current position.// For const_iterator, this is an accessor with a// const reference return type.const Object & operator* ( ) const{ return retrieve( ); }const_iterator & operator++ ( ){current = current->next;return *this;}const_iterator operator++ ( int ){const_iterator old = *this;++( *this );return old;}const_iterator & operator-- ( ){current = current->prev;return *this;}const_iterator operator-- ( int ){const_iterator old = *this;--( *this );return old;}bool operator== ( const const_iterator & rhs ) const{ return current == rhs.current; }bool operator!= ( const const_iterator & rhs ) const{ return !( *this == rhs ); }protected:Node *current;// Protected helper in const_iterator that returns the object// stored at the current position. Can be called by all// three versions of operator* without any type conversions.Object & retrieve( ) const{ return current->data; }// Protected constructor for const_iterator.// Expects a pointer that represents the current position.const_iterator( Node *p ) : current{ p }{ }friend class List<Object>;};class iterator : public const_iterator{public:// Public constructor for iterator.// Calls the base-class constructor.// Must be provided because the private constructor// is written; otherwise zero-parameter constructor// would be disabled.iterator( ){ }Object & operator* ( ){ return const_iterator::retrieve( ); }// Return the object stored at the current position.// For iterator, there is an accessor with a// const reference return type and a mutator with// a reference return type. The accessor is shown first.const Object & operator* ( ) const{ return const_iterator::operator*( ); }iterator & operator++ ( ){this->current = this->current->next;return *this;}iterator operator++ ( int ){iterator old = *this;++( *this );return old;}iterator & operator-- ( ){this->current = this->current->prev;return *this;}iterator operator-- ( int ){iterator old = *this;--( *this );return old;}protected:// Protected constructor for iterator.// Expects the current position.iterator( Node *p ) : const_iterator{ p }{ }friend class List<Object>;};public:List( ){ init( ); }~List( ){clear( );delete head;delete tail;}List( const List & rhs ){init( );for( auto & x : rhs )push_back( x );}List & operator= ( const List & rhs ){List copy = rhs;std::swap( *this, copy );return *this;}List( List && rhs ): theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail }{rhs.theSize = 0;rhs.head = nullptr;rhs.tail = nullptr;}List & operator= ( List && rhs ){ std::swap( theSize, rhs.theSize );std::swap( head, rhs.head );std::swap( tail, rhs.tail );return *this;}// Return iterator representing beginning of list.// Mutator version is first, then accessor version.iterator begin( ){ return iterator( head->next ); }const_iterator begin( ) const{ return const_iterator( head->next ); }// Return iterator representing endmarker of list.// Mutator version is first, then accessor version.iterator end( ){ return iterator( tail ); }const_iterator end( ) const{ return const_iterator( tail ); }// Return number of elements currently in the list.int size( ) const{ return theSize; }// Return true if the list is empty, false otherwise.bool empty( ) const{ return size( ) == 0; }void clear( ){while( !empty( ) )pop_front( );}// front, back, push_front, push_back, pop_front, and pop_back// are the basic double-ended queue operations.Object & front( ){ return *begin( ); }const Object & front( ) const{ return *begin( ); }Object & back( ){ return *--end( ); }const Object & back( ) const{ return *--end( ); }void push_front( const Object & x ){ insert( begin( ), x ); }void push_back( const Object & x ){ insert( end( ), x ); }void push_front( Object && x ){ insert( begin( ), std::move( x ) ); }void push_back( Object && x ){ insert( end( ), std::move( x ) ); }void pop_front( ){ erase( begin( ) ); }void pop_back( ){ erase( --end( ) ); }// Insert x before itr.iterator insert( iterator itr, const Object & x ){Node *p = itr.current;++theSize;return iterator( p->prev = p->prev->next = new Node{ x, p->prev, p } );}// Insert x before itr.iterator insert( iterator itr, Object && x ){Node *p = itr.current;++theSize;return iterator( p->prev = p->prev->next = new Node{ std::move( x ), p->prev, p } );}// Erase item at itr.iterator erase( iterator itr ){Node *p = itr.current;iterator retVal( p->next );p->prev->next = p->next;p->next->prev = p->prev;delete p;--theSize;return retVal;}iterator erase( iterator from, iterator to ){for( iterator itr = from; itr != to; )itr = erase( itr );return to;}private:int theSize;Node *head;Node *tail;void init( ){theSize = 0;head = new Node;tail = new Node;head->next = tail;tail->prev = head;}
};#endif
相关文章:
【数据结构】链表-1
数组 数组在分配内存的时候需要先告诉系统它有多大,为什么呢?打个比方,我们有以一列的凳子,按顺序排布,一个位置只放一个,数组呢,是一个家庭,数组这个家庭呢,他们得挨着…...

Python进阶--正则表达式
目录 1. 基础匹配 2. 元字符匹配 1. 基础匹配 正则表达式,又称规则表达式(Regular Expression),是使用单个字符串来描述、匹配某个句法规则的字符串,常被用来检索、替换那些符合某个模式(规则ÿ…...
富格林:发现潜在欺诈安全交易
富格林指出,在全球经济不确定性加剧的背景下,黄金的避险优势再次吸引了投资者的关注。尤其是在今年,随着多种因素的变化,金价的走势引发了市场的广泛讨论。但事实上黄金与其他投资品类相似,也存在潜在的欺诈套路导致我…...

Linux复习--Linux服务管理类(SSH服务、DHCP+FTP、DNS服务、Apache服务、Nginx服务、HTTP状态码)
前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 一、SSH服务 1、问题引出 哪些设置能够提升SSH远程管理的安全等级? 2、SSH的登录验证方式-口令登录 3、SSH的登录验证方式-密钥登录 4、…...

如何用大模型来提升学习效率?
自从2022年底ChatGPT横空出世以来,在过去的十几个月里,生成式人工智能的浪潮席卷并改变着各行各业。 2023年一月,在线课程供应商Study.com曾向1000名18岁以上的学生发起的一项调查显示,当时就已经有超过89%的学生使用ChatGPT来完…...
SQL进阶技巧:如何优雅求解指标累计去重问题?
目录 0 需求概述 1 数据准备 2 问题分析 3 小结 0 需求概述 近期公司开发某项学习功能,改功能有很多学习内容(如java,C,python等方向),每天都会有众多学习用户学习某一项或者多项学习内容。产生数据如下表: 产生数据如下表: 日期 内容 学习用户 2022…...

大数据毕业设计选题推荐-国产电影数据分析-Python数据可视化-Hive-Hadoop-Spark
✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…...

Linux:无法为立即文档创建临时文件: 设备上没有空间
虚拟机磁盘空间不足解决记录 1、问题描述2、问题解决 1、问题描述 在命令行输入命令按Tab键时出现如下报错: 很明显,设备上没有空间,即磁盘空间不足。通过命令查看具体情况如下: df -h2、问题解决 首先想到的是虚拟机扩容。关机虚…...
【SQL】掌握SQL查询技巧:数据筛选与限制
目录 1. DISTINCT:避免重复记录1.1 示意图1.2 使用场景 2. LIMIT:控制查询结果的数量2.1 示意图2.2 使用场景 3. OFFSET:跳过前几行3.1 示意图3.2 使用场景 4. WHERE子句:精细控制数据过滤4.1 示意图4.2 运算符详细说明4.3 基本条…...

大学生社团活动系统小程序的设计
管理员账户功能包括:系统首页,个人中心,学生管理,社长管理,社团分类管理,社团信息管理,社团加入管理,社团活动管理,轮播图信息 微信端账号功能包括:系统首页…...

codetop标签双指针题目大全解析(三),双指针刷穿地心!!!!!
复习比学习更重要,更需要投入时间,更需要花费精力 1.字符串的排列2.找出字符串中第一个匹配的下标3.最大连续1的个数II4.数组中的山脉5.移除元素6.两个数组的交集II7.有序数组的平方8.删除有序数组中的重复项II9.寻找重复数10.水果成篮 1.字符串的排列 …...

HarmonyOS应用六之应用程序进阶一
目录: 1、UIAbility的冷启动和UIAbility热启动2、静态资源和动态资源的访问3、页面跳转3.1、页面返回跳转 4、HAR的ArkUI组件、接口、资源,供其他应用或当前应用的其他模块引用4.1、导出HAR的ArkUI组件4.2、引用HAR的ArkUI组件 5、循环渲染6、状态管理最…...
vue开发中变量第一次双向绑定无效,界面并没有变化,第二次则又好了。
这个问题出现的太频繁了,基本大部分用户都遇到这个情况。大部分是弹框的情况。代码如下: <el-dialog:visible.sync="isShowCode" @close="closeCode()"><div class="u4259f"><edite-edite-code isNoShowClose="true"…...
C++基础(8)——string的相关面试题
目录 1.字符串转成整数 2.字符串相加 3.高精度加法模板(acwing) 4.验证回文串 1.字符串转成整数 题目:将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。数值为0或者字符串不是一个合法的数值则返回0。输入的…...

【Docker】06-DockerCompose
1. Docker compose 2. Docker Compose部署项目 docker-compose.yml version: "3.8"services:mysql:image: mysqlcontainer_name: mysqlports:- "3307:3306"environment:TZ: Asia/ShanghaiMYSQL_ROOT_PASSWORD: 123volumes:- "/root/docker/mysql/…...

代码随想录训练营Day27 | 77. 组合 | 216.组合总和III | 17.电话号码的字母组合
学习文档:代码随想录 (programmercarl.com) 视频链接:代码随想录算法公开课 | 最强算法公开课 | 代码随想录 (programmercarl.com) Leetcode 77. 组合 题目描述 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以…...

Linux文件重定向文件缓冲区
目录 一、C文件接口 二、系统文件I/O 2.1认识系统文件I/O 2.2系统文件I/O 2.3系统调用和库函数 2.4open( )的返回值--文件描述符 2.5访问文件的本质 三、文件重定向 3.1认识文件重定向 3.2文件重定向的本质 3.3在shell中添加重定向功能 3.4stdout和stderr 3.5如何理…...

训练贪吃蛇ai的后续记录
发现可以结合遗传算法的思路,产生更好的效果。 即每训练一段时间,就停下来测试一下新模型的效果。如果效果优于记录中最好的,则继续导入该模型并训练。重复几次,效果可能更好。 例如,昨晚我便通过唯一一个在十次测试中…...

WPF 手撸插件 八 操作数据库一
1、本文将使用SqlSugar创建Sqlite数据库,进行入门的增删改查等操作。擦,咋写着写着凌乱起来了。 SqlSugar官方文档:简单示例,1分钟入门 - SqlSugar 5x - .NET果糖网 2、环境SqlSugar V5.0版本需要.Net Framework 4.6 ࿰…...

代数结构基础 - 离散数学系列(八)
目录 1. 群(Group) 群的定义 群的示例 2. 环(Ring) 环的定义 环的示例 3. 域(Field) 域的定义 域的示例 域在密码学中的应用 4. 实际应用场景 1. 对称性与加密 2. 误差检测与纠正 3. 数据编码…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...