python实现动态数组的示例代码


Posted in Python onJuly 15, 2019

实现一个支持动态扩容的数组并完成其增删改查

#通过python实现动态数组
 
"""
数组特点:
  占用一段连续的内存空间,支持随机(索引)访问,且时间复杂度为O(1)
  添加元素时间复杂度:O(n)
  删除元素时间复杂度:O(n)
"""
 
class Arr:
  def __init__(self, capacity=10):
    """
    构造函数
    :param capacity: 数组最大容量,不指定的话默认为10
    """
    self._capacity = capacity
    self._size = 0                 # 数组有效元素的数目,初始化为0
    self._data = [None] * self._capacity  # 由于python的list是动态扩展的,而我们要实现底层具有固定容量、占用一段连续的内存空间的数组,所以用None来作为无效元素的标识
 
  def __getitem__(self, item):
    """让Arr类支持索引操作"""
    return self._data[item]
 
  def getSize(self):
    """返回数组有效元素的个数"""
    return self._size
 
  def getCapacity(self):
    """返回当前数组的容量"""
    return self._capacity
 
  def isEmpty(self):
    """判断当前数组是否为空"""
    return self._size == 0
 
  def add(self, index, elem):
    """
    向数组中添加一个元素,注意数组占用的是一段连续的内存空间,所以在添加元素后,数组还是要保证这个特点的,因此需要将后面的元素都向后挪一个位置,而且要注意要先从
    尾部开始挪,防止元素之间的覆盖
    时间复杂度:O(n)
    :param index:  添加的元素所在的索引
    :param elem:  所要添加的元素
    """
    if index < 0 or index > self._size:   # 插入的位置无效
      raise Exception('Add Filed. Require 0 <= index <= self._size')
    if self._size == self._capacity:    # 满了
      self._resize(self._capacity * 2)  # 默认扩容当前容量的二倍。容量翻倍要比容量加上一个固定值要好,这样做均摊复杂度为O(1)。具体请百度
 
    for i in range(self._size - 1, index - 1, -1): # 从尾部开始挪动元素,在index处腾出一个空间
                            # 一定要注意在步长为负数的情况下,区间是左开右闭区间,即(index, self._size - 1],所以是index-1,与正常的左闭右开区间是相反的!
      self._data[i + 1] = self._data[i]
    self._data[index] = elem    # 将该位置赋值为elem
    self._size += 1         # 数组有效元素数加1
 
  def addLast(self, elem):
    """
    向数组尾部添加元素
    时间复杂度:O(1)
    :param elem: 所要添加的元素
    """
    self.add(self._size, elem) # 直接调用add方法,注意不用再次判定合法性了,因为add函数中已经判断过了
 
  def addFirst(self, elem):
    """
    想数组头部添加元素
    时间复杂度:O(n)
    :param elem: 所要添加的元素
    """
    self.add(0, elem)  # 同理直接调用add方法
 
  def get(self, index):
    """
    获得索引index处的元素
    时间复杂度:O(1)
    :param index: 数组索引
    :return:   数组索引处的值
    """
    if index < 0 or index >= self._size:    # 判断index的合法性
      raise Exception('Get failed. Index is illegal.')
    return self._data[index]
 
  def getFirst(self):
    """
    获得数组首位置元素的值
    :return: 首位置元素的值
    """
    return self.get(0)   # 直接调用get函数,安全可靠
 
  def getLast(self):
    """
    获得数组末尾元素的值
    :return: 末尾元素的值
    """
    return self.get(self._size - 1) # 直接调用get函数,安全可靠
 
  def set(self, index, elem):
    """
    将索引为index的元素的值设为elem
    时间复杂度:O(1)
    :param index: 索引
    :param elem:  新的值
    """
    if index < 0 or index >= self._size:    # 判断index的合法性
      raise Exception('Sat failed. Index is illegal.')
    self._data[index] = elem
 
  def contains(self, elem):
    """
    查看数组中是否存在元素elem,最好不要传入一个浮点数,你懂得。。
    时间复杂度:O(n)
    :param elem: 目标元素
    :return:   bool值,存在为真
    """
    for i in range(self._size):    # 遍历
      if self._data[i] == elem:
        return True        # 找到了就返回True
    return False            # 遍历完了还没找到,就返回False
 
  def find(self, elem):
    """
    在数组中查找元素,并返回元素所在的索引。(如果数组中存在多个elem,只返回最左边elem的索引)
    时间复杂度:O(n)
    :param elem: 目标元素
    :return:   元素所在的索引,没找到则返回-1(无效值)
    """
    for i in range(self._size):     # 遍历数组
      if self._data[i] == elem:
        return i          # 找到就返回索引
    return -1              # 没找到返回-1
 
  def findAll(self, elem):
    """
    找到值为elem全部元素的索引
    :param elem: 目标元素
    :return:   一个列表,值为全部elem的索引
    """
    ret_list = Arr()        # 建立一个新的数组用于存储索引值
    for i in range(self._size):   # 遍历数组
      if self._data[i] == elem:
        ret_list.addLast(i)   # 找到就将索引添加进ret_list
    return ret_list
 
  def remove(self, index):
    """
    删除索引为index的元素。index后面的元素都要向前移动一个位置
    时间复杂度:O(n)
    :param index: 目标索引
    :return:   位于该索引的元素的值
    """
    if index < 0 or index >= self._size:  # index合法性检查
      raise Exception('Remove failed.Require 0 <= index < self._size')
    ret = self._data[index]         # 拷贝一下index处的元素,便于返回
    for i in range(index + 1, self._size): # index后面的元素都向前挪一个位置
      self._data[i - 1] = self._data[i]
    self._size -= 1     # 维护self._size
    self._data[self._size] = None  # 最后一个元素的垃圾回收
 
    if self._size and self._capacity // self._size == 4:  # 如果当前有效元素为总容量的四分之一且还存在有效元素,则将容量缩减为原来的一半
      self._resize(self._capacity // 2)
    return ret
 
  def removeFirst(self):
    """
    删除数组首位置的元素
    时间复杂度:O(n)
    :return: 数组首位置的元素
    """
    return self.remove(0)  # 调用remove函数
 
  def removeLast(self):
    """
    删除数组末尾的元素
    时间复杂度:O(1)
    :return: 数组末尾的元素
    """
    return self.remove(self._size - 1)   # 调用remove函数
 
  def removeElement(self, elem):
    """
    删除数组中为elem的元素,如果数组中不存在elem,那么什么都不做。如果存在多个相同的elem,只删除最左边的那个
    时间复杂度:O(n)
    :param elem: 要删除的目标元素
    """
    index = self.find(elem)     # 尝试找到目标元素(最左边的)的索引
    if index != -1:         # elem在数组中就删除,否则什么都不做
      self.remove(index)     # 调用remove函数
 
  def removeAllElement(self, elem):
    """
    删除数组内所有值为elem的元素,可以用递归来写,这里用的迭代的方法。elem不存在就什么都不做
    :param elem: 要删除的目标元素
    """
    while True:
      index = self.find(elem)   # 循环来找elem,如果还存在就继续删除
      if index != -1:       # 若存在
        self.remove(index)
      else:
        break
 
  def get_Max_index(self):
    """
    获取数组中的最大元素的索引,返回最大元素的索引值,如果有多个最大值,默认返回最左边那个的索引
    时间复杂度:O(n)
    :return: 最大元素的索引
    """
    if self.isEmpty():
      raise Exception('Error, array is Empty!')
    max_elem_index = 0  # 记录最大值的索引,初始化为0 
    for i in range(1, self.getSize()):  # 从索引1开始遍历,一直到数组尾部
      if self._data[i] > self._data[max_elem_index]:  # 如果当前索引的值大于最大值索引处元素的值
        max_elem_index = i   # 更新max_elem_index,这样它还是当前最大值的索引
    return max_elem_index   # 遍历完后,将数组的最大值的索引返回
 
  def removeMax(self):
    """
    删除数组中的最大元素,返回最大元素的值,如果有多个最大值,默认值删除最左边那个
    时间复杂度:O(n)
    :return: 最大元素
    """
    return self.remove(self.get_Max_index())  # 直接调用remove函数删除最大值
 
  def get_Min_index(self):
    """
    获取数组中的最小元素的索引,返回最小元素的索引值,如果有多个最小值,默认返回最左边那个的索引
    时间复杂度:O(n)
    :return: 最小元素的索引
    """
    if self.isEmpty():
      raise Exception('Error, array is Empty!')
    min_elem_index = 0  # 记录最小值的索引,初始化为0 
    for i in range(1, self.getSize()):  # 从索引1开始遍历,一直到数组尾部
      if self._data[i] < self._data[min_elem_index]:  # 如果当前索引的值小于最小值索引处元素的值
        min_elem_index = i   # 更新min_elem_index,这样它还是当前最小值的索引
    return min_elem_index   # 遍历完后,将数组的最小值的索引返回
 
  def removeMin(self):
    """
    删除数组中的最小元素,返回最小元素的值,如果有多个最小值,默认值删除最左边那个
    时间复杂度:O(2n),可以看成是O(n)的
    :return: 最小元素
    """
    return self.remove(self.get_Min_index())
 
  def swap(self, index1, index2):
    """
    交换分别位于索引index1和索引index2处的元素
    :param index1: 索引1
    :param index2: 索引2
    """ 
    if index1 < 0 or index2 < 0 or index1 >= self._size or index2 >= self._size:    # 合法性检查
      raise Exception('Index is illegal')
    self._data[index1], self._data[index2] = self._data[index2], self._data[index1]   # 交换元素
 
  def printArr(self):
    """对数组元素进行打印"""
    for i in range(self._size):
      print(self._data[i], end=' ')
    print('\nSize: %d-----Capacity: %d' % (self.getSize(), self.getCapacity()))
 
  # private
  def _resize(self, new_capacity):
    """
    数组容量放缩至new_capacity,私有成员函数
    :param new_capacity: 新的容量
    """
    new_arr = Arr(new_capacity)     # 建立一个新的数组new_arr,容量为new_capacity
    for i in range(self._size):
      new_arr.addLast(self._data[i]) # 将当前数组的元素按当前顺序全部移动到new_arr中
    self._capacity = new_capacity    # 数组容量变为new_capacity
    self._data = new_arr._data     # 将new_arr._data赋值给self._data,从而完成数组的容量放缩操作

测试代码

import Array 
import numpy as np
np.random.seed(7)
test = Array.Arr()
print(test.getSize())
print(test.getCapacity())
print(test.isEmpty())
for i in range(8):
  test.add(0, np.random.randint(5))
test.printArr()
test.addLast(2)
test.printArr()
print(test.get(3))
test.set(3, 10)
test.printArr()
print(test.contains(10))
print(test.find(4))
test.findAll(1).printArr()
test.remove(3)
test.printArr()
test.removeFirst()
test.removeLast()
test.printArr()
test.removeElement(4)
test.printArr()
test.removeAllElement(3)
test.printArr()
for i in range(30):
  test.addLast(np.random.randint(10))
test.printArr()
print(test[3])
test.swap(0, 1)
test.printArr()

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

Python 相关文章推荐
忘记ftp密码使用python ftplib库暴力破解密码的方法示例
Jan 22 Python
Python实现给qq邮箱发送邮件的方法
May 28 Python
基于Python列表解析(列表推导式)
Jun 23 Python
Django开发中的日志输出的方法
Jul 02 Python
python-itchat 获取微信群用户信息的实例
Feb 21 Python
python 求一个列表中所有元素的乘积实例
Jun 11 Python
Pytorch 数据加载与数据预处理方式
Dec 31 Python
深入浅析python的第三方库pandas
Feb 13 Python
python利用蒙版抠图(使用PIL.Image和cv2)输出透明背景图
Aug 04 Python
python获取命令行参数实例方法讲解
Nov 02 Python
Django多数据库联用实现方法解析
Nov 12 Python
python 删除系统中的文件(按时间,大小,扩展名)
Nov 19 Python
python移位运算的实现
Jul 15 #Python
python与C、C++混编的四种方式(小结)
Jul 15 #Python
解决Python3 控制台输出InsecureRequestWarning问题
Jul 15 #Python
python导包的几种方法(自定义包的生成以及导入详解)
Jul 15 #Python
Python将文字转成语音并读出来的实例详解
Jul 15 #Python
解决win7操作系统Python3.7.1安装后启动提示缺少.dll文件问题
Jul 15 #Python
Python符号计算之实现函数极限的方法
Jul 15 #Python
You might like
C#静态方法与非静态方法实例分析
2014/09/22 PHP
PHP比你想象的好得多
2014/11/27 PHP
php验证手机号码
2015/11/11 PHP
thinkPHP3.1验证码的简单实现方法
2016/04/22 PHP
php文件上传后端处理小技巧
2016/05/22 PHP
PHP数组遍历的几种常见方式总结
2019/02/15 PHP
php源码的使用方法讲解
2019/09/26 PHP
PHP中类与对象功能、用法实例解读
2020/03/27 PHP
js实现ASP分页函数 HTML分页函数
2006/09/22 Javascript
用javascript实现点击链接弹出&quot;图片另存为&quot;而不是直接打开
2007/08/15 Javascript
Ext grid 添加右击菜单
2009/11/26 Javascript
Json序列化和反序列化方法解析
2013/12/19 Javascript
jQuery判断当前点击的是第几个li的代码
2014/09/26 Javascript
使用JS+plupload直接批量上传图片到又拍云
2014/12/01 Javascript
jQuery中$(function() {});问题详解
2015/08/10 Javascript
基于jQuery全屏焦点图左右切换插件responsiveslides
2015/09/07 Javascript
jQuery进行组件开发完整实例
2015/12/15 Javascript
Bootstrap实现各种进度条样式详解
2017/04/13 Javascript
jQuery获取单选按钮radio选中值与去除所有radio选中状态的方法
2017/05/20 jQuery
JS实现弹出下载对话框及常见文件类型的下载
2017/07/13 Javascript
JS继承与闭包及JS实现继承的三种方式
2017/10/15 Javascript
如何在js代码中消灭for循环实例详解
2018/07/29 Javascript
在Vue项目中引入JQuery-ui插件的讲解
2019/01/27 jQuery
Javascript 关于基本类型和引用类型的个人理解
2019/11/01 Javascript
JS实现简易留言板(节点操作)
2020/03/16 Javascript
详解微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)
2020/07/21 Javascript
俄罗斯最大的在线珠宝大卖场:Nebo
2019/12/08 全球购物
Fox Racing官方网站:越野摩托车和山地自行车装备和服装
2019/12/23 全球购物
中医专业职业生涯规划书范文
2014/01/04 职场文书
高三历史教学反思
2014/01/09 职场文书
军训自我鉴定怎么写
2014/02/13 职场文书
优秀工作者事迹材料
2014/12/26 职场文书
事业单位年度考核评语
2014/12/31 职场文书
导游词之云南省玉龙雪山
2019/12/19 职场文书
Python入门学习之类的相关知识总结
2021/05/25 Python
html粘性页脚的具体使用
2022/01/18 HTML / CSS