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

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

#通过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()

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

(0)

相关推荐

  • Python动态生成多维数组的方法示例

    本文实例讲述了Python动态生成多维数组的方法.分享给大家供大家参考,具体如下: 多维数组其实就是多个一维数组的嵌套,Python中有原生的list,类似一个动态数组. 所以动态生成多维数组的思想就是在list中动态嵌套添加list. 下面代码生成一个一个3×3×2的三维数组: # coding:utf-8 # 使用Python3中的print函数 from __future__ import print_function arr = [] # 基本思想是在list中动态添加list,每个li

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

    实现一个支持动态扩容的数组并完成其增删改查 #通过python实现动态数组 """ 数组特点: 占用一段连续的内存空间,支持随机(索引)访问,且时间复杂度为O(1) 添加元素时间复杂度:O(n) 删除元素时间复杂度:O(n) """ class Arr: def __init__(self, capacity=10): """ 构造函数 :param capacity: 数组最大容量,不指定的话默认为10 "

  • python通过pillow识别动态验证码的示例代码

    目录 环境配置  安装 pillow(PIL)库 识别过程 生活中,我们在登录微博,邮箱的时候,常常会碰到验证码.在工作时,如果想要爬取一些数据,也会碰到验证码的阻碍.本次试验将带领大家认识验证码的一些特性,并利用 Python 中的 pillow 库完成对验证码的破解. 环境配置 Python 2.7 Pillow 模块 有个问题就是python2.7目前只能让使用到2020年,现在再利用2.7下载好多东西都会报错,也该是时候更新到python3.7了,本文还是依赖于2.7的环境. 识别验证码

  • Element实现动态表格的示例代码

    目录 [代码背景] [代码实现] #1# -> 代码复用的基础是你需要一个可复用的组件 #2# -> 在展示页面使用动态表格组件 #3# -> 如何给动态表格根据需求动态添加序号列/索引列 [代码背景] 有这样一个业务需求场景,有大概十几张表归属于某个类别,用户希望在同一个页面,通过选择不同的查询指标展示不同的表格,这些表的表头样式类似但是又不完全相同,怎么做呢? 到目前为止所有基于Element UI的表格样式都是直接在页面写死的,像官方这样: <el-table :data=&

  • C语言实现动态链表的示例代码

    目录 结构体定义已经函数声明 函数实现 创建一个链表 判断链表是否为空 获得链表中节点的个数 在某个特定的位置插入一个元素 获得指定下标的节点的元素 删除一个节点 链表逆序 链表的清空 链表的销毁 链表的遍历 按特定的元素查找节点 按某些特定的条件删除所有符合情况的节点 链表的排序 总结 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个部分:一个是存储

  • Python实现生命游戏的示例代码(tkinter版)

    目录 生命游戏(Game of Life) 游戏概述 生存定律 图形结构 代码实现 运行界面 使用简介 后续改进 生命游戏(Game of Life) 由剑桥大学约翰·何顿·康威设计的计算机程序.美国趣味数学大师马丁·加德纳(Martin Gardner,1914-2010)通过<科学美国人>杂志,将康威的生命游戏介绍给学术界之外的广大渎者,一时吸引了各行各业一大批人的兴趣,这时细胞自动机课题才吸引了科学家的注意. 游戏概述 用一个二维表格表示“生存空间”,空间的每个方格中都可放置一个生命细胞

  • Python实现登录接口的示例代码

    之前写了Python实现登录接口的示例代码,最近需要回顾,就顺便发到随笔上了 要求: 1.输入用户名和密码 2.认证成功,显示欢迎信息 3.用户名3次输入错误后,退出程序 4.密码3次输入错误后,锁定用户名 Readme: 1.UserList.txt 是存放用户名和密码的文件,格式为:username: password,每行存放一条用户信息 2.LockList.txt 是存放已被锁定用户名的文件,默认为空 3.用户输入用户名,程序首先查询锁定名单 LockList.txt,如果用户名在里面

  • 史上最简单的MyBatis动态SQL入门示例代码

    假如有如下的关于书籍基本信息的表: DROP DATABASE IF EXISTS `books`; CREATE DATABASE `books`; USE books; DROP TABLE IF EXISTS `book`; CREATE TABLE `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(128) DEFAULT NULL, `author` varchar(64) DEFAULT NULL, `pres

  • python实现log日志的示例代码

    源代码: # coding=utf-8 import logging import os import time LEVELS={'debug':logging.DEBUG,\ 'info':logging.INFO,\ 'warning':logging.WARNING,\ 'error':logging.ERROR,\ 'critical':logging.CRITICAL,} logger=logging.getLogger() level='default' def createFile

  • Python中字符串与编码示例代码

    在最新的Python 3版本中,字符串是以Unicode编码的,即Python的字符串支持多语言 编码和解码 字符串在内存中以Unicode表示,在操作字符串时,经常需要str和bytes互相转换   如果在网络上传输或保存到磁盘上,则从内存读到的数据就是str,要把str变为以字节为单位的bytes,称为编码   如果从网络或磁盘上读取字节流,则从网络或磁盘上读到的数据就是bytes,要把bytes变为str,称为解码   为避免乱码问题,应当始终坚持使用UTF-8编码对str和bytes进行

  • python+selenium+chromedriver实现爬虫示例代码

    下载好所需程序 1.Selenium简介 Selenium是一个用于Web应用程序测试的工具,直接运行在浏览器中,就像真正的用户在操作一样. 2.Selenium安装 方法一:在Windows命令行(cmd)输入pip install selenium即可自动安装,安装完成后,输入pip show selenium可查看当前的版本 方法二:直接下载selenium包: selenium下载网址 Pychome安装selenium如果出现无法安装,参考以下博客 解决Pycharm无法使用已经安装S

随机推荐