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

news2024/12/24 9:01:37

文章目录

      • 一、顺序表的概念
      • 二、顺序表的实现
        • 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()

在这里插入图片描述

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

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

相关文章

Java毕业设计 基于SpringBoot vue城镇保障性住房管理系统

Java毕业设计 基于SpringBoot vue城镇保障性住房管理系统 SpringBoot 城镇保障性住房管理系统 功能介绍 首页 图片轮播 房源信息 房源详情 申请房源 公示信息 公示详情 登录注册 个人中心 留言反馈 后台管理 登录 个人中心 修改密码 个人信息 用户管理 房屋类型 房源信息管理…

微信小程序:5.数据绑定

在Data中定义数据早wxml中进行数据使用 在data中定义数据 在页面对应的js对象中找到data&#xff0c;然后把数据进行定义即可 Page({data: {motto: Hello World,userInfo: {avatarUrl: defaultAvatarUrl,nickName: ,},hasUserInfo: false,canIUseGetUserProfile: wx.canIUse…

药房管理 T1072

#include<bits/stdc.h> using namespace std; int main(){int m,n;cin>>m>>n;int f[n];for(int i0;i<n;i)cin>>f[i];int count0;for(int i0;i<n;i){if(m>f[i]){mm-f[i];}else {count;}}cout<<count;return 0;}

【Redis 开发】缓存雪崩和缓存击穿

缓存问题 缓存雪崩解决方案 缓存击穿互斥锁逻辑时间基于互斥锁解决缓存击穿问题基于逻辑过期方式解决缓存击穿问题 缓存雪崩 缓存雪崩是指在同一时间段&#xff0c;大量的缓存key同时失效或者Redis服务器宕机&#xff0c;导致大量请求到达数据库&#xff0c;带来巨大压力 解决…

node.js egg.js

Egg 是 Node.js 社区广泛使用的框架&#xff0c;简洁且扩展性强&#xff0c;按照固定约定进行开发&#xff0c;低协作成本。 在Egg.js框架中&#xff0c;ctx 是一个非常核心且常用的对象&#xff0c;全称为 Context&#xff0c;它代表了当前 HTTP 请求的上下文。ctx 对象封装了…

【JavaEE网络】 TCP的可靠传输机制总结

目录 可靠传输实现机制确认应答超时重传连接管理滑动窗口流量控制拥塞控制延迟应答捎带应答 可靠传输实现机制 确认应答 这是保证可靠性的最核心机制 TCP将每个字节的数据都进行了编号。即为序列号。 这是为了防止连续发多条数据的时候&#xff0c;可能出现“后发先至”的情…

c++图论基础(2)

目录 图的存储方式&#xff1a; 邻接矩阵&#xff1a; 代码实现&#xff1a; 邻接表&#xff1a; 代码实现&#xff1a; 邻接矩阵邻接表对比&#xff1a; 带权图&#xff1a; 邻接矩阵存储&#xff1a; 邻接表存储(代码实现)&#xff1a; 图的存储方式&#xff1a; 邻…

ShardingSphere 5.x 系列【26】 数据分片原理之 SQL 路由

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 概述2. 携带分片键2.1 直接路由2.2 标准路由2.3 笛卡尔路由3. 不携带分片…

CH4INRULZ-v1靶机练习实践报告

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

k8s学习(三十六)centos下离线部署kubernetes1.30(单主节点)

文章目录 服务器准备工作一、升级操作系统内核1 查看操作系统和内核版本2 下载内核离线升级包3 升级内核4 确认内核版本 二、修改主机名/hosts文件1 修改主机名2 修改hosts文件 三、关闭防火墙四、关闭SELINUX配置五、时间同步1 下载NTP2 卸载3 安装4 配置4.1 主节点配置4.2 从…

Java设计模式 _结构型模式_适配器模式

一、适配器模式 **1、适配器模式&#xff08;Adapter Pattern&#xff09;**是一种结构型设计模式。适配器类用来作为两个不兼容的接口之间的桥梁&#xff0c;使得原本不兼容而不能一起工作的那些类可以一起工作。譬如&#xff1a;读卡器就是内存卡和笔记本之间的适配器。您将…

JAVA:maven-->>检查 所有依赖 与 环境 兼容

内容 为了确保你项目中的所有依赖都彼此兼容&#xff0c;并与你的环境相适应&#xff0c;你可以利用 Maven 的依赖管理功能。Maven 有助于解决、升级&#xff0c;并对齐所有库的版本&#xff0c;以避免任何不一致或冲突。以下是检查兼容性的步骤&#xff1a; ### 检查兼容性的…

sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

使用JavaScript日历小部件和DHTMLX Gantt的应用场景(一)

DHTMLX Suite UI 组件库允许您更快地构建跨平台、跨浏览器 Web 和移动应用程序。它包括一组丰富的即用式 HTML5 组件&#xff0c;这些组件可以轻松组合到单个应用程序界面中。 DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足项目管理应用…

DB索引B+树SQL优化

数据库的索引就像一本书的目录&#xff0c;查数据快人一步&#xff0c;快速定位&#xff0c;精准打击&#xff01; 什么是数据库的索引&#xff1f; 官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说&#xff0c;数据库索引好比是一本书前面的目录&#xff0c;能加…

实现瓦片地图摄像机追随以及玩家粘在地图上

目前是出现BUG但是摄像机可以加速减速追赶&#xff0c;并且玩家用了绝对游戏坐标&#xff0c;可以减去采样区绝对游戏坐标&#xff0c;得到参考于整个游戏地图里在采样区的位置坐标 相机追踪&#xff0c;有三个函数 bklocalplayer 是玩家在采样区里不出界&#xff0c;相机慢…

Docker深入探索:网络与资源控制、数据管理与容器互联以及镜像生成

目录 一、 Docker网络 &#xff08;一&#xff09;Docker网络实现原理 &#xff08;二&#xff09;Docker网络模式 1. Bridge网络&#xff08;默认&#xff09; 2. Host网络 3. None网络 4. Container网络 5. 自定义网络 二、资源控制 &#xff08;一&#xff09;cgr…

嵌入式开发一:初识Stm32

目录 一、嵌入式简介 1.1 嵌入式概念 1.2 嵌入式系统的组成 1.3 嵌入式的分类 1.3.1 嵌入式系统的分类 1.3.2 嵌入式处理器的分类 二、单片机简介(MCU嵌入式微控制器) 2.1 单片机是什么 2.2 单片机的作用是什么 2.3 单片机的发展历程 2.4 单片机发展趋势 2.5 复杂指…

Web APIs 学习归纳3---元素操作的补充

上一节也学习了一些有关元素操作的内容&#xff0c;主要集中在样式、属性、内容的修改。 一、元素操作的经典案例和思想 1.1 排他思想&#xff08;排除他人、保留自己&#xff09; 这个内容很重要&#xff0c;一般情况下如果有同一组元素&#xff0c;我们想要某一个元素实现某…

spring常用注解(五)lombok库

一、介绍&#xff1a; 1、简介&#xff1a; Lombok是一个作用于编辑器和构建工具的 Java 库&#xff0c;可以对编写的 Java 代码进行增强&#xff0c;比如说不用再写实体类的 getter 方法&#xff0c;equals 方法而是自动生成&#xff0c;自动生成日志输出变量等等&#xff0…