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在Windows下安装setuptools(easy_install工具)步骤详解
Jul 01 Python
听歌识曲--用python实现一个音乐检索器的功能
Nov 15 Python
python opencv之SIFT算法示例
Feb 24 Python
python面向对象多线程爬虫爬取搜狐页面的实例代码
May 31 Python
详解python中Numpy的属性与创建矩阵
Sep 10 Python
Python遍历文件夹 处理json文件的方法
Jan 22 Python
Django 外键的使用方法详解
Jul 19 Python
pycharm配置git(图文教程)
Aug 16 Python
Python3实现二叉树的最大深度
Sep 30 Python
使用Python文件读写,自定义分隔符(custom delimiter)
Jul 05 Python
浅析Python 抽象工厂模式的优缺点
Jul 13 Python
彻底解决pip下载pytorch慢的问题方法
Mar 01 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出现Cannot modify header information问题的解决方法大全
2008/04/09 PHP
JavaScript高级程序设计 读书笔记之九 本地对象Array
2012/02/27 Javascript
javascript设计模式 接口介绍
2012/07/24 Javascript
jQuery查询数据返回object和字符串影响原因是什么
2013/08/09 Javascript
jQuery中bind,live,delegate与one方法的用法及区别解析
2013/12/30 Javascript
关于JavaScript对象的动态选择及遍历对象
2014/03/10 Javascript
input:checkbox多选框实现单选效果跟radio一样
2014/06/16 Javascript
javascript快速排序算法详解
2014/09/17 Javascript
javascript实现简单查找与替换的方法
2015/07/22 Javascript
jQuery实现时尚漂亮的弹出式对话框实例
2015/08/07 Javascript
AngularJS中的过滤器filter用法完全解析
2016/04/22 Javascript
Bootstrap table分页问题汇总
2016/05/30 Javascript
JS获取复选框的值,并传递到后台的实现方法
2016/05/30 Javascript
Javascript 实现计算器时间功能详解及实例(二)
2017/01/08 Javascript
jQuery模拟爆炸倒计时功能实例代码
2017/08/21 jQuery
对于input 框限定输入值为浮点型的js代码
2017/09/25 Javascript
java实现单链表增删改查的实例代码详解
2019/08/30 Javascript
jquery实现有过渡效果的tab切换
2020/07/17 jQuery
vue 使用 sortable 实现 el-table 拖拽排序功能
2020/12/26 Vue.js
简介Django中内置的一些中间件
2015/07/24 Python
python得到qq句柄,并显示在前台的方法
2018/10/14 Python
python绘制简单彩虹图
2018/11/19 Python
django实现类似触发器的功能
2019/11/15 Python
PyCharm下载和安装详细步骤
2019/12/17 Python
python模拟实现斗地主发牌
2020/01/07 Python
利用jupyter网页版本进行python函数查询方式
2020/04/14 Python
html5 datalist标签使用示例(自动完成组件)
2014/05/04 HTML / CSS
Moda Operandi官网:美国奢侈品电商,海淘秀场T台同款
2020/05/26 全球购物
会计专业应届生自荐信
2014/02/07 职场文书
人力资源求职信
2014/05/25 职场文书
酒店优秀员工事迹材料
2014/06/02 职场文书
企业爱心捐款倡议书
2015/04/27 职场文书
甲午风云观后感
2015/06/02 职场文书
烈士陵园观后感
2015/06/08 职场文书
物资采购管理制度
2015/08/06 职场文书
MySql数据库触发器使用教程
2022/06/01 MySQL