「数据结构」线性表

定义和基本操作

  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… 实现线性表时,用顺序表还是链表好?

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/680054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】实现双向链表

目录 &#xff08;一&#xff09;头文件 &#xff08;二&#xff09; 功能实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;打印链表 &#xff08;3&#xff09; 头插与头删 &#xff08;4&#xff09;尾插与尾删 &#xff08;5&#xff09;指定位置之后…

STM32 + ESP8266,连接阿里云 上报/订阅数据

&#xff08;文章正在编辑中&#xff0c;一点点地截图操作过程&#xff0c;估计要拖拉两三天&#xff09; 一、烧录MQTT固件 ESP8266出厂时&#xff0c;默认是AT固件。连接阿里云&#xff0c;需要使用MQTT固件。 1、独立EPS8266模块的烧录方法 2、魔女开发板&#xff0c;板载…

‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序

遇到 vue-cli-service 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 的错误时&#xff0c;通常意味着Vue CLI没有被正确安装或配置在项目中。这可能是因为node_modules目录缺失了必要的包&#xff0c;或者局部安装的Vue CLI没有被正确设置到系统的PATH环境…

洛谷: P1308 [NOIP2011 普及组] 统计单词数

前言: 这道题没理解清题目表达意思&#xff0c;我开始想的是用map来记录个数&#xff0c;然后一个变量记录一开始出现的单词位置&#xff0c;不挺简单的吗&#xff0c;然后....就AC了2个..从错误提示能看到个数没啥问题&#xff0c;但是第一个单词位置不对&#xff0c;看了新样…

二级C语言笔试10

(总分101,考试时间90分钟) 一、选择题 1. 设有如下关系表&#xff1a; A) TR∩S B) TR∪S C) TRS D) TR/S 2. 在一棵二叉树中&#xff0c;叶子结点共有30个&#xff0c;度为1的结点共有40个&#xff0c;则该二叉树中的总结点数共有( )个。 A) 89 …

【51单片机】AT24C02(江科大、爱上半导体)

一、AT24C02 1.AT24C02介绍 AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息 存储介质:E2PROM 通讯接口:12C总线 容量:256字节 2.引脚即应用电路 本开发板AT24C02原理图 12C地址全接地,即全为0 WE接地,没有写使能 SCL接P21 S…

Microsoft Excel 加载数据分析工具

Microsoft Excel 加载数据分析工具 1. 打开 Excel&#xff0c;文件 -> 选项2. 加载项 -> 转到…3. 分析工具库、分析工具库 - VBA4. 打开 Excel&#xff0c;数据 -> 数据分析References 1. 打开 Excel&#xff0c;文件 -> 选项 2. 加载项 -> 转到… ​​​ 3…

不安全的 HTTP请求 漏洞原理以及修复方法

漏洞名称&#xff1a;不安全的HTTP方法、危险的HTTP方法 漏洞描述&#xff1a;不安全的HTTP方法一般包括&#xff1a;TRACE、PUT、DELETE、COPY 等。其中最常见的为TRACE方法可以回显服务器收到的请求&#xff0c;主要用于测试或诊断&#xff0c;恶意攻击者可以利用该方法进行…

【Java程序设计】【C00270】基于Springboot的moba类游戏攻略分享平台(有论文)

基于Springboot的moba类游戏攻略分享平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的游戏攻略分享平台 本系统分为系统功能模块、管理员功能模块、以及用户后台功能模块。 系统功能模块&#xff1a;在平台首…

关闭Ubuntu 默认开启的自动安全更新

简介 Ubuntu 和 Debian 应该从很早版本开始预装unattended-upgrades 包&#xff0c;并开启自动更新有安全问题的软件包。 &#xff08;最小化安装不会安装此包&#xff09; 有什么影响&#xff1f; 如果软件包有安全漏洞&#xff0c;Ubuntu发布更新包后会自动安装更新并重启…

【开源】基于JAVA+Vue+SpringBoot的房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

Ocr之TesseractOcr的安装及使用

目录 一、安装环境 二、安装内容 三、安装过程及识别测试 1. 安装过程 2. 程序编写 总结 1. 安装复杂度较低 2. 国外开源Ocr 3. 可设置识别参数 4. 工具类 一、 系统环境windows 10 linux环境也可安装, 可借鉴此篇文章>> | 二、安装内容 Tesseract exe 程序安…

常见的web前端开发框架:Vue.js

常见的Web前端开发框架包括Bootstrap、Vue.js、React.js、Angular.js等。每个框架都有其独特的特点和优势&#xff0c;开发者可以根据项目的需求和个人的喜好来选择合适的框架。同时&#xff0c;随着技术的不断发展&#xff0c;新的框架和工具也会不断涌现&#xff0c;为Web前端…

python学习23

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

数模.matlab符号计算方程

一、符号函数 a&#xff1a;整理简化&#xff1a; b&#xff1a;因式分解&#xff1a; c&#xff1a;多项式展开 d&#xff1a;合并&#xff1a; e&#xff1a;计算分子分母&#xff1a; f&#xff1a;求导&#xff1a; f&#xff1a;差分&#xff1a; g&#xff1a;不定积分&a…

阿里云服务器“带宽计费模式”怎么选?有啥区别?

阿里云服务器带宽计费模式分为“按固定带宽”和“按使用流量”&#xff0c;有什么区别&#xff1f;按固定带宽是指直接购买多少M带宽&#xff0c;比如1M、5M、10M、100M等&#xff0c;阿里云直接分配用户所购买的带宽值&#xff0c;根据带宽大小先付费再使用&#xff1b;按使用…

BYTEVALUE 百为流控路由器远程命令执行漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

Mybatis的使用

MyBatis 是一个流行的 Java 持久层框架&#xff0c;它提供了 SQL 映射和对象关系映射的功能&#xff0c;让开发者能够更加便捷地操作数据库。MyBatis 通过 XML 或注解的方式配置 SQL 语句&#xff0c;并将 Java 对象与数据库表进行映射&#xff0c;以简化 JDBC 的复杂操作。以下…

单片机接收PC发出的数据

#include<reg51.h> //包含单片机寄存器的头文件 /***************************************************** 函数功能&#xff1a;接收一个字节数据 ***************************************************/ unsigned char Receive(void) { unsigned char dat; …