【数据结构与算法】:手搓顺序表(Python篇)

文章目录

      • 一、顺序表的概念
      • 二、顺序表的实现
        • 1. 顺序表的创建
          • 1.1 扩容
          • 1.2 整体建立顺序表
        • 2. 顺序表的基本运算算法
          • 2.1 顺序表的添加(尾插)
          • 2.2 指定位置插入
          • 2.3 指定位置删除
          • 2.4 顺序表的查找
          • 2.5 顺序表元素的索引访问
          • 2.6 顺序表元素的修改
          • 2.7 顺序表长度
          • 2.8 顺序表的输出
      • 三、完整代码
      • 四、代码验证

一、顺序表的概念

顺序表是一种线性的数据结构,其中数据元素按照特定的顺序依次存储在连续的内存空间中。它由一系列元素组成,每个元素都与唯一的索引(或者叫下标)相关联,索引从 0 开始递增。
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
下面这张图中,最下面那行数字0~9代表的是元素的索引,天蓝色的柱子中的数字代表的是顺序表中的元素,顺序表中的元素必须是同一数据类型的,数据类型可以是整数、浮点数、字符串等等。
在这里插入图片描述

二、顺序表的实现

设计顺序表类为SqList,主要包含存放元素的data列表和表示实际元素个数的size属性。因为Python属于弱类型语言,没必要专门设计像C++或则Java中的泛型类,在应用SqList时可以指定其元素为任意合法数据类型。

创建顺序表类

# 顺序表类
class SqList:
    # 初始化
    def __init__(self):
        self.initcapacity = 5  # 初始容量设置为5
        self.capacity = self.initcapacity  # 容量设置为初始容量
        self.data = [None] * self.capacity  # 设置顺序表的空间
        self.size = 0  # 长度设为0
1. 顺序表的创建
1.1 扩容

顺序表在实现各种基本运算如插入和删除时会涉及到容量的更新,所以要设计一个方法将data列表的容量改变为newcapacity。

# 扩容
def resize(self, newcapacity):  # 改变顺序表的容量为newcapacity
    assert newcapacity >= 0
    oldata = self.data
    self.data = [None] * newcapacity
    self.capacity = newcapacity
    for i in range(self.size):
        self.data[i] = oldata[i]

这里就是先让olddata指向data,为data重新分配一个容量为newcapacity的空间,再将olddata中的所有元素复制到data中,复制中所有的元素的序号和长度size不变。原data空间会被系统自动释放掉。

1.2 整体建立顺序表

该方法就是从空顺序表开始,由含若干个元素的列表a的全部元素整体创建顺序表,即依次将a中的元素添加到data列表的末尾,当出现上溢出时按实际元素个数size的两倍扩大容量。

# 整体创建顺序表
def CreateList(self, a):  # 有数组a中的元素整体建立顺序表
    for i in range(0, len(a)):
        if self.size == self.capacity:  # 出现上溢出时
            self.resize(2 * self.size)  # 扩容
        self.data[self.size] = a[i]
        self.size += 1  # 添加后元素增加1

时间复杂度为O(n), n表示顺序表中的元素个数。

2. 顺序表的基本运算算法
2.1 顺序表的添加(尾插)

将元素e添加到顺序表的末尾:Add(e)
在data列表的尾部插入元素e,在插入中出现上溢出时按实际元素个数size的两倍扩大容量。

# 顺序表的添加(尾插)
def Add(self, e):  # 在线性表的末尾添加一个元素
    if self.size == self.capacity:
        self.resize(2 * self.size)  # 顺序表空间满时倍增容量
    self.data[self.size] = e  # 添加元素e
    self.size += 1  # 长度加1

该算法中调用一次resize()方法的时间复杂度为O(n),但n次Add操作仅需要扩大一次data空间,所以平均时间复杂度仍然为O(1)。

2.2 指定位置插入

在顺序表中插入e作为第i个元素:Insert(i,e)
在顺序表中序号i的位置上插入一个新元素e。若参数i合法(0<= i <= n),先将data[i…n-1]的每个元素均后移一个位置(从data[n - 1]元素开始移动),腾出一个空位置data[i]插入新元素e,最后将长度size增1。在插入元素时若出现上溢出,则按两倍size扩大容量。
在这里插入图片描述

