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 相关文章推荐
把大数据数字口语化(python与js)两种实现
Feb 21 Python
Python的Django框架中TEMPLATES项的设置教程
May 29 Python
简单讲解Python编程中namedtuple类的用法
Jun 21 Python
Python简单爬虫导出CSV文件的实例讲解
Jul 06 Python
kaggle+mnist实现手写字体识别
Jul 26 Python
python检测文件夹变化,并拷贝有更新的文件到对应目录的方法
Oct 17 Python
浅谈pyqt5中信号与槽的认识
Feb 17 Python
Python实现微信翻译机器人的方法
Aug 13 Python
pip安装tensorflow的坑的解决
Apr 19 Python
Python xmltodict模块安装及代码实例
Oct 05 Python
Pandas中两个dataframe的交集和差集的示例代码
Dec 13 Python
python 基于Apscheduler实现定时任务
Dec 15 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
Fatal error: session_start(): Failed to initialize storage module: files问题解决方法
2014/05/04 PHP
php中创建和调用webservice接口示例
2014/07/25 PHP
JavaScript的9个陷阱及评点分析
2008/05/16 Javascript
javascript操作cookie_获取与修改代码
2009/05/21 Javascript
jQuery 常见学习网站与参考书
2009/11/09 Javascript
爆炸式的JS圆形浮动菜单特效代码
2010/03/03 Javascript
JS实现网页表格自动变大缩小的方法
2015/03/09 Javascript
纯JavaScript代码实现文本比较工具
2016/02/17 Javascript
JavaScript知识点总结(十一)之js中的Object类详解
2016/05/31 Javascript
微信小程序之MaterialDesign--input组件详解
2017/02/15 Javascript
从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
2017/04/13 Javascript
微信小程序开发教程之增加mixin扩展
2017/08/09 Javascript
vuejs实现本地数据的筛选分页功能思路详解
2017/11/15 Javascript
详解单页面路由工程使用微信分享及二次分享解决方案
2019/02/22 Javascript
小程序实现订单倒计时功能
2019/04/23 Javascript
vue 组件开发原理与实现方法详解
2019/11/29 Javascript
JS遍历树层级关系实现原理解析
2020/08/31 Javascript
[01:52]PWL S2开团时刻第四期——DOTA2成语故事
2020/12/03 DOTA
跟老齐学Python之不要红头文件(1)
2014/09/28 Python
Python使用Django实现博客系统完整版
2020/09/29 Python
Python文件读写保存操作的示例代码
2018/09/14 Python
python 多线程中子线程和主线程相互通信方法
2018/11/09 Python
python实现视频读取和转化图片
2019/12/10 Python
基于Python和PyYAML读取yaml配置文件数据
2020/01/13 Python
Python实现ATM系统
2020/02/17 Python
浅谈python元素如何去重,去重后如何保持原来元素的顺序不变
2020/02/28 Python
使用Matplotlib绘制不同颜色的带箭头的线实例
2020/04/17 Python
python中random模块详解
2021/03/01 Python
利用CSS3实现毛玻璃效果示例源码
2016/09/25 HTML / CSS
智利最大的网上商店:Linio智利
2016/11/24 全球购物
新浪微博实习心得体会
2014/01/27 职场文书
《世界多美呀》教学反思
2014/03/02 职场文书
新学期红领巾广播稿
2014/10/04 职场文书
步步惊心观后感
2015/06/12 职场文书
剖析后OpLog订阅MongoDB的数据变更就没那么难了
2022/02/24 MongoDB
使用python创建股票的时间序列可视化分析
2022/03/03 Python