侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Python如何实现动态数组

Python  /  管理员 发布于 7年前   369

Python序列类型

在本博客中,我们将学习探讨Python的各种“序列”类,内置的三大常用数据结构――列表类(list)、元组类(tuple)和字符串类(str)。

不知道你发现没有,这些类都有一个很明显的共性,都可以用来保存多个数据元素,最主要的功能是:每个类都支持下标(索引)访问该序列的元素,比如使用语法 Seq[i]。其实上面每个类都是使用 数组 这种简单的数据结构表示。

但是熟悉Python的读者可能知道这3种数据结构又有一些不同:比如元组和字符串是不能修改的,列表可以修改。

计算机内存中的数组结构

计算机体系结构中,我们知道计算机主存由位信息组成,这些位通常被归类成更大的单元,这些单元则取决于精准的系统架构。一个典型的单元就是一个字节,相当于8位。

计算机系统拥有庞大数量的存储字节,那么如何才能找到我们的信息存在哪个字节呢?答案就是大家平时熟知的 存储地址 。基于存储地址,主存中的任何字节都能被有效的访问。实际上,每个存储字节都和一个作为其地址的唯一二进制数字相关联。如下图中,每个字节均被指定了存储地址:

一般来说,编程语言记录标识符和其关联值所存储的地址之间的关系。比如,当我们声明标识符 xx 就有可能和存储器中的某一值相关联,而标识符 yy就可能和其他的值相关联。一组相关的变量能够一个接一个地存储在计算机存储器的一块连续区域内。我们将这种方式称为 数组。

我们来看Python中的例子,一个文本字符串 HELLO 是以一列有序字符的形式存储的,假定该字符串的每个Unicode字符需要两个字节的存储空间。最下面的数字就是该字符串的索引值。

