动态数组如何实现?揭秘内存分配与元素添加!
2024-02-01 12:53:50
引言:
提到数组,大部分脑海里一下子想到了一堆东西:int long short byte float double boolean char String 这些是我们经常使用的数据类型,同时也是最基本的。而数组是把这种数据类型组合在一起,让我们可以用一个变量名来管理多个这种类型的数据。
但数组有一个很令人头疼的缺点——它的大小是固 固的,也就是我们创建数组的时候,就要知道它的大小。而在使用数组的时候,可能我们还需要更多的数据,所以数组必须要扩容,扩容又非常麻烦。
那么有没有一个容器可以既是数组又可以动态扩展呢?答案是动态数组,又名可变长数组,就是解决这个问题的。
动态数组,顾名思义,就是数组的大小是动态扩展的。这种数据类型在很多语言里是内置的,即使是数据类型不在是内置的,也会提供一些动态数组的支持。
本文将详细解析动态数组的底层实现原理,揭晓内存分配与元素添加的奥秘,并通过代码示例,揭开动态数组背后的技术奥秘。
那么它是如何做到这一切的呢?
动态数组的实现原理比较简单,它其实就是一个数组的首地址,也就是内存起始位置,同时有一个变量来记录元素个数(很多语言里这个变量也叫size)。
这和我们平时理解的数组有一个本质区别,那就是数组的首地址和长度两个变量才是动态数组本身,它本身其实不占位置,而普通数组占的空间就是元素的总和了。
这有个非常明显的优点,那就是空间的利用率更高,虽然我们可以通过某些手段,如linkedlist,前向后指针,达到同样效果,但始终不如动态数组这种对内存管理要求更低,更直接粗暴的内存管理来的高。
动态数组的缺陷也很明显,那就是扩容后,如果空间不够,会引起内存的再一次分配,非常耗时。在扩容的时候,原先内存中的数据会拷贝到新的内存中,这当然也非常耗时间。
当然,解决这些缺点的方法,也是很直接的,就是不要这么频繁的扩容。
实现一个数组的内存分配过程
class Array:
def __init__(self):
self.size = 0 # 记录数组的当前元素个数
self.arr = [] # 元素存放的列表
# 当数组中元素个数等于数组长度时,执行元素扩容
def expand(self):
self.size *= 2 # 增加两倍空间
self.arr = self.arr[:self.size] # 再创建列表,原有元素在扩容后仍然存在
# 数组元素个数 + 1,并插入元素
def add(self, value):
self.arr.append(value)
self.size += 1
# 删除元素
def delete(self, index):
del self.arr[index] # 删除元素
self.size -= 1 # 数组元素个数 - 1
# 创建一个数组,并往其中添加元素
a = Array()
a.add(1)
a.add(2)
a.add(3)
a.add(4)
# 数组已经扩容一次了,虽然数组长度变大了,但数组中只有前 3个元素
a.add(5)
# 输出当前数组中的元素
print(a.arr) # 输出结果:1,2,3,4,5