【数据结构】链表-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. 数据编码…...
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方式进行封装,供调用如何按…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
