线性表的定义和基本操作

news2024/12/26 12:59:10

线性表的定义和基本操作

一、线性表的定义

线性表(Linear List)是具有相同数据类型的n(n>=0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表。若用L命名线性表,则其一般表示为

L = (a1,a2,...,ai,ai+1,...,an)

ai是线性表中的“第i个”元素线性表中的位序

a1是表头元素;an是表尾元素。

除第一个元素外,每个元素有且仅有一个直接前驱;出最后一个元素外,每个元素有且仅有一个直接后继

二、线性表的基本操作

InitList(&L):初始化表。构造一个空的线性表L,分配内存空间。

DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占有的内存空间。

ListInsert(&L,i,e):插入操作。在表L中的第i个位序(位置)上插入制定元素e。

ListDelete(&L,i,&e):删除操作。删除表L中第i个位序(位置)的元素,并用e返回删除元素的值。

LocateElem(L,e):按值查找操作。在表L中查找具体给定关键字值的元素。

GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。

其他常用操作:

Length(L):求表长操作。返回线性表L的长度,即L中数据元素的个数。

PrinList(L):输出操作。按前后顺序输出线性表L的所有元素值。

Empty(L):判空操作。若L为空表,则返回true,否则返回false。

Tips:

对数据的操作(记忆思路)——创(Init)销(Destroy)、增(Insert)删(Delete)改(Alter)查(Query)

C语言函数的定义

实际开发中,可根据实际需求定义其他的基本操作

函数名和参数的形式、命令都可改变

什么时候需要传入“&”——对参数的修改结果需要“带回来”

三、初始化代码实践

1、顺序表静态分配
#include <stdio.h>
// 顺序表存储空间静态分配
#define MaxSize 10      // 定义最大长度
typedef int ElemType;   // int类型重命名为ElemType,方便后续调整
typedef struct{         // 定义结构体
    ElemType data[MaxSize];         // 用静态的数组存放数据元素
    ElemType length;                // 数组长度
}SqList;
void InitList(SqList &L){           // 初始化顺序表
    L.length=0;                     // 长度赋值,没有设置数据元素的默认值
}
int main() {
    SqList L;           // 声明一个顺序表
    InitList(L);    // 初始化顺序表
    for (int i = 0; i < MaxSize; i++) {
        // 尝试违规打印整个data数组
        printf("data[%d]=%d\n", i, L.data[i]);
    }
    return 0;
}

在这里插入图片描述

#include <stdio.h>
// 顺序表存储空间静态分配
#define MaxSize 10      // 定义最大长度
typedef int ElemType;   // int类型重命名为ElemType,方便后续调整
typedef struct{         // 定义结构体
    ElemType data[MaxSize];         // 用静态的数组存放数据元素
    ElemType length;                // 数组长度
}SqList;
void InitList(SqList &L){          // 初始化顺序表
    for(int i=0;i<MaxSize;i++){    // 设置数据元素的默认值,否则内存中会有遗留的“脏数据”
        L.data[i]=0;
    }
    L.length=0;                     // 长度赋值,没有设置数据元素的默认值
}
int main() {
    SqList L;           // 声明一个顺序表
    InitList(L);    // 初始化顺序表
    for (int i = 0; i < L.length; i++) {    //按照数据长度进行打印
        // 尝试违规打印整个data数组
        printf("data[%d]=%d\n", i, L.data[i]);
    }
    return 0;
}
2、顺序表动态分配
#include <stdio.h>
#include <stdlib.h>
// 顺序表存储空间动态分配
#define InitSize 10      // 顺序表初始长度
typedef int ElemType;   // int类型重命名为ElemType,方便后续调整
typedef struct{         // 定义结构体
    ElemType *data;     // 用静态的数组存放数据元素
    ElemType MaxSize;   // 顺序表最大容量
    ElemType length;    // 顺序表数据长度
}SqList;
void InitList(SqList &L){           // 初始化顺序表
    // 用malloc函数申请一片连续的存储空间
    L.data = (ElemType *) malloc(InitSize * sizeof(ElemType));
    L.MaxSize = InitSize;
    L.length = 0;
}
void IncreaseSize(SqList &L, ElemType len){
    ElemType *p=L.data;
    L.data = (int *) malloc((L.MaxSize + len) * sizeof(ElemType));
    for (ElemType i = 0; i < L.length; i++) {
        L.data[i]=p[i];     // 将数据复制到新区域
    }
    L.MaxSize=L.MaxSize+len;    // 顺序表最大长度增加len
    free(p);            // 释放原来的内存空间
}
int main() {
    SqList L;           // 声明一个顺序表
    InitList(L);    // 初始化顺序表
    IncreaseSize(L, 5);
    return 0;
}
3、特点

随机访问:即可以在O(1)时间内找到第i个元素。

存储密度高:每个节点只存储数据元素。

扩展容量不方便:即便采取动态分配的方式实现,拓展长度的时间复杂度也比较高。

插入、删除操作不方便:需要移动大量的元素。

四、插入和删除

1、顺序表插入实践
#include <stdio.h>

#define MaxSize 10      // 指定大小
typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    ElemType length;
}SqList;

