当前位置: 首页 > news >正文

「数据结构」线性表

定义和基本操作

  1. 定义:相同数据类型的 n ( n ≥ 0 ) n(n \ge 0) n(n0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表
  2. 一般表示: 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)
    1. a 1 a_1 a1是表头元素, a n a_n an是表尾元素
  3. 除第一个元素外,每个元素有且只有一个直接前驱;除最后一个元素外,每个元素有且只有一个直接后继

基本操作

  1. InitList(&L);初始化表。构造一个空的线性表L,分配内存空间
  2. DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间
  3. ListInsert(&L,i,e):插入操作。在表L中的第i个位置插入指定元素e
  4. ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值
  5. LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素
  6. GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值

其他常用操作

  1. Length(L):求表长。返回线性表L中数据元素的个数
  2. PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值
  3. Empty(L):判空操作。若L为空表,返回true,否则返回false

顺序表

定义

  1. 顺序表:用顺序存储的方式实现线性表的顺序存储。把逻辑上相邻的元素存储在物理位置也相邻的存储单元中
  2. 顺序表的实现-静态分配
#define MaxSize 50		//线性表的最大长度typedef struct {ElemType data[MaxSize];	//顺序表的元素int length;			//顺序表的当前长度
}SqList;				//顺序表的类型定义
  1. 顺序表的实现-动态分配
    1. 时间开销大
#define InitSize 50		//顺序表的初始长度
//动态分配
typedef struct {ElemType* data;	//指针动态分配数组的指针int maxsize;	//顺序表的最大容量int length;	//顺序表的当前长度
}SeqList;
  1. 动态申请和释放内存空间
    1. C:malloc、free函数

