利用python实现动态数组

说动态数组之前,首先要说数组,数组是一种顺序存储的线性表,所有元素的内存地址都是连续的。数组的最大优点是他的查找时间复杂度能够达到O(1),但是增和删的时间复杂度较高O(n)

二、动态数组

动态数组,即根据用户的输入动态扩充或缩小当前数组的容量。在python中,已经内置了动态数组,叫做列表,List

下面是利用python代码实现动态数组的增删改查操作。

# ArrryList.py
class Arr:
    # 设置两个常亮,分别是默认容量大小与未找到元素返回的值
    DEFAULT_CAPACITY = 10
    ELEMENT_NOT_FOUND = -1

    # 初始化,若用户未指定数组大小或者小于默认,直接使用默认容量,否则容量为用户指定
    def __init__(self, capacity=DEFAULT_CAPACITY):
        capacity = self.DEFAULT_CAPACITY if capacity < self.DEFAULT_CAPACITY else capacity
        self._capacity = capacity
        self._size = 0
        self._elements = [None] * self._capacity

    def size(self):
        return self._size

    def is_empty(self):
        # return True if self._size == 0 else False
        # 改进上面这还代码,因为在python中所有值都可以转布尔,所以利用隐式布尔值
        return self._size == 0

    # 查看元素是否存在--->bool
    def contains(self, element):
        # if self.index_of(element):
        #     return True
        # return False

        return True if self.index_of(element) else False

    # 根据索引添加,添加结束后判断是否需要扩容
    def add(self, index, element):
        self._out_of_index(index)
        self._size = i = self._size + 1
        while i >= index:
            self._elements[i] = self._elements[i - 1]
            i -= 1
        self._elements[index] = element
        self._expend_capacity()

    # 数组末尾追加,添加结束后判断是否需要扩容
    def add_last(self, element):
        self._out_of_index(self._size)
        self._elements[self._size] = element
        self._size += 1
        self._expend_capacity()

    # 根据索引取值
    def get(self, index):
        self._out_of_index(index)
        return self._elements[index]

    # 根据索引改值
    def set(self, index, element):
        self._out_of_index(index)
        self._elements[index] = element

    # 删除元素,若用户未指定参数,默认删除最后一个元素,删除后判断是否要缩容
    def remove(self, index=ELEMENT_NOT_FOUND):
        self._out_of_index(index)
        if index == self.ELEMENT_NOT_FOUND:
            self._remove_last()

        # 删除元素后,该索引后的每个元素都要往前移一格,然后数组大小减一
        i = index
        while i <= self._size:
            self._elements[i] = self._elements[i + 1]
            i += 1
        self._size -= 1
        self._reduce_capacity()

    # 返回第一个匹配传入值的索引
    def index_of(self, element):
        for index in range(self._size + 1):
            if element == self._elements[index]:
                return index
        return self.ELEMENT_NOT_FOUND

    def clear(self):
        self._size = 0
        return self._size

    # 判断索引是否越界
    def _out_of_index(self, index):
        if index < 0 or index > self._size + 1:
            raise IndexError('index out of range')

    # 当容量不够时动态扩容,默认为扩大为原来的1.5倍
    def _expend_capacity(self):
        # 当size小于容量,直接返回,当size正好等于容量,需要扩容
        if self._size < self._capacity - 1:
            return

        self._capacity = self._capacity * 2
        self._new_elements = [None] * self._capacity
        for i in range(self._size):
            self._new_elements[i] = self._elements[i]

        self._elements = self._new_elements

    # 动态缩容,默认缩小到当前的一半
    def _reduce_capacity(self):
        # 当size小于默认容量或者大于当前容量的一半时直接返回
        if self._size <= self._capacity or self._size > (self._capacity // 2):
            return

        self._capacity = (self._capacity // 2).__ceil__()
        for i in range(self._size):
            self._new_elements[i] = self._elements[i]

        self._elements = self._new_elements

    def __str__(self):
        arrlist = ''
        num = 0

        for i in self._elements:
            if num == self._size:
                break
            arrlist = arrlist + str(i) + ','
            num += 1

        arrlist = arrlist.strip(",")
        arrlist = '[' + arrlist + ']'
        return arrlist

    """
    删除最后一个元素,因为最后一个元素也是往前移动一格,虽然size-1,但是其实最后一个元素引用了两次,
    即当前的数组末尾加上原来位置的引用,无法回收,所以对于最后一个元素要手动设置为None
    """

    def _remove_last(self):
        self._size -= 1
        self._elements[self._size] = None
        self._reduce_capacity()

# 测试文件,test.py
if __name__ == '__main__':
    from ArrayList import Arr
    a = Arr()
    # a = a  #type:Arr
    a.add_last(11)
    a.add_last(22)
    a.add_last(33)
    a.add_last(44)
    a.add_last('55')
    a.add_last(66)
    a.add_last(77)
    a.add_last(88)
    a.add_last(99)
    # a.add(2,'st')
    # a.remove(2)
    # print(a.size())
    # print(a.is_empty())
    # print(a.contains('55'))
    # print(a.index_of(99))
    # print(a.get(789))
    # a.set(-1,99)
    # a.clear()

    print(a)