bool InsertList(SqList &L, ElemType position, ElemType element){
    if (position < 1 || position > L.length + 1) {      // 判断插入是否合理
        return false;
    }
    if (L.length >= MaxSize) {          // 判断插入是否合理
        return false;
    }
    for (ElemType i = L.length; i >= position; i--) {   // 循环从最后一位开始,到插入的位序,减减
        L.data[i] = L.data[i-1];        // 将前一位值向后移一位
    }
    L.data[position-1] = element;       // 插入的位置附上要插入的值,注意数组下标和位序是相差一位的
    L.length++;                         // 插入一个元素之后,数组的长度是要加1
    return true;
}

void PrintList(SqList L){
    for (ElemType i = 0; i < L.length; i++) {
        printf("data[%d]=%d\n",i,L.data[i]);
    }
}
int main() {
    SqList L;   // 初始化
    for (ElemType i = 0; i < 6; i++) {      // 数组赋值
        L.data[i]=i*2;
    }
    L.length=6;
    bool ret;
    ret = InsertList(L, 6, 20); // 调用插入
    if (ret) {          // 判断是否正常插入
        printf("insert element success\n");
        PrintList(L);
    } else {
        printf("insert element failed\n");
    }
    return 0;
}

在这里插入图片描述

插入操作的时间复杂度

最好情况:新元素插入到表尾,按照以上例子为插入位序为6的位置,不需要移动元素,循环0次,最好时间复杂度=O(1)

最坏情况:新元素插入到表头,需要将原有的n个元素全部都向后移动,循环n次,最坏时间复杂度=O(n)

平均情况:假设新元素插入到任何一个位置的概率相同,即i=1,2,3,…,length+1的概率都是
p = 1 n + 1 p=\frac{1}{n+1} p=n+11
i=1,循环n次,i=2,循环n-1,…,i=n+1,循环0次
平均循环次数 = n p + ( n − 1 ) p − ( n − 2 ) p + . . . + 1. p = n ( n + 1 ) 2 ⋅ 1 n + 1 = n 2 平均循环次数=np+(n-1)p-(n-2)p+...+1.p=\frac{n(n+1)}{2}·\frac{1}{n+1}=\frac{n}{2} 平均循环次数=np+(n1)p(n2)p+...+1.p=2n(n+1)n+11=2n
平均时间复杂度=O(n)

2、顺序表删除实践
#include <stdio.h>

#define MaxSize 10      // 指定大小
typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    ElemType length;
}SqList;

bool DeleteList(SqList &L, ElemType position, ElemType &element){
    if (position < 1 || position > L.length + 1) {      // 判断删除是否合理
        return false;
    }
    element = L.data[position-1];       // 删除的数据,注意数组的下标和位序的关系
    for (ElemType i = position; i <L.length; i++) {   // 循环从要删除的位序开始,结束条件为到数组长度减一位的位置
        L.data[i-1] = L.data[i];        // 将删除位序的值向前移动
    }
    L.length--;                         // 删除一个元素之后,数组的长度是要减1
    return true;
}

