「列表 list」是一个抽象的数据结构概念,它表示元素的有序集合,支持元素访问、修改、添加、删除和遍历等操作,无须使用者考虑容量限制的问题。列表可以基于链表或数组实现。
- 链表天然可以看作一个列表,其支持元素增删查改操作,并且可以灵活动态扩容。
- 数组也支持元素增删查改,但由于其长度不可变,因此只能看作一个具有长度限制的列表。
当使用数组实现列表时,长度不可变的性质会导致列表的实用性降低。这是因为我们通常无法事先确定需要存储多少数据,从而难以选择合适的列表长度。若长度过小,则很可能无法满足使用需求;若长度过大,则会造成内存空间浪费。
为解决此问题,我们可以使用「动态数组 dynamic array」来实现列表。它继承了数组的各项优点,并且可以在程序运行过程中进行动态扩容。
实际上,许多编程语言中的标准库提供的列表是基于动态数组实现的,例如 Python 中的 list
、Java 中的 ArrayList
、C++ 中的 vector
和 C# 中的 List
等。在接下来的讨论中,我们将把“列表”和“动态数组”视为等同的概念。
4.3.2 列表实现¶
许多编程语言内置了列表,例如 Java、C++、Python 等。它们的实现比较复杂,各个参数的设定也非常考究,例如初始容量、扩容倍数等。感兴趣的读者可以查阅源码进行学习。
为了加深对列表工作原理的理解,我们尝试实现一个简易版列表,包括以下三个重点设计。
- 初始容量:选取一个合理的数组初始容量。在本示例中,我们选择 10 作为初始容量。
- 数量记录:声明一个变量
size
,用于记录列表当前元素数量,并随着元素插入和删除实时更新。根据此变量,我们可以定位列表尾部,以及判断是否需要扩容。 - 扩容机制:若插入元素时列表容量已满,则需要进行扩容。先根据扩容倍数创建一个更大的数组,再将当前数组的所有元素依次移动至新数组。在本示例中,我们规定每次将数组扩容至之前的 2 倍。
class MyList: """列表类""" def __init__(self): """构造方法""" self._capacity: int = 10 # 列表容量 self._arr: list[int] = [0] * self._capacity # 数组(存储列表元素) self._size: int = 0 # 列表长度(当前元素数量) self._extend_ratio: int = 2 # 每次列表扩容的倍数 def size(self) -> int: """获取列表长度(当前元素数量)""" return self._size def capacity(self) -> int: """获取列表容量""" return self._capacity def get(self, index: int) -> int: """访问元素""" # 索引如果越界,则抛出异常,下同 if index < 0 or index >= self._size: raise IndexError("索引越界") return self._arr[index] def set(self, num: int, index: int): """更新元素""" if index < 0 or index >= self._size: raise IndexError("索引越界") self._arr[index] = num def add(self, num: int): """在尾部添加元素""" # 元素数量超出容量时,触发扩容机制 if self.size() == self.capacity(): self.extend_capacity() self._arr[self._size] = num self._size += 1 def insert(self, num: int, index: int): """在中间插入元素""" if index < 0 or index >= self._size: raise IndexError("索引越界") # 元素数量超出容量时,触发扩容机制 if self._size == self.capacity(): self.extend_capacity() # 将索引 index 以及之后的元素都向后移动一位 for j in range(self._size - 1, index - 1, -1): self._arr[j + 1] = self._arr[j] self._arr[index] = num # 更新元素数量 self._size += 1 def remove(self, index: int) -> int: """删除元素""" if index < 0 or index >= self._size: raise IndexError("索引越界") num = self._arr[index] # 将索引 index 之后的元素都向前移动一位 for j in range(index, self._size - 1): self._arr[j] = self._arr[j + 1] # 更新元素数量 self._size -= 1 # 返回被删除的元素 return num def extend_capacity(self): """列表扩容""" # 新建一个长度为原数组 _extend_ratio 倍的新数组,并将原数组复制到新数组 self._arr = self._arr + [0] * self.capacity() * (self._extend_ratio - 1) # 更新列表容量 self._capacity = len(self._arr) def to_array(self) -> list[int]: """返回有效长度的列表""" return self._arr[: self._size]