列表中可以包含元组吗python_Python 中的列表和元组

Python 中的列表和元组

要编写一个高效的程序,我们需要了解几件事:首先,程序的输入内容是什么,其次是我们应该如何选择最合适的数据结构来处理该输入。

在这篇博文中,我们将会在与 dict,set 等其他数据结构的比较中了解数据结构 List 和 Tuple 以及它可以有效处理的输入内容。

列表和元组属于一类称为数组的数据结构。数组是元素的集合,而这些元素的顺序或位置与元素本身一样重要。因为定义数组时我们给定了位置或索引,所以找到元素需要的时间复杂度为 O(1)。列表是一个动态数组,我们可以在其中修改和调整存储在其中的数据的大小。 元组是一个静态数组,其元素是固定且不可变的。元组由 Python 运行时缓存,这意味着我们不需要在每次我们需要使用一个元组的时候 Python 不需要与内核对话来获得保留这个元组的内存。

在计算机系统中,存储器是一系列编号的分配存储块,每个分配存储块都可以容纳一个数字。Python 通过引用将数据存储在这些分配存储块中。这意味着数字本身只是指向或引用了我们实际关心的数据。

当创建列表或元组时,我们需要分配一个系统存储块,该块的每个部分都使用整数指针进行引用。为了查找列表中的任何特定元素,我们应该知道分配存储块的编号和所需的元素。

例如,假设我们有一个从分配存储块编号 S 开始的数组,要找到该数组中的第 5 个元素,我们可以直接搜索分配存储块编号 S + 5 ,同样类推到数组中的 i 元素。但是,如果分配存储块编号不适用于给定的数组,那么我们需要在整个数组中执行元素搜索,时间复杂度会随着数组大小的增加而增加。此搜索也称为线性搜索。最坏的情况是 O(n),其中 n 是列表中元素的总数。如果列表已排序,则可以使用其他有效的搜索算法来搜索数组中的元素如二分法。

为了进行搜索和排序,Python 内置了 __ eq __、__ lt __ 等比较方法,并且 Python 中的列表内置有 TimSort 的内置排序算法,而它的最佳情况是 O(n),最坏的情况是 O(nlog n)。

排序完成后,我们可以进行二分法,其平均复杂度为 O(log n)。它通过查看列表的中间并将此值与所需值进行比较来实现此目的。如果此中点的值小于我们的期望值,则考虑列表的右半部分,然后继续像这样将列表减半,直到找到该值或知道该值不会出现在已排序列表中为止。我们不需要像线性搜索那样需要读取列表中的所有值。相反,我们仅读取其中的一小部分。

注意:我们可以使用 Python 标准库中的 bisect 模块,该模块可以将元素添加到列表中、并保持排序顺序。

LISTS 列表

List 是一个动态数组,所以它可以使用调整大小操作,且它也支持动态更改。

如果有一个大小为 N 的列表 A,如果将新项目附加到列表 A,则 Python 会创建一个足够容纳 N 个元素以及更多元素的新列表。即,Python 中的列表的创建,不是分配能够容纳 N + 1 个元素的数组,而是分配能够容纳 M 个元素( M>N )的数组。当 Python 复制旧列表到新列表的时候,它会随即删除或销毁旧列表。我们建议在首次分配时请求额外的空间,以减少后续分配的次数 —— 出于内存复制的消耗系统资源之大,列表元素的增加会严重影响程序运行速度。

List 的分配方程

M = (N >> 3) + (3 if N < 9 else 6)

该图显示列表尺寸与额外元素的关系。例如,如果使用创建了一个包含 8000 个元素的列表,Python 将返回一个能够容纳大约8,600个元素的列表,也就是会多分配 600 个元素的空间!

当我们构建了一个列表并且添加元素时候,我们使用了 2.7 倍的内存。与创建列表相比,添加元素时候分配给列表的额外空间要大得多。

TUPLES 元组

元组是静态的,也就是说,一旦创建了元组,与列表不同,我们再也无法对其进行修改或调整其大小。

特性 1:静态性

>>> t = (1, 2, 3, 4)

>>> t[0] = 5

Traceback (most recent call last):

File "", line 1, in

TypeError: 'tuple' object does not support item assignment

特性 2:可连接性

>>> t1 = (1, 2, 3, 4)

>>> t2 = (5, 6, 7, 8)

>>> t1 + t2

(1, 2, 3, 4, 5, 6, 7, 8)

现在,如果我们考虑将连接操作与列表的 append 操作放在一起,一起使用,那么有趣的是,元组连接所花费的时间将会是 O(n),而列表所花费的时间为 O(1)。因为列表是追加元素的,所以列表中只要有多余的空间即可。对于元组,每当将一个新元素连接到现有元组时,它就会在不同的内存位置上创建一个新的元组,从而使连接花费 O(n) 时间(因为对于元组来说没有直接添加元素的方法可用)。

元组被认为是轻量的 —— 与列表不同,元组仅占用数据所需的内存。因此如果数据是静态的,我们建议使用元组。

使用元组的另一个好处是资源回收 —— Python 是支持垃圾回收的,这意味着,当我们不再使用某个变量的时候,它将释放其内存,并将其返回给系统,以便将该内存分配给其他应用程序或变量。对于元组,如果不再使用元组空间,则它将保留它的内存,并且如果将来需要该大小的内存,则 Python 而不是向系统寻求新的内存,而是分配 Python 自己保留下来的内存 —— 它极大程度上避免了向系统再度调用内存块。

List 和 Tuple 的实例

>>> %timeit l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

95 ns ± 1.87 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

>>> %timeit t = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

12.5 ns ± 0.199 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

列表和元组都有优点和缺点,但是重要的是要牢记它们的特性 —— 例如列表中的过度分配以及元组中的静态和缓存资源,同时将其用作可能的数据结构。

希望您喜欢阅读本文!

参考资料如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值