void PrintList(SqList L){
    for (ElemType i = 0; i < L.length; i++) {
        printf("data[%d]=%d\n",i,L.data[i]);
    }
}
int main() {
    SqList L;   // 初始化
    for (ElemType i = 0; i < 6; i++) {      // 数组赋值
        L.data[i]=i*2;
    }
    L.length=6;
    ElemType num;
    bool ret;
    ret = DeleteList(L, 2, num); // 调用插入
    if (ret) {          // 判断是否正常插入
        printf("delete element success!delete element is %d\n",num);
        PrintList(L);
    } else {
        printf("insert element failed\n");
    }
    return 0;
}

在这里插入图片描述

最好情况:删除表尾元素,不需要移动元素,循环0次,最好时间复杂度=O(1)

最坏情况:删除表头元素,需要将后续n-1个元素全部向前移动,循环n-1次,最坏时间复杂度=O(n)

平均情况:假设删除任何一个元素的概率相同,即i=1,2,3,…,length+1的概率都是
p = 1 n p=\frac{1}{n} p=n1
i=1,循环n-1次,i=2,循环n-2,…,i=n,循环0次
平均循环次数 = ( n − 1 ) p − ( n − 2 ) p + . . . + 1. p = n ( n − 1 ) 2 ⋅ 1 n = n − 1 2 平均循环次数=(n-1)p-(n-2)p+...+1.p=\frac{n(n-1)}{2}·\frac{1}{n}=\frac{n-1}{2} 平均循环次数=(n1)p(n2)p+...+1.p=2n(n1)n1=2n1
平均时间复杂度=O(n)

3、顺序表查询实践
#include <stdio.h>

// 静态分配
#define MaxSize 10		// 定义最大长度

typedef int Element;

typedef struct{
    Element data[MaxSize];		// 用静态的“数组”存放数据元素
    int length;
}SqList;
	
int GetList(SqList L,int position){		// 查询该位序的值
    return L.data[position - 1];		// 位序和数组下标少一位
}