# 指定位置插入
def Insert(self, i, e):  # 在线性表中序号为i的位置插入元素
    assert 0 <= i <= self.size
    if self.size == self.capacity:  # 满时扩容
        self.resize(2 * self.size)
    for j in range(self.size, i - 1, -1):  # 疆data[i]及后面的元素后移一位
        self.data[j] = self.data[j - 1]
    self.data[i] = e  # 插入元素e
    self.size += 1  # 长度加1

该算法的时间主要花在元素的移动上,元素移动的次数不仅与表长n有关,而且与插入位置i有关。有效插入位置i的取值是0~n,共有n + 1个位置可以插入元素:

  1. 当i = 0时,移动次数为n,达到最大值。
  2. 当i = n时,移动次数为0,达到最小值。
  3. 其他情况,需要移动data[i…n - 1]的元素,移动次数为(n - 1)- i + 1 = n - i。

时间复杂度为O(n)。

2.3 指定位置删除

顺序表中删除第i个数据元素:Delete(i)
该算法删除顺序表中序号i的元素。若参数i合法(0<= i < n),删除操作是将data[i + 1 … n - 1]的元素均向前移动一个位置(从data[i + 1]元素开始移动),这样覆盖了元素data[i],从而达到删除该元素的目的,最后将顺序表的长度减一。若当前容量大于初始容量并且实际长度仅为当前容量的1/4(缩容条件),则将当前容量减半。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

