「数据结构」线性表
定义和基本操作
- 定义:相同数据类型的 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)订单的显著增长。据悉…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
