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创建日历实例
Aug 21 Python
Python利用operator模块实现对象的多级排序详解
May 09 Python
关于Python中浮点数精度处理的技巧总结
Aug 10 Python
Python回文字符串及回文数字判定功能示例
Mar 20 Python
一百行python代码将图片转成字符画
Feb 19 Python
Python的高阶函数用法实例分析
Apr 11 Python
在Python中os.fork()产生子进程的例子
Aug 08 Python
python中几种自动微分库解析
Aug 29 Python
python 实现二维列表转置
Dec 02 Python
python 一维二维插值实例
Apr 22 Python
Python参数传递机制传值和传引用原理详解
May 22 Python
python使用建议与技巧分享(一)
Aug 17 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
php的一些小问题
2010/07/03 PHP
php把数组值转换成键的方法
2015/07/13 PHP
深入理解PHP之源码目录结构与功能说明
2016/06/01 PHP
Ajax::prototype 源码解读
2007/01/22 Javascript
10个新的最有前途的JavaScript框架
2009/03/12 Javascript
经过绑定元素时会多次触发mouseover和mouseout事件
2014/02/28 Javascript
jquery实现倒计时效果
2015/12/14 Javascript
JS获取IMG图片高宽的简单实例
2016/05/17 Javascript
javascript实现图片左右滚动效果【可自动滚动,有左右按钮】
2016/09/19 Javascript
最原始的jQuery注册验证方式
2016/10/11 Javascript
Angular浏览器插件Batarang介绍及使用
2018/02/07 Javascript
vue后台管理之动态加载路由的方法
2018/08/13 Javascript
使用Vue实现移动端左滑删除效果附源码
2019/05/16 Javascript
js简单遍历获取对象中的属性值的方法示例
2019/06/19 Javascript
浅谈Vue3 Composition API如何替换Vue Mixins
2020/04/29 Javascript
Python pickle模块用法实例
2015/04/14 Python
用于统计项目中代码总行数的Python脚本分享
2015/04/21 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
2018/02/21 Python
python XlsxWriter模块创建aexcel表格的实例讲解
2018/05/03 Python
对Python 2.7 pandas 中的read_excel详解
2018/05/04 Python
Python实现统计给定字符串中重复模式最高子串功能示例
2018/05/16 Python
python递归全排列实现方法
2018/08/18 Python
python如何实现代码检查
2019/06/28 Python
Python简易版停车管理系统
2019/08/12 Python
python 实现单例模式的5种方法
2020/09/23 Python
html5 Canvas画图教程(2)—画直线与设置线条的样式如颜色/端点/交汇点
2013/01/09 HTML / CSS
Orvis官网:自1856年以来,优质服装、飞钓装备等
2018/12/17 全球购物
大学本科生的个人自我评价
2013/12/09 职场文书
研发工程师岗位职责
2014/04/28 职场文书
五水共治捐款倡议书
2014/05/14 职场文书
社区爱国卫生月活动总结
2014/06/30 职场文书
水电维修专业推荐信
2014/09/06 职场文书
落实八项规定专题民主生活会对照检查材料
2014/09/15 职场文书
2017年寒假少先队活动总结
2016/04/06 职场文书
李清照的诗词赏析(20首)
2019/08/22 职场文书
Vue的过滤器你真了解吗
2022/02/24 Vue.js