[Hello 算法】列表

「列表 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]

    4.3   列表 - Hello 算法 (hello-algo.com)

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值