def Delete(self, i):  # 在线性表中删除序号为i的元素
    assert 0 <= i <= self.size - 1
    for j in range(i, self.size - 1):
        self.data[j] = self.data[j + 1]  # 将data[j]之后的元素前移一位
    self.size -= 1  # 长度减一
    if self.capacity > self.initcapacity and self.size <= self.capacity / 4:
        self.resize(self.capacity // 2)  # 满足要求容量减半

该算法的时间主要花在元素的移动上,元素移动的次数不仅与表长n有关,而且与删除位置i有关。有效删除位置i的取值是0~n - 1,共有n个位置可以插入元素:

  1. 当i = 0时,移动次数为n - 1,达到最大值。
  2. 当i = n - 1时,移动次数为0,达到最小值。
  3. 其他情况,需要移动data[i +1 … n - 1]的元素,移动次数为(n - 1)- (i + 1)+ 1 = n - i - 1。

时间复杂度为O(n)。

2.4 顺序表的查找

求顺序表中第一个值为e的元素的序号:GetNo(e)
在data列表中从前向后顺序查找第一个值与e相等的元素的序号,若不存在这样的元素,则返回-1。
在这里插入图片描述

def GetNo(self, e):  # 查找第一个为e的元素的下标
    i = 0
    while i < self.size and self.data[i] != e:  # 查找元素e
        i += 1
    if i >= self.size:
        return -1
    else:
        return i

该算法的时间复杂度为O(n),其中n表示顺序表中的元素个数。

2.5 顺序表元素的索引访问

求顺序表中序号i的元素值:GetElem(i)
当序号i合法时(0<= i < size)返回data[i]。
在这里插入图片描述

def __getitem__(self, i):  # 求序号为i的元素
    assert 0 <= i < self.size
    return self.data[i]

对于顺序表对象L,可以通过L[i]调用上述运算获取序号i的元素值。时间复杂度为O(1)。

2.6 顺序表元素的修改

设置顺序表中序号i的元素值:SetElem(i,e)
在这里插入图片描述

def __setitem__(self, i, value):  # 设置序号为i的元素
    assert 0 <= i < self.size
    self.data[i] = value

对于顺序表对象L,可以通过L[i] = e调用上述运算将序号i的元素值设置为e。该算法的时间复杂度为O(1)

2.7 顺序表长度

求顺序表的长度:getsize()
返回顺序表的长度(实际元素个数size)。

def getsize(self):  # 返回长度
    return self.size

时间复杂度为O(1)

2.8 顺序表的输出

输出顺序表的所有元素:display()
依次输出顺序表中的所有元素值。

def display(self):  # 输出顺序表
    for i in range(0, self.size):
        print(self.data[i], end=' ')
    print()  # 换行

时间复杂度为O(n),n表示顺序表中的元素个数。

三、完整代码

# 顺序表类
class SqList:
    # 初始化
    def __init__(self):
        self.initcapacity = 5  # 初始容量设置为5
        self.capacity = self.initcapacity  # 容量设置为初始容量
        self.data = [None] * self.capacity  # 设置顺序表的空间
        self.size = 0  # 长度设为0

    # 扩容
    def resize(self, newcapacity):  # 改变顺序表的容量为newcapacity
        assert newcapacity >= 0
        oldata = self.data
        self.data = [None] * newcapacity
        self.capacity = newcapacity
        for i in range(self.size):
            self.data[i] = oldata[i]

    # 整体创建顺序表
    def CreateList(self, a):  # 有数组a中的元素整体建立顺序表
        for i in range(0, len(a)):
            if self.size == self.capacity:  # 出现上溢出时
                self.resize(2 * self.size)  # 扩容
            self.data[self.size] = a[i]
            self.size += 1  # 添加后元素增加1

    def Add(self, e):  # 在线性表的末尾添加一个元素
        if self.size == self.capacity:
            self.resize(2 * self.size)  # 顺序表空间满时倍增容量
        self.data[self.size] = e  # 添加元素e
        self.size += 1  # 长度加1

    def getsize(self):  # 返回长度
        return self.size

    def __getitem__(self, i):  # 求序号为i的元素
        assert 0 <= i < self.size
        return self.data[i]

    def __setitem__(self, i, value):  # 设置序号为i的元素
        assert 0 <= i < self.size
        self.data[i] = value

    def GetNo(self, e):  # 查找第一个为e的元素的下标
        i = 0
        while i < self.size and self.data[i] != e:  # 查找元素e
            i += 1
        if i >= self.size:
            return -1
        else:
            return i

    # 指定位置插入
    def Insert(self, i, e):  # 在线性表中序号为i的位置插入元素
        assert 0 <= i <= self.size
        if self.size == self.capacity:  # 满时扩容
            self.resize(2 * self.size)
        for j in range(self.size, i - 1, -1):  # 疆data[i]及后面的元素后移一位
            self.data[j] = self.data[j - 1]
        self.data[i] = e  # 插入元素e
        self.size += 1  # 长度加1

    def Delete(self, i):  # 在线性表中删除序号为i的元素
        assert 0 <= i <= self.size - 1
        for j in range(i, self.size - 1):
            self.data[j] = self.data[j + 1]  # 将data[j]之后的元素前移一位
        self.size -= 1  # 长度减一
        if self.capacity > self.initcapacity and self.size <= self.capacity / 4:
            self.resize(self.capacity // 2)  # 满足要求容量减半

    def display(self):  # 输出顺序表
        for i in range(0, self.size):
            print(self.data[i], end=' ')
        print()  # 换行

四、代码验证

if __name__ == '__main__':
    L = SqList()  # 实例化
    print('建立空顺序表L, 其容量为 %d' % (L.capacity))
    a = [1, 2, 3, 4, 5]
    print('1~6创建L')
    L.CreateList(a)
    print('L[容量 = %d, 长度 = %d]:' % (L.capacity, L.getsize()), end=' '), L.display()
    print('插入6~10')
    for i in range(6, 11):
        L.Add(i)
    print('L[容量 = %d, 长度 = %d]:' % (L.capacity, L.getsize()), end=' '), L.display()
    print('序号为2的元素 = %d' % (L[2]))
    print('设置序号为2的元素为20')
    L[2] = 20
    print('L[容量 = %d, 长度 = %d]:' % (L.capacity, L.getsize()), end=' '), L.display()
    x = 6
    print('第一个值为%d的元素序号 = %d' % (x, L.GetNo(x)))
    n = L.getsize()
    for i in range(n - 2):
        print('删除首元素')
        L.Delete(0)
        print('L[容量 = %d, 长度 = %d]:' % (L.capacity, L.getsize()), end=' '), L.display()

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mouse without Borders(无界鼠标)使用教程 多台电脑(最多4)共用鼠标键盘,换言之一套键鼠操作多台电脑,跨电脑文件拖动传输

Mouse without Borders&#xff08;无界鼠标&#xff09;使用教程 目的&#xff1a;多台电脑&#xff08;最多4&#xff09;共用鼠标键盘&#xff0c;换言之一套键鼠操作多台电脑。 优势&#xff1a;微软官方软件&#xff0c;对于windows系统友好&#xff0c;轻量实用。 劣势…

【Diffusion实战】训练一个diffusion模型生成蝴蝶图像(Pytorch代码详解)

上一篇Diffusion实战是确确实实一步一步走的公式&#xff0c;这回采用一个更方便的库&#xff1a;diffusers&#xff0c;来实现Diffusion模型训练。 Diffusion实战篇&#xff1a;   【Diffusion实战】训练一个diffusion模型生成S曲线&#xff08;Pytorch代码详解&#xff09;…

锁,数据同步

目录 原子操作中断控制自旋锁信号量小结 经常遇到数据同步的问题&#xff0c;具体有哪些情况呢&#xff1f;来聊一聊。我知道的&#xff0c;应该有以下四种&#xff0c;原子操作&#xff0c;中断控制&#xff0c;自旋锁和信号量。 原子操作 适用情况和场景 原子操作经常用在单…

vue实现录音并转文字功能,包括PC端web,手机端web

vue实现录音并转文字功能&#xff0c;包括PC端&#xff0c;手机端和企业微信自建应用端 不止vue&#xff0c;不限技术栈&#xff0c;vue2、vue3、react、.net以及原生js均可实现。 原理 浏览器实现录音并转文字最快捷的方法是通过Web Speech API来实现&#xff0c;这是浏览器…

【Linux系统编程】第八弹---权限管理操作(中)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、修改文件权限的做法(二) 2、文件类型 3、可执行权限 4、创建文件/目录的默认权限 4.1、权限掩码 总结 前面一弹我们学…

CH4INRULZ-v1靶机练习实践报告

CH4INRULZ-v1靶机练习实践报告 1 安装靶机 靶机是.ova文件&#xff0c;需要用VirtualBox打开&#xff0c;但我习惯于使用VMWare,因此修改靶机文件&#xff0c;使其适用于VMWare打开。 解压ova文件&#xff0c;得到.ovf文件和.vmdk文件。直接用VMWare打开.ovf文件即可。 2 夺…

社区新零售:重构邻里生活圈,赋能美好未来

新时代的邻里脉动 在城市的肌理中&#xff0c;社区作为生活的基本单元&#xff0c;正经历一场由新零售引领的深刻变革。社区新零售&#xff0c;以其独特的商业模式、创新的技术手段和以人为本的服务理念&#xff0c;重新定义了社区商业的边界&#xff0c;重构了邻里生活的形态…

[C++ QT项目实战]----C++ QT系统实现多线程通信

前言 在C QT中&#xff0c;多线程通信原理主要涉及到信号与槽机制和事件循环机制。 1、信号与槽机制&#xff1a; 在QT中&#xff0c;信号与槽是一种用于对象间通信的机制。对象可以通过发送信号来通知其他对象&#xff0c;其他对象通过连接槽来接收信号并进行相应的处…

软件物料清单(SBOM)生成指南 .pdf

如今软件安全攻击技术手段不断升级&#xff0c;攻击数量显著增长。尤其是针对软件供应链的安全攻击&#xff0c;具有高隐秘性、追溯难的特点&#xff0c;对企业软件安全威胁极大。 同时&#xff0c;软件本身也在不断地更新迭代&#xff0c;软件内部成分安全性在持续变化浮动。…

web题目实操 5(备份文件和关于MD5($pass,true)注入的学习)

1.[ACTF2020 新生赛]BackupFile &#xff08;1&#xff09;打开页面后根据提示是备份文件 &#xff08;2&#xff09;查看源码发现啥都没有 &#xff08;3&#xff09;这里啊直接用工具扫描&#xff0c;可以扫描到一个文件名为&#xff1a;/index.php.bak的文件 &#xff08;…

json解析大全

JSON解析案例1 将String转为JSONObject JSONObject res JSONObject.parseObject(result);获取documents JSONArray array res.getJSONObject("result").getJSONArray("documents");遍历JSONArray for (int i 0; i < array.size(); i) {JSONObject…

IDEA pom.xml依赖警告

IDEA中&#xff0c;有时 pom.xml 中会出现如下提示&#xff1a; IDEA 2022.1 升级了检测易受攻击的 Maven 和 Gradle 依赖项&#xff0c;并建议修正&#xff0c;通过插件 Package Checker 捆绑到 IDE 中。 这并不是引用错误&#xff0c;不用担心。如果实在强迫症不想看到这个提…

稳态视觉诱发电位 (SSVEP) 分类学习系列 (4) :Temporal-Spatial Transformer

稳态视觉诱发电位分类学习系列:Temporal-Spatial Transformer 0. 引言1. 主要贡献2. 提出的方法2.1 解码的主要步骤2.2 网络的主要结构 3. 结果和讨论3.1 在两个数据集下的分类效果3.2 与基线模型的比较3.3 消融实验3.4 t-SNE 可视化 4. 总结欢迎来稿 论文地址&#xff1a;http…

Hive——DDL(Data Definition Language)数据定义语句用法详解

1.数据库操作 1.1创建数据库 CREATE DATABASE [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_nameproperty_value, ...)];IF NOT EXISTS&#xff1a;可选参数&#xff0c;表示如果数据库已经存在&#xff0c…

软考-系统分析师-精要2

5、可行性分类 经济可行性&#xff1a;成本收益分析&#xff0c;包括建设成本、运行成本和项目建设后可能的经济收益。 技术可行性&#xff1a;技术风险分析&#xff0c;现有的技术能否支持系统目标的实现&#xff0c;现有资源&#xff08;员工&#xff0c;技术积累&#xff0…

GEM TSU Interface Details and IEEE 1588 Support

摘要&#xff1a;Xilinx ZNYQ ULTRASCALE MPSOC的GEM和1588的使用 对于FPGA来说&#xff0c;只需要勾选一些znyq的配置就行了&#xff0c;其余的都是软件的工作&#xff1b; 所有配置都勾选之后&#xff0c;最终会露出来的接口如下&#xff1a; GEM需要勾选的配置如下&#xf…

泰坦尼克号乘客生存情况预测分析2

泰坦尼克号乘客生存情况预测分析1 泰坦尼克号乘客生存情况预测分析2 泰坦尼克号乘客生存情况预测分析3 泰坦尼克号乘客生存情况预测分析总 背景描述 Titanic数据集在数据分析领域是十分经典的数据集&#xff0c;非常适合刚入门的小伙伴进行学习&#xff01; 泰坦尼克号轮船的…

AI新闻速递:揭秘本周科技界最热的AI创新与发展

兄弟朋友们&#xff0c;本周的AI领域又迎来了一系列激动人心的进展。在这个快速变化的时代&#xff0c;不会利用AI的人&#xff0c;就像在数字化高速公路上步行的旅行者&#xff0c;眼看着同行者驾驶着智能汽车绝尘而去&#xff0c;而自己却束手无策。 1. Adobe Firefly 3&…

【基础算法总结】双指针算法二

双指针 1.有效三角形的个数2.和为S的两个数字3.和为S的两个数字4.四数之和 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.有效三角形的个数…

深度学习运算:CUDA 编程简介

一、说明 如今&#xff0c;当我们谈论深度学习时&#xff0c;通常会将其实现与利用 GPU 来提高性能联系起来。GPU&#xff08;图形处理单元&#xff09;最初设计用于加速图像、2D 和 3D 图形的渲染。然而&#xff0c;由于它们能够执行许多并行操作&#xff0c;因此它们的实用性…