int LocateList(SqList L,int num){		// 查询值在数据哪个位序
    for (int i = 0; i < L.length; i++) {
        if (L.data[i] == num) {
            return i+1;					// 返回位序和数组下标相差一位
        }
    }
}
int main() {
    SqList L;
    for (int i = 0; i < 5; i++) {
        L.data[i] = i*2;
    }
    L.length=5;
    int ret;
    ret = GetList(L, 3);
    printf("Get List num is %d\n", ret);

    ret = LocateList(L,4);
    printf("Locate List position is %d\n", ret);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
// 动态分配
#define InitSize 10

typedef int Element;

typedef struct{
    Element *data;
    int MaxSize;
    int length;
}SqList;

void InitList(SqList &L){               // 初始化
    L.data = (int *) malloc(InitSize*sizeof(int));
    L.MaxSize = InitSize;
    L.length = 0;
}

int GetList(SqList L,int position){		// 查询该位序的值
    return L.data[position - 1];		// 位序和数组下标少一位
}

int LocateList(SqList L,int num){		// 查询值在数据哪个位序
    for (int i = 0; i < L.length; i++) {
        if (L.data[i] == num) {
            return i+1;					// 返回位序和数组下标相差一位
        }
    }
}
int main() {
    SqList L;
    InitList(L);
    for (int i = 0; i < 5; i++) {
        L.data[i] = i*2;
    }
    L.length=5;
    int ret;
    ret = GetList(L, 3);
    printf("Get List num is %d\n", ret);

    ret = LocateList(L,4);
    printf("Locate List position is %d\n", ret);
    return 0;
}

时间复杂度:

按位查找:O(1)

按值查找:最好时间复杂度:O(1),在第一个位置

​ 最坏时间复杂度:O(n),在最后一个位置

​ 平均时间复杂度:O(n),目标元素在每个位置的概率相同
O = ( 1 + 2 + . . . + n ) 1 n = n ( n + 1 ) 2 ⋅ 1 n = n + 1 2 = O ( n ) O=(1+2+...+n)\frac{1}{n}=\frac{n(n+1)}{2}·\frac{1}{n}=\frac{n+1}{2}=O(n) O=(1+2+...+n)n1=2n(n+1)n1=2n+1=O(n)

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

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

相关文章

防止请求重复提交:注解+拦截器的实现方案

文章目录 了解请求重复提交解决思路具体实现 了解请求重复提交 请求重复提交是指用户在一次请求还未处理完成时&#xff0c;重复提交了相同的请求。这种情况通常发生在网络延迟、用户误操作或系统性能不佳等情况下。 请求重复提交可能会导致以下问题和影响&#xff1a; 数据不…

学习笔记:二分图

二分图 引入 二分图又被称为二部图。 二分图就是可以二分答案的图。 二分图是节点由两个集合组成&#xff0c;且两个集合内部没有边的图。换言之&#xff0c;存在一种方案&#xff0c;将节点划分成满足以上性质的两个集合。 性质 如果两个集合中的点分别染成黑色和白色&am…

C语言之 结构体,枚举,联合

目录 1.结构体 1.1结构的基础知识 1.2结构的声明 1.3 特殊的声明 1.4 结构的自引用 1.5 结构体变量的定义和初始化 1.6 结构体内存对齐 1.7 修改默认对齐数 1.8 结构体传参 2. 位段 2.1 什么是位段 2.2位段的内存分配 2.3 位段的跨平台问题 3. 枚举 3.1 枚举类型…

Mybatis简介(二)

1、多表映射 简介一 链接 对于数据库的操作&#xff0c;很多时候我们都是在多表的基础上进行操作的&#xff0c;在这里讲一下多表属性值与列名映射。 案例&#xff1a;这里有一个订单表和一个客户表 CREATE TABLE t_customer (customer_id INT NOT NULL AUTO_INCREMENT, cus…

在 Elasticsearch 中丰富你的 Elasticsearch 文档

作者&#xff1a;David Pilato 对于 Elasticsearch&#xff0c;我们知道联接应该在 “索引时” 而不是查询时完成。 本博文是一系列三篇博文的开始&#xff0c;因为我们可以在 Elastic 生态系统中采取多种方法。 我们将介绍如何在 Elasticsearch 中做到这一点。 下一篇博文将介…

node实战——后端koa结合jwt连接mysql实现权限登录(node后端就业储备知识)

文章目录 ⭐前言⭐ 环境准备⭐ 实现过程⭐ mysql 配置⭐路由前的准备⭐账号注册生成token⭐账号登录生成token⭐token登录 ⭐ 自测过程截图⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于node实战——后端koa项目配置jwt实现登录注册&#xff08;n…

1230. K倍区间(前缀和)

题目&#xff1a; 1230. K倍区间 - AcWing题库 突破口&#xff1a; 区间遍历枚举一般先枚举右端点&#xff0c;再枚举左端点&#xff0c;注意由右端点限制左端点 思路&#xff1a;1.暴力 #include<cstdio> #include<iostream> #include<algorithm> #incl…

Win 7 VPN拨号错误734.

正在验证用户名和密码错误 734: PPP 链接控制协议终止。 如果您继续收到错误信息&#xff0c;您可以启用日志记录来做分析。 其他电脑拨号都成功.就这个电脑不行.找了很久,修改之后报好成功 ************************** 找到是跟下面两个两个注册表信息有关,尤其是第一个我…

基于Pytest+Requests+Allure实现接口自动化测试!

一、整体结构 框架组成&#xff1a;pytestrequestsallure设计模式&#xff1a; 关键字驱动项目结构&#xff1a; 工具层&#xff1a;api_keyword/参数层&#xff1a;params/用例层&#xff1a;case/数据驱动&#xff1a;data_driver/数据层&#xff1a;data/逻辑层&#xff1a…

75 寻找旋转排序数组中的最小值

寻找旋转排序数组中的最小值 题解1 一次循环(正确理解题意)题解2 二分 已知一个长度为 n 的数组&#xff0c;预先按照 升序排列&#xff0c;经由 1 到 n 次 旋转 后&#xff0c;得到输入数组。例如&#xff0c;原数组 nums [0,1,2,4,5,6,7] 在变化后可能得到&#xff1a; …

刚刚:2023阿里云双十一优惠活动上线了!

2023阿里云双十一优惠活动「金秋云创季」开始啦&#xff0c;10月27日到10月31日可以领满减优惠&#xff0c;到11月1日和11月11日之间可以购买云服务器等产品&#xff0c;11.12到11.30日赢最高百万上云抵扣金&#xff0c;阿里云百科aliyunbaike.com分享2023阿里云双十一优惠活动…

Xray的简单使用

xray 简介 xray 是一款功能强大的安全评估工具&#xff0c;由多名经验丰富的一线安全从业者呕心打造而成&#xff0c;主要特性有: 检测速度快。发包速度快; 漏洞检测算法效率高。支持范围广。大至 OWASP Top 10 通用漏洞检测&#xff0c;小至各种 CMS 框架 POC&#xff0c;均…

前端实现打印功能Print.js

前端实现打印的方式有很多种&#xff0c;本人恰好经历了几个项目都涉及到了前端打印&#xff0c;目前较为推荐Print.js来实现前端打印 话不多说&#xff0c;直接上教程 官方链接: Print.js官网 在项目中如何下载Print.js 使用npm下载&#xff1a;npm install print-js --sav…

python 从mssql取出datetime2类型之后格式化

我mssql是datetime2类型&#xff0c;用df取出之后发现是个纳秒的int&#xff08;1698419713000000000 这种&#xff09; 所以格式化的话就需要变成秒为单位&#xff0c;他们之间是10的9次方倍。所以先除以1e9之后用datetime.datetime.fromtimestamp()转换之后再format就行了 l…

CCF CSP认证历年题目自练 Day39

题目 试题编号&#xff1a; 201312-5 试题名称&#xff1a; I’m stuck! 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   给定一个R行C列的地图&#xff0c;地图的每一个方格可能是’#‘, ‘’, ‘-’, ‘|’, ‘.’, ‘S’, ‘…

系列十九、循环依赖(一)

一、概述 循环依赖是指&#xff0c;多个bean之间相互依赖&#xff0c;形成了一个闭环。比如A依赖于B、B依赖于C、C依赖于A&#xff0c;形成了一个圈。 二、两种方式对循环依赖的影响 2.1、官网说明 2.2、结论 我们AB循环依赖问题只要A的注入方式是setter、并且是singleton&am…

Android14 WMS启动流程

一 概述 本文Android14源代码可参考&#xff1a;Search 在 Android 系统中&#xff0c;从设计的角度来看&#xff0c;窗口管理系统是基于 C/S 模式的。整个窗口系统分为服务端和客户端两大部分&#xff0c;客户端负责请求创建窗口和使用窗口&#xff0c;服务端完成窗口的维护…

智慧工地管理系统源码-数字孪生智慧工地可视化解决方案

一、智慧工地建设背景 我国经济发展正从传统粗放式的高速增长阶段&#xff0c;进入高效率、低成本、可持续的中高速增长阶段。随着现代建筑的复杂度和体量等不断增加&#xff0c;施工现场管理的内容越来越多&#xff0c;管理的技术难度和要求在不断提高。传统的施工现场管理模…

用超声波清洗机洗眼镜的有哪些?清洁力强的超声波清洗机不能错过

超声波清洗机在清洗眼镜方面表现出色&#xff0c;其强大的清洁能力可以彻底清除眼镜上的污垢和细菌。这种清洗方式被认为是一种高效且卫生的清洁方式&#xff0c;因为它利用高频振动和微射流打击力来清除污垢和细菌&#xff0c;而不是使用化学物质。对于那些长时间佩戴眼镜或者…

windows + ubuntu + vscode开发环境配置安装

一、卸载WSL/WSL2 如果安装了windows子系统的朋友&#xff0c;可以选择继续使用。或者提前卸载WSL&#xff0c;再选择安装虚拟机。虚拟机占用内存较大&#xff0c;WSL可能对于开发的一些需求还有欠缺。根据自己的实际情况进行选择。 WIN10/11安装WSL(请参考官方资料&#xff0c…