我们可以看到,数组可以存储多个值而无需构造具有特定索引的多个变量来指定其中的每个项目,并且几乎在所有编程语言(例如C、Java、C#、C++)中使用,但是Python更具有优势。Python在构建列表时,熟悉的读者可能知道,不需要预先定义数组或列表的大小,相反,在Python中,列表具有动态性质,我们可以不断的往列表中添加我们想要的数据元素。接下来,让我们看看Python列表的知识(已经熟悉的读者可以快速浏览或者跳过)。

Python列表

Python列表的操作

创建列表的语法格式:

[ele1, ele2, ele3, ele4, ...]

创建元组的语法格式:

(ele1, ele2, ele3, ele4, ...)

元组比列表的内存空间利用率更高,因为元组是固定不变的,所以没有必要创建拥有剩余空间的动态数组。

我们先在Python的IDE中创建一个列表,然后大致了解一下列表部分内置操作,我们先创建了一个名为test_list的列表,然后修改(插入或删除)元素,反转或清空列表,具体如下:

>>> test_list = [] # 创建名为test_list的空列表>>> test_list.append("Hello")>>> test_list.append("World")>>> test_list['Hello', 'World']>>> test_list = ["Hello", "Array", 2019, "easy learning", "DataStructure"] # 重新给test_list赋值>>> len(test_list) # 求列表的长度5>>> test_list[2] = 1024 # 修改列表元素>>> test_list['Hello', 'Array', 1024, 'easy learning', 'DataStructure']>>>>>> test_list.insert(1, "I love")  # 向列表中指定位置中插入一个元素>>> test_list['Hello', 'I love', 'Array', 1024, 'easy learning', 'DataStructure']>>> test_list.append(2020) # 向列表末尾增加一个元素>>> test_list['Hello', 'I love', 'Array', 1024, 'easy learning', 'DataStructure', 2020]>>>>>> test_list.pop(1)  # 删除指定位置的元素'I love'>>> test_list.remove(2020) # 删除指定元素>>> >>> test_list.index('Hello')  # 查找某个元素的索引值0>>> test_list.index('hello')  # 如果查找某个元素不在列表中,返回ValueError错误Traceback (most recent call last): File "<pyshell#11>", line 1, in <module>  test_list.index('hello')ValueError: 'hello' is not in list>>> >>> test_list.reverse() # 反转整个列表>>> test_list['DataStructure', 'easy learning', 2019, 'Array', 'Hello']>>> test_list.clear()  # 清空列表>>> test_list[]

我们看上面的代码,可以看到list的相关操作――增删改查,已经很强大了,还有一些内置方法这里并没有做展示,留给读者自己去发现并体验。

那么Python内置的list类是如何被实现的呢?

好吧,答案是动态数组。说到这里,不知道大家学Python列表的时候是不是这样想的――列表很简单嘛,就是list()类、用中括号[]括起来,然后指导书籍或文档上的各类方法append、insert、pop...在IDE或者Pycharm一顿操作过后,是的我学会了。

但其实真的很不简单,比如我举个例子:A[-1]这个操作怎么实现?列表切片功能怎么实现?如何自己写pop()默认删除列表最右边的元素(popleft删除最左边简单)?...这些功能用起来爽,但真的自己实现太难了(我也还在学习中,大佬们请轻喷!)如果我们能学习并理解,肯定可以加强我们对数组这一结构的理解。

动态数组

什么是动态数组

动态数组是内存的连续区域,其大小随着插入新数据而动态增长。在静态数组中,我们需要在分配时指定大小。在定义数组的时候,其实计算机已经帮我们分配好了内存来存储,实际上我们不能扩展数组,因为它的大小是固定的。比如:我们分配一个大小为10的数组,则不能插入超过10个项目。

但是动态数组会在需要的时候自动调整其大小。这一点有点像我们使用的Python列表,可以存储任意数量的项目,而无需在分配时指定大小。

所以实现一个动态数组的实现的关键是――如何扩展数组?当列表list1的大小已满时,而此时有新的元素要添加进列表,我们会执行一下步骤来克服其大小限制的缺点:

  • 分配具有更大容量的新数组 list2
  • 设置 list2[i] = list1[i] (i=0,1,2,...,n-1),其中n是该项目的当前编号
  • 设置list1 = list2,也就是说,list2正在作为新的数组来引用我们的新列表。
  • 然后,只要将新的元素插入(添加)到我们的列表list1即可。

接下来要思考的问题是,新数组应该多大?通常我们得做法是:新数组的大小是已满的旧数组的2倍。我们将在Python中编程实现动态数组的概念,并创建一个简单的代码,很多功能不及Python强大。

实现动态数组Python代码

在Python中,我们利用ctypes的内置库来创建自己的动态数组类,因为ctypes模块提供对原始数组的支持,为了更快的对数组进行学习,所以对ctypes的知识可以查看官方文档进行学习。关于Python的公有方法与私有方法,我们在方法名称前使用双下划线**__**使其保持隐藏状态,代码如下:

# -*- coding: utf-8 -*-# @Time   : 2019-11-01 17:10# @Author  : yuzhou_1su# @ContactMe : https://blog.csdn.net/yuzhou_1shu# @File   : DynamicArray.py# @Software : PyCharmimport ctypesclass DynamicArray:  """A dynamic array class akin to a simplified Python list."""  def __init__(self):    """Create an empty array."""    self.n = 0       # count actual elements    self.capacity = 1   # default array capacity    self.A = self._make_array(self.capacity)   # low-level array  def is_empty(self):    """ Return True if array is empty"""    return self.n == 0  def __len__(self):    """Return numbers of elements stored in the array."""    return self.n  def __getitem__(self, i):    """Return element at index i."""    if not 0 <= i < self.n:      # Check it i index is in bounds of array      raise ValueError('invalid index')    return self.A[i]  def append(self, obj):    """Add object to end of the array."""    if self.n == self.capacity:      # Double capacity if not enough room      self._resize(2 * self.capacity)    self.A[self.n] = obj  # Set self.n index to obj    self.n += 1  def _resize(self, c):    """Resize internal array to capacity c."""    B = self._make_array(c)   # New bigger array    for k in range(self.n):  # Reference all existing values      B[k] = self.A[k]    self.A = B     # Call A the new bigger array    self.capacity = c  # Reset the capacity  @staticmethod  def _make_array(c):    """Return new array with capacity c."""    return (c * ctypes.py_object)()  def insert(self, k, value):    """Insert value at position k."""    if self.n == self.capacity:      self._resize(2 * self.capacity)    for j in range(self.n, k, -1):      self.A[j] = self.A[j-1]    self.A[k] = value    self.n += 1  def pop(self, index=0):    """Remove item at index (default first)."""    if index >= self.n or index < 0:      raise ValueError('invalid index')    for i in range(index, self.n-1):      self.A[i] = self.A[i+1]    self.A[self.n - 1] = None    self.n -= 1  def remove(self, value):    """Remove the first occurrence of a value in the array."""    for k in range(self.n):      if self.A[k] == value:        for j in range(k, self.n - 1):          self.A[j] = self.A[j+1]        self.A[self.n - 1] = None        self.n -= 1        return    raise ValueError('value not found')  def _print(self):    """Print the array."""    for i in range(self.n):      print(self.A[i], end=' ')    print()

测试动态数组Python代码

上面我们已经实现了一个动态数组的类,相信都很激动,接下来让我们来测试一下,看能不能成功呢?在同一个文件下,写的测试代码如下:

def main():  # Instantiate  mylist = DynamicArray()  # Append new element  mylist.append(10)  mylist.append(9)  mylist.append(8)  # Insert new element in given position  mylist.insert(1, 1024)  mylist.insert(2, 2019)  # Check length  print('The array length is: ', mylist.__len__())  # Print the array  print('Print the array:')  mylist._print()  # Index  print('The element at index 1 is :', mylist[1])  # Remove element  print('Remove 2019 in array:')  mylist.remove(2019)  mylist._print()  # Pop element in given position  print('Pop pos 2 in array:')  # mylist.pop()  mylist.pop(2)  mylist._print()if __name__ == '__main__':  main()

测试结果

激动人心的时刻揭晓,测试结果如下。请结合测试代码和数组的结构进行理解,如果由疏漏,欢迎大家指出。

The array length is: 5Print the array:10 1024 2019 9 8 The element at index 1 is : 1024Remove 2019 in array:10 1024 9 8 Pop pos 2 in array:10 1024 8 

总结

通过以上的介绍,我们知道了数组存在静态和动态类型。而在本博客中,我们着重介绍了什么是动态数组,并通过Python代码进行实现。希望你能从此以复杂的方式学会数组。

总结发言,其实越是简单的操作,背后实现原理可能很复杂。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    图解python全局变量与局部变量相关知识
    下一条:
    python基于gevent实现并发下载器代码实例
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客