L.data = (ElemType*)malloc(sizeof(ElemType) * InitSize); //C语言初始动态分配

	2. C++:new、delete关键字```C++
L.data = new int[InitSize];
  1. 顺序表的特点
    1. 随机访问,可以在O(1)时间内找到第i个元素
    2. 存储密度高
    3. 拓展容量不方便
    4. 插入、删除操作不方便,需要移动大量元素

插入和删除

插入

  1. 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;
}
  1. 时间复杂度
    1. 最好情况:在表尾插入(即i=n+1),不需要移动元素,时间复杂度为O(1)
    2. 最坏情况:在表头插入(即i=1),元素后移语句执行n次,时间复杂度为O(n)
    3. 平均情况:移动结点的平均次数 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;
}
  1. 时间复杂度
    1. 最好情况:删除表尾元素(即i=n),时间复杂度为O(1)
    2. 最坏情况:删除表头元素(即i=1),时间复杂度为O(n)
    3. 平均情况:移动结点的平均次数 n − 1 2 \frac{n-1}{2} 2n1,时间复杂度O(n)

查找

按位查找

  1. 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];
}
  1. 时间复杂度O(1)
    1. 随机存取特性

按值查找

  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;	//退出循环,说明查找失败
}
  1. 时间复杂度
    1. 最好情况:查找的元素在表头,时间复杂度为O(1)
    2. 最坏情况:查找的元素在表尾(或不存在),时间复杂度为O(n)
    3. 平均情况:平均比较次数 n + 1 2 \frac{n+1}{2} 2n+1,时间复杂度为O(n)

单链表

定义

typedef struct LNode {	//定义单链表结点类型int data;	//每个结点存放一个指针元素struct LNode* next;	//指针指向下一个结点
}LNode, * LinkList;
  1. 不带头结点的单链表
bool InitList(LinkList& L){L = NULL;	//空表,暂时没有任何结点return true;
}
  1. 带头结点的单链表
bool InitList(LinkList& L) {L = (LNode*)malloc(sizeof(LNode));	//分配一个头结点if (L == NULL) {return false;}L -> next = NULL;	//头结点之后暂时还没有结点return true;
}

插入和删除

按位序插入(带头结点)

  1. 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;    //插入成功
}

按位序插入(不带头结点)

  1. 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;
}

按位序删除(带头结点)

  1. 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)

查找

按位查找

  1. 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;
}
  1. 平均时间复杂度O(n)

按值查找

  1. 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
}
  1. 时间复杂度O(n)

求表的长度

//求表的长度
int Length(LinkList L){int len = 0;    //统计表长LNode *p = L;while (p->next != NULL){p = p->next;len++;}return len;
  1. 时间复杂度O(n)

建立

  1. 尾插法
  2. 头插法

双链表

  1. 初始化
  2. 插入
  3. 删除
  4. 遍历

循环链表

  1. 循环单链表:表尾结点的next指针指向头结点
    1. 从一个结点出发可以找到其他任何一个结点
  2. 循环双链表

静态链表

  1. 概念:分配一整连续的内存空间,各个结点集中安置

顺序表和链表的比较

  1. 逻辑结构
    1. 都属于线性表,都是线性结构
  2. 物理结构/存储结构
    1. 顺序表
      1. 优点:支持随机存取、存取密度高
      2. 缺点:大片连续空间分配不方便,改变容量不方便
    2. 链表
      1. 优点:离散的小空间分配方便、改变容量方便
      2. 缺点:不可随机存取、存取密度低
  3. 数据的运算/基本操作
    1. 初始化
      1. 顺序表:需要预分配大片连续空间若分配空间过小,则之后不方便拓展容量;若分配空间过大,则浪费内存资源
        1. 静态分配:静态数组,容量不可改变
        2. 动态分配:动态数组(malloc、free),容量可改变,但需要移动大量元素,时间代价高
      2. 链表:只需分配一个头结点 (也可以不要头结点,只声明一个头指针) ,之后方便拓展
    2. 销毁
      1. 顺序表:修改Length=0
        1. 静态分配:系统自动回收空间
        2. 动态分配:需要手动free
      2. 链表:依次删除各个结点(free)
    3. 插入和删除
      1. 顺序表:需要把后续元素后移/前移,若数据元素很大,则移动的时间代价很大
      2. 链表:修改指针
    4. 查找
      1. 顺序表
        1. 按位查找:O(1)
        2. 按值查找:O(n)
          1. 若表内元素有序,可在 O ( l o g 2 n ) O(log_2n) O(log2n)时间内找到
      2. 链表
        1. 按位查找:O(n)
        2. 按值查找:O(n)

开放式问题回答思路

问题: 请描述顺序表和链表的 bla bla bla… 实现线性表时,用顺序表还是链表好?

顺序表和链表的逻辑结构都是线性结构,都属于线性表但是二者的存储结构不同,顺序表采用顺序存储…(特点,带来的优点缺点): 链表采用链式存储…(特点、导致的优缺点)。由于采用不同的存储方式实现,因此基本操作的实现效率也不同。当初始化时…;当插入一个数据元素时…;当删除一个数据元素时…; 当查找一个数据元素时…

相关文章:

「数据结构」线性表

定义和基本操作 定义&#xff1a;相同数据类型的 n ( n ≥ 0 ) n(n \ge 0) n(n≥0)个数据元素的有限序列&#xff0c;其中n为表长&#xff0c;当n0时线性表是一个空表一般表示&#xff1a; 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平台上进行回归计算的若干问题

作者&#xff1a;CSDN _养乐多_ 记录一些在Google Earth Engine &#xff08;GEE&#xff09;平台上进行机器学习回归计算的问题和解释。 文章目录 一、回归1.1 问&#xff1a;GEE平台上可以进行哪些机器学习回归算法&#xff1f;1.2 问&#xff1a;为什么只有这四种&#xf…...

Vivado -RAM

ip_ram 定义了一个名为ip_ram的模块&#xff0c;该模块具有以下端口&#xff1a; sys_clk&#xff1a;系统时钟输入。 sys_rst_n&#xff1a;系统复位输入。 module ip_ram( input sys_clk, input sys_rst_n);wire ram_en ; wire ram_wea …...

备战蓝桥杯---图论之最短路dijkstra算法

目录 先分个类吧&#xff1a; 1.对于有向无环图&#xff0c;我们直接拓扑排序&#xff0c;和AOE网类似&#xff0c;把取max改成min即可。 2.边权全部相等&#xff0c;直接BFS即可 3.单源点最短路 从一个点出发&#xff0c;到达其他顶点的最短路长度。 Dijkstra算法&#x…...

C#系列-C#实现秒杀功能(14)

在C#中实现商品秒杀功能&#xff0c;通常需要考虑并发控制、数据库事务、缓存策略、限流措施等多个方面。下面是一个简单的示例&#xff0c;演示了如何使用C#和数据库来实现一个基本的商品秒杀功能。 首先&#xff0c;假设你有一个商品表&#xff08;Product&#xff09;和一个…...

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 &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Deductive Closure Training of Language Models for Coherence, Accur…...

实验5-4 使用函数计算两点间的距离

本题要求实现一个函数&#xff0c;对给定平面任意两点坐标(x1​,y1​)和(x2​,y2​)&#xff0c;求这两点之间的距离。 函数接口定义&#xff1a; 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&#xf…...

ARM交叉编译搭建SSH

首先搭建好arm-linux交叉编译环境&#xff0c;开发板和主机可以ping通。 一、下载需要的源码 下载zlib: zlib-1.2.3.tar.gz 下载ssl: openssl-0.9.8d.tar.gz 下载ssh: openssh-4.6p1.tar.gz 二、交叉编译 新建目录/home/leo/ssh&#xff0c;并且将三个源码复制到该目录下。…...

###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 目录 一. 延时函数的生成 1.通过延时计算器得到延时函数 2.可赋值改变…...

回归预测模型:MATLAB多项式回归

1. 多项式回归模型的基本原理 多项式回归是线性回归的一种扩展&#xff0c;用于分析自变量 X X X与因变量 Y Y Y之间的非线性关系。与简单的线性回归模型不同&#xff0c;多项式回归模型通过引入自变量的高次项来增加模型的复杂度&#xff0c;从而能够拟合数据中的非线性模式。…...

「计算机网络」数据链路层

数据链路层的地位&#xff1a;网络中的主机、路由器等都必须实现数据链路层信道类型 点对点信道&#xff1a;使用一对一的点对点通信方式广播信道 使用一对多的广播通信方式必须使用专用的共享信道协议来协调这些主机的数据发送 使用点对点信道的数据链路层 数据链路和帧 链…...

【Linux】Ubuntu 22.04 升级 nodejs 到 v18

Ubuntu 22.04 已经安装的nodejs 版本 nodejs is already the newest version (12.22.9~dfsg-1ubuntu3.3). 删除以前的 nodejs 版本&#xff1a; 1. sudo apt remove nodejs rooterp:~# sudo apt remove nodejs Reading package lists... Done Building dependency tree..…...

当go get获取不到软件包时

当使用go get命令获取软件包时&#xff0c;如果无法成功获取&#xff0c;您可以尝试以下方法来解决问题&#xff1a; 检查网络连接&#xff1a;首先&#xff0c;确保您的计算机能够访问互联网&#xff0c;并且没有任何网络防火墙或代理设置阻止了go get命令的正常运行。 设置代…...

全网最详细解法|同济大学|高等数学|第八版|习题1-5

文章目录 全网最详细解法&#xff5c;同济大学&#xff5c;高等数学&#xff5c;第八版&#xff5c;习题1-5&#xff5c;5.1全网最详细解法&#xff5c;同济大学&#xff5c;高等数学&#xff5c;第八版&#xff5c;习题1-5&#xff5c;5.2 全网最详细解法&#xff5c;同济大学…...

可视化工具:将多种数据格式转化为交互式图形展示的利器

引言 在数据驱动的时代&#xff0c;数据的分析和理解对于决策过程至关重要。然而&#xff0c;不同的数据格式和结构使得数据的解读变得复杂和困难。为了解决这个问题&#xff0c;一种强大的可视化工具应运而生。这个工具具有将多种数据格式&#xff08;包括JSON、YAML、XML、C…...

[嵌入式AI从0开始到入土]14_orangepi_aipro小修补含yolov7多线程案例

[嵌入式AI从0开始到入土]嵌入式AI系列教程 注&#xff1a;等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间&#xff0c;后期会考虑出视频教程&#xff0c;务必催更&#xff0c;以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官…...

机器学习、深度学习、强化学习、迁移学习的关联与区别

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要了解并初步探究机器学习、深度学习、强化学习、迁移学习的关系与区别&#xff0c;通过清晰直观的关系图展现出四种“学习”之间的关系。虽然这四种“学习”方法在理论和应用上存在着一定的区别&#xff0c;但它们之间也…...

苹果为什么需要台积电3nm工艺芯片?

据《经济日报》报道&#xff0c;苹果公司的产品线将迎来重大升级。下一代应用于iPad、MacBook和iPhone的M4和A18处理器预计将会增加内置AI计算核心的数量&#xff0c;从而大幅提高AI运算能力。这一变化将导致对台积电&#xff08;TSMC&#xff09;订单的显著增长。据悉&#xf…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...