「数据结构」线性表
定义和基本操作
- 定义:相同数据类型的 n ( n ≥ 0 ) n(n \ge 0) n(n≥0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表
- 一般表示: L = ( a 1 , a 2 , … … , a i , a i + 1 , a n ) L=(a_1,a_2,……,a_i,a_{i+1},a_n) L=(a1,a2,……,ai,ai+1,an)
- a 1 a_1 a1是表头元素, a n a_n an是表尾元素
- 除第一个元素外,每个元素有且只有一个直接前驱;除最后一个元素外,每个元素有且只有一个直接后继
基本操作
InitList(&L);初始化表。构造一个空的线性表L,分配内存空间DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间ListInsert(&L,i,e):插入操作。在表L中的第i个位置插入指定元素eListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值
其他常用操作
Length(L):求表长。返回线性表L中数据元素的个数PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值Empty(L):判空操作。若L为空表,返回true,否则返回false
顺序表
定义
- 顺序表:用顺序存储的方式实现线性表的顺序存储。把逻辑上相邻的元素存储在物理位置也相邻的存储单元中
- 顺序表的实现-静态分配
#define MaxSize 50 //线性表的最大长度typedef struct {ElemType data[MaxSize]; //顺序表的元素int length; //顺序表的当前长度
}SqList; //顺序表的类型定义
- 顺序表的实现-动态分配
- 时间开销大
#define InitSize 50 //顺序表的初始长度
//动态分配
typedef struct {ElemType* data; //指针动态分配数组的指针int maxsize; //顺序表的最大容量int length; //顺序表的当前长度
}SeqList;
- 动态申请和释放内存空间
- C:malloc、free函数
L.data = (ElemType*)malloc(sizeof(ElemType) * InitSize); //C语言初始动态分配
2. C++:new、delete关键字```C++
L.data = new int[InitSize];
- 顺序表的特点
- 随机访问,可以在O(1)时间内找到第i个元素
- 存储密度高
- 拓展容量不方便
- 插入、删除操作不方便,需要移动大量元素
插入和删除
插入
ListInsert(&L,i,e):插入操作。在表L中第i个位置上插入指定元素
bool ListInsert(SqList& L, int i, int e){if (i<1 || i>L.length + 1) { //判断i的范围是否有效return false;}if (L.length >= MaxSize) { //当前存储空间已满,不能插入return false;}for (int j = L.length; j >= i; j--) { //将第i个元素及之后的元素后移L.data[j] = L.data[j - 1];}L.data[i - 1] = e; //在位置i处放eL.length++; //长度加1return true;
}
- 时间复杂度
- 最好情况:在表尾插入(即i=n+1),不需要移动元素,时间复杂度为O(1)
- 最坏情况:在表头插入(即i=1),元素后移语句执行n次,时间复杂度为O(n)
- 平均情况:移动结点的平均次数 n 2 \frac{n}{2} 2n,时间复杂度O(n)
删除
bool ListDelete(SqList& L, int i, int& e){if (i<1 || i>L.length + 1) { //判断i的范围是否有效return false;}e = L.data[i - 1]; //将被删除的元素赋值给efor (int j = i; j < L.length; j++) { //将第i个位置后的元素前移L.data[j - 1] = L.data[j];}L.length--; 线性表长度减1return true;
}
- 时间复杂度
- 最好情况:删除表尾元素(即i=n),时间复杂度为O(1)
- 最坏情况:删除表头元素(即i=1),时间复杂度为O(n)
- 平均情况:移动结点的平均次数 n − 1 2 \frac{n-1}{2} 2n−1,时间复杂度O(n)
查找
按位查找
GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值
int GetElem(SqList L, int i){return L.data[i - 1];
}int GetElem(SeqList L, int i){return L.data[i - 1];
}
- 时间复杂度O(1)
- 随机存取特性
按值查找
LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素
int LoacteElem(SqList L, int e){int i;for (i = 0; i < L.length; i++) {if (L.data[i] == e) { //"=="不可以用于比较两个结构体return i + 1; //下标为i的元素值等于e,返回其位序i+1}}return 0; //退出循环,说明查找失败
}
- 时间复杂度
- 最好情况:查找的元素在表头,时间复杂度为O(1)
- 最坏情况:查找的元素在表尾(或不存在),时间复杂度为O(n)
- 平均情况:平均比较次数 n + 1 2 \frac{n+1}{2} 2n+1,时间复杂度为O(n)
单链表
定义
typedef struct LNode { //定义单链表结点类型int data; //每个结点存放一个指针元素struct LNode* next; //指针指向下一个结点
}LNode, * LinkList;
- 不带头结点的单链表
bool InitList(LinkList& L){L = NULL; //空表,暂时没有任何结点return true;
}
- 带头结点的单链表
bool InitList(LinkList& L) {L = (LNode*)malloc(sizeof(LNode)); //分配一个头结点if (L == NULL) {return false;}L -> next = NULL; //头结点之后暂时还没有结点return true;
}
插入和删除
按位序插入(带头结点)
ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e
bool ListInsert(LinkList &L, int i, ElemType e){if(i<1){return false;}LNode *p; //指针p指向当前扫描的结点int j=0; //当前p指向的是第几个结点p=L; //L指向头结点,头结点是第0个结点(不存储数据)while(p!=NULL && j<i-1){ //循环找到第i-1个结点p=p->next;j++;}if(p==NULL){ //i值不合法return false;}LNode *s=(LNode *)malloc(sizeof(LNode));s->data=e;s->next=p->next;p-next=s; //将结点s连到p之后return true; //插入成功
}
按位序插入(不带头结点)
ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e
bool ListInsert(LinkList &L, int i, ElemType e){if(i<1){return false;}if(i==1){ //插入第i个结点的操作与其他结点不同LNode *s=(LNode *)malloc(sizeof(LNode));s->data=e;s->next=L;L=s; //头指针指向新结点return true; //插入成功}LNode *p; //指针p指向当前扫描的结点int j=1; //当前p指向的是第几个结点p=L; //p指向第1个结点(不是头结点)while(p!=NULL && j<i-1){ //循环找到第i-1个结点p=p->next;j++;}if(p==NULL){ //i值不合法return false;}LNode *s=(LNode *)malloc(sizeof(LNode));s->data=e;s->next=p->next;p-next=s; //将结点s连到p之后return true; //插入成功
}
指定结点的后插操作
//在p结点之后插入元素e
bool InsertNextNode(LNode *p, ElemType e){if(p==NULL){return false;}LNode *s=(LNode *)malloc(sizeof(LNode));if(s==NULL){ //内存分配失败return false;}s->data=e; //用结点s保存数据元素es->next=p->next;p->next=s; //将结点s连接到p之后return true;
}
指定元素的前插操作
//在p结点之前插入元素e
bool InsertPriorNode(LNode *p, ElemType e){if(p==NULL){return false;}LNode *s=(LNode *)malloc(sizeof(LNode));if(s==NULL){ //内存分配失败return false;}s->next=p->next;p->next=s; //将结点s连接到p之后s->data=p->data; //将p中的元素复制到s中p->data=e; //p中元素覆盖为ereturn true;
}
按位序删除(带头结点)
ListDelete(&L,i,&e);删除操作,删除表L中第i个位置的元素,并用e返回元素的值
bool ListDelete(LinkList &L,int i,ElemType &e){if(i<1){return false;}LNode *p; //指针p指向当前扫描到的结点int j=0; //当前p指向的是第几个结点p=L; //L指向头结点,头结点是第0个结点 (不存数据)while (p!=NULL & j<i-1){ //循环找至第 i-1个结点p=p->next;j++;}if(p==NULL){ //i值不合法return false;}if(p->next == NULL){ //第i-1个结点之后已无其他结点return false;}LNode *q=p->next; //令q指向被删除结点e = q->data; //用e返回元素的值p->next=q->next; //将*q结点从链中“断开”free(q); //释放结点的存储空间return true; //删除成功
}
指定结点的删除
//删除指定结点p
bool DeleteNode (LNode *p){if (p==NULL){return false;}LNode *q=p->next; //令q指向*p的后继结点p->data=p->next->data; //和后继结点交换数据域p->next=q->next; //将*q结点从链中“断开”free(q); //释放后继结点的存储空间return true;
}
如果p是最后一个结点,只能从表头开始寻找p的前驱,时间复杂度O(n)
查找
按位查找
GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值
//按位查找,返回第i个元素(带头结点)
LNode *GetElem(LinkList, int i){if(i<0){return NULL;}LNode *p; //指针p指向当前扫描到的结点int j=0; //当前p指向的是第几个结点p=L; //L指向头结点,头结点是第0个结点(不存储数据)while (p!=NULL && j<i){ //循环找到第 i 个结点p=p->next;j++;}return p;
}
- 平均时间复杂度O(n)
按值查找
LocateElem(L,i):按值查找操作。在表L中查找具有给定关键字值的元素
//按值查找,找到数据域==e 的结点
LNode * LocateElem(LinkList L,ElemType e){LNode *p = L->next;//从第1个结点开始查找数据域为e的结点while (p != NULL && p->data != e)p = p->next;return p; //找到后返回该结点指针,否则返回NULL
}
- 时间复杂度O(n)
求表的长度
//求表的长度
int Length(LinkList L){int len = 0; //统计表长LNode *p = L;while (p->next != NULL){p = p->next;len++;}return len;
- 时间复杂度O(n)
建立
- 尾插法
- 头插法
双链表
- 初始化
- 插入
- 删除
- 遍历
循环链表
- 循环单链表:表尾结点的next指针指向头结点
- 从一个结点出发可以找到其他任何一个结点
- 循环双链表
静态链表
- 概念:分配一整连续的内存空间,各个结点集中安置
顺序表和链表的比较
- 逻辑结构
- 都属于线性表,都是线性结构
- 物理结构/存储结构
- 顺序表
- 优点:支持随机存取、存取密度高
- 缺点:大片连续空间分配不方便,改变容量不方便
- 链表
- 优点:离散的小空间分配方便、改变容量方便
- 缺点:不可随机存取、存取密度低
- 顺序表
- 数据的运算/基本操作
- 初始化
- 顺序表:需要预分配大片连续空间若分配空间过小,则之后不方便拓展容量;若分配空间过大,则浪费内存资源
- 静态分配:静态数组,容量不可改变
- 动态分配:动态数组(malloc、free),容量可改变,但需要移动大量元素,时间代价高
- 链表:只需分配一个头结点 (也可以不要头结点,只声明一个头指针) ,之后方便拓展
- 顺序表:需要预分配大片连续空间若分配空间过小,则之后不方便拓展容量;若分配空间过大,则浪费内存资源
- 销毁
- 顺序表:修改Length=0
- 静态分配:系统自动回收空间
- 动态分配:需要手动free
- 链表:依次删除各个结点(free)
- 顺序表:修改Length=0
- 插入和删除
- 顺序表:需要把后续元素后移/前移,若数据元素很大,则移动的时间代价很大
- 链表:修改指针
- 查找
- 顺序表
- 按位查找:O(1)
- 按值查找:O(n)
- 若表内元素有序,可在 O ( l o g 2 n ) O(log_2n) O(log2n)时间内找到
- 链表
- 按位查找:O(n)
- 按值查找:O(n)
- 顺序表
- 初始化
开放式问题回答思路
问题: 请描述顺序表和链表的 bla bla bla… 实现线性表时,用顺序表还是链表好?
顺序表和链表的逻辑结构都是线性结构,都属于线性表但是二者的存储结构不同,顺序表采用顺序存储…(特点,带来的优点缺点): 链表采用链式存储…(特点、导致的优缺点)。由于采用不同的存储方式实现,因此基本操作的实现效率也不同。当初始化时…;当插入一个数据元素时…;当删除一个数据元素时…; 当查找一个数据元素时…
相关文章:
「数据结构」线性表
定义和基本操作 定义:相同数据类型的 n ( n ≥ 0 ) n(n \ge 0) n(n≥0)个数据元素的有限序列,其中n为表长,当n0时线性表是一个空表一般表示: L ( a 1 , a 2 , … … , a i , a i 1 , a n ) L(a_1,a_2,……,a_i,a_{i1},a_n) L(a…...
GEE:关于在GEE平台上进行回归计算的若干问题
作者:CSDN _养乐多_ 记录一些在Google Earth Engine (GEE)平台上进行机器学习回归计算的问题和解释。 文章目录 一、回归1.1 问:GEE平台上可以进行哪些机器学习回归算法?1.2 问:为什么只有这四种…...
Vivado -RAM
ip_ram 定义了一个名为ip_ram的模块,该模块具有以下端口: sys_clk:系统时钟输入。 sys_rst_n:系统复位输入。 module ip_ram( input sys_clk, input sys_rst_n);wire ram_en ; wire ram_wea …...
备战蓝桥杯---图论之最短路dijkstra算法
目录 先分个类吧: 1.对于有向无环图,我们直接拓扑排序,和AOE网类似,把取max改成min即可。 2.边权全部相等,直接BFS即可 3.单源点最短路 从一个点出发,到达其他顶点的最短路长度。 Dijkstra算法&#x…...
C#系列-C#实现秒杀功能(14)
在C#中实现商品秒杀功能,通常需要考虑并发控制、数据库事务、缓存策略、限流措施等多个方面。下面是一个简单的示例,演示了如何使用C#和数据库来实现一个基本的商品秒杀功能。 首先,假设你有一个商品表(Product)和一个…...
Java ‘Elasticsearch‘ 操作
依赖 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-elasticsearch --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</ar…...
【AI视野·今日NLP 自然语言处理论文速览 第七十八期】Wed, 17 Jan 2024
AI视野今日CS.NLP 自然语言处理论文速览 Wed, 17 Jan 2024 (showing first 100 of 163 entries) Totally 100 papers 👉上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Deductive Closure Training of Language Models for Coherence, Accur…...
实验5-4 使用函数计算两点间的距离
本题要求实现一个函数,对给定平面任意两点坐标(x1,y1)和(x2,y2),求这两点之间的距离。 函数接口定义: double dist( double x1, double y1, double x2, double y2 );其中用户传入的参数为平面上两个点的坐标(x1, y1)和(x2, y2)&…...
【JavaEE】_JavaScript(Web API)
目录 1. DOM 1.1 DOM基本概念 1.2 DOM树 2. 选中页面元素 2.1 querySelector 2.2 querySelectorAll 3. 事件 3.1 基本概念 3.2 事件的三要素 3.3 示例 4.操作元素 4.1 获取/修改元素内容 4.2 获取/修改元素属性 4.3 获取/修改表单元素属性 4.3.1 value…...
ARM交叉编译搭建SSH
首先搭建好arm-linux交叉编译环境,开发板和主机可以ping通。 一、下载需要的源码 下载zlib: zlib-1.2.3.tar.gz 下载ssl: openssl-0.9.8d.tar.gz 下载ssh: openssh-4.6p1.tar.gz 二、交叉编译 新建目录/home/leo/ssh,并且将三个源码复制到该目录下。…...
###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
前言:感谢您的关注哦,我会持续更新编程相关知识,愿您在这里有所收获。如果有任何问题,欢迎沟通交流!期待与您在学习编程的道路上共同进步。 目录 一. 延时函数的生成 1.通过延时计算器得到延时函数 2.可赋值改变…...
回归预测模型:MATLAB多项式回归
1. 多项式回归模型的基本原理 多项式回归是线性回归的一种扩展,用于分析自变量 X X X与因变量 Y Y Y之间的非线性关系。与简单的线性回归模型不同,多项式回归模型通过引入自变量的高次项来增加模型的复杂度,从而能够拟合数据中的非线性模式。…...
「计算机网络」数据链路层
数据链路层的地位:网络中的主机、路由器等都必须实现数据链路层信道类型 点对点信道:使用一对一的点对点通信方式广播信道 使用一对多的广播通信方式必须使用专用的共享信道协议来协调这些主机的数据发送 使用点对点信道的数据链路层 数据链路和帧 链…...
【Linux】Ubuntu 22.04 升级 nodejs 到 v18
Ubuntu 22.04 已经安装的nodejs 版本 nodejs is already the newest version (12.22.9~dfsg-1ubuntu3.3). 删除以前的 nodejs 版本: 1. sudo apt remove nodejs rooterp:~# sudo apt remove nodejs Reading package lists... Done Building dependency tree..…...
当go get获取不到软件包时
当使用go get命令获取软件包时,如果无法成功获取,您可以尝试以下方法来解决问题: 检查网络连接:首先,确保您的计算机能够访问互联网,并且没有任何网络防火墙或代理设置阻止了go get命令的正常运行。 设置代…...
全网最详细解法|同济大学|高等数学|第八版|习题1-5
文章目录 全网最详细解法|同济大学|高等数学|第八版|习题1-5|5.1全网最详细解法|同济大学|高等数学|第八版|习题1-5|5.2 全网最详细解法|同济大学…...
可视化工具:将多种数据格式转化为交互式图形展示的利器
引言 在数据驱动的时代,数据的分析和理解对于决策过程至关重要。然而,不同的数据格式和结构使得数据的解读变得复杂和困难。为了解决这个问题,一种强大的可视化工具应运而生。这个工具具有将多种数据格式(包括JSON、YAML、XML、C…...
[嵌入式AI从0开始到入土]14_orangepi_aipro小修补含yolov7多线程案例
[嵌入式AI从0开始到入土]嵌入式AI系列教程 注:等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间,后期会考虑出视频教程,务必催更,以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官…...
机器学习、深度学习、强化学习、迁移学习的关联与区别
Hi,大家好,我是半亩花海。本文主要了解并初步探究机器学习、深度学习、强化学习、迁移学习的关系与区别,通过清晰直观的关系图展现出四种“学习”之间的关系。虽然这四种“学习”方法在理论和应用上存在着一定的区别,但它们之间也…...
苹果为什么需要台积电3nm工艺芯片?
据《经济日报》报道,苹果公司的产品线将迎来重大升级。下一代应用于iPad、MacBook和iPhone的M4和A18处理器预计将会增加内置AI计算核心的数量,从而大幅提高AI运算能力。这一变化将导致对台积电(TSMC)订单的显著增长。据悉…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
