一、数组
线性数据结构,其将相同类型元素(链表就不一定要存储相同类型的元素)存储在连续的内存空间中。。数组有Index
数组的优点:访问很高效,O(1)
PS:元素长度是单个元素占用的内存空间,这里是4bytes
数组的缺点:初始化后长度不可变、插入或删除元素效率低下O(n
数组中首个元素对应数组的内存地址偏移量是0,Index可以理解为偏移程度,所以Index从0开始
二、链表
存储在非连续的内存空间中。
链表「节点 Node」包含两项数据,一是节点「值 Value」,二是指向下一节点的「指针 Pointer」,或称「引用 Reference」。
尾结点指向空,None
将头节点当作链表的代称,例如头节点 head
和链表 head
实际上是同义的。
初始化链表需要初始化Node和next:
# 初始化链表 1 -> 3 -> 2 -> 5 -> 4
# 初始化各个节点
n0 = ListNode(1)
n1 = ListNode(3)
n2 = ListNode(2)
n3 = ListNode(5)
n4 = ListNode(4)
# 构建引用指向
n0.next = n1
n1.next = n2
n2.next = n3
n3.next = n4
链表优点:插入和删除节点的效率高O(1)
链表缺点:访问节点效率低,占用内存大
def access(head: ListNode, index: int) -> ListNode | None:
"""访问链表中索引为 index 的节点"""
for _ in range(index):
if not head:
return None
head = head.next
return head
三、列表
动态数组,解决数组长度不可变的缺点
列表的扩充机制:
- 扩容机制:插入元素时可能超出列表容量,此时需要扩容列表。(if self.__size == self.capacity()或者size == 1/2 capacity或者...,可以自己定;size是真实长度,capacity是预定容量)扩容方法是根据扩容倍数创建一个更大的数组,并将当前数组的所有元素依次移动至新数组。在本示例中,我们规定每次将数组扩容至之前的 2 倍。