python中对列表的复制操作(浅拷贝与深拷贝)

python中对列表的复制操作用的比较广泛,之前写过一篇博客Python:复制列表,禁止函数修改列表(副本,切片表示法[:])详细讲述了python中的 [:] 操作,但是 [:] 操作仅仅只是浅拷贝,具有很大的局限性。

一:[:] 浅拷贝操作

用法(path和num都是数组):

 path = num[:] 

如 path = num[:] 中,
path只会创建num的浅层副本,即只复制num中的元素的引用,而不会复制嵌套对象本身。
什么意思呢?简单举例来说:
如果num是一维数组的话,浅拷贝与深拷贝一样,对数组path怎样操作都影响不到数组num。

path修改元素(num值不变):
在这里插入图片描述

如果num是二维或二维以上的数组的话,path只会复制num数组的表面,如果修改path中的元素,原始列表num中的对应元素也会被修改。但是,如果你对path整体进行修改(例如path.append([3,3])),则不会影响原始列表num。

path修改元素(num也会改变):
在这里插入图片描述

path增加元素(num值不变):
在这里插入图片描述

所以 [:] 浅拷贝的缺陷很明显,一旦拷贝嵌套列表(二维及二维以上),对复制的列表进行修改操作会影响原列表,无法恢复。

二:copy()浅拷贝操作:

这里主要扩充一下copy()函数的知识点,copy()函数的用法是:path = num.copy()。

path = num.copy()

path = num.copy() 与 path = num[:] 操作一样

这种方式也是对列表进行浅拷贝操作。它会创建一个新的列表path,但是该列表中的元素依然是原始列表num中元素的引用。因此,和path = num[:]一样,对path中的元素的修改会影响原始列表num中的对应元素,但对path整体的修改不会影响原始列表num。

三:标准库函数copy.deepcopy() 深拷贝(蓝桥杯可用)

用法:

import copy

path = copy.deepcopy(num)

这种方式是对列表进行深拷贝操作。它会递归地复制原始列表num及其内部的所有对象,包括嵌套的列表、字典等。这样,创建的新列表path与原始列表num完全独立,对其中一个对象的修改不会影响另一个对象。深拷贝操作确保了复制后的对象与原始对象完全独立,是最安全的复制方式。

如图所示:
在这里插入图片描述

总结:

在 Python 中,如果a是一个数组,copy.deepcopy(a)a.copy() 都是用于复制对象的方法,但它们的行为和时间复杂度是有差异的。具体差异和时间复杂度的分析如下:

1. b = a.copy()

a.copy()浅拷贝 方法。它创建了一个新的对象,并将原对象的引用传递给这个新对象。这意味着,对于嵌套的可变对象(例如列表中的列表),浅拷贝仅仅复制了这些对象的引用,而没有复制嵌套对象本身。

时间复杂度:
  • 对于 可变对象(例如列表、字典等):

    • 如果 a 是一个 列表,那么 a.copy() 只会创建一个新的列表对象,但列表中的元素(如果是可变对象)仍然指向原来的对象。因此,对于列表中的每个元素,都是复制其引用,没有递归复制
    • 这个操作的时间复杂度是 O(n),其中 n 是 a 中元素的数量,因为只需要复制一层结构。

    示例:

    a = [1, 2, 3]
    b = a.copy()  # 创建一个浅拷贝
    
  • 对于 字典,也是类似的,a.copy() 只会复制字典的键值对的引用,而不会递归复制键值对中的对象。

    • 时间复杂度同样是 O(n),其中 n 是字典中的元素数量。
总结:
  • a.copy() 的时间复杂度是 O(n),其中 n 是对象中的元素数量。
  • 它仅创建了一层新结构,而没有递归地复制嵌套对象。

2. b = copy.deepcopy(a)

copy.deepcopy(a)深拷贝 方法。它会递归地复制 a 中的所有对象,包括嵌套的对象,直到没有更深层的对象为止。这意味着深拷贝会完全复制整个对象及其嵌套的所有内容,而不再引用原始对象。

时间复杂度:
  • 深拷贝会递归地遍历整个对象的结构(包括所有嵌套的对象)。对于每一个 可变对象(如列表、字典、集合等),都会创建一个新的对象,并递归地复制其中的元素。
  • 假设 a 是一个包含嵌套结构的对象(如列表中的列表、字典中的字典等),则深拷贝的时间复杂度通常取决于 对象的嵌套深度和元素数量
  • 如果对象是树形结构,深拷贝的时间复杂度是 O(m),其中 m 是对象中的所有元素(包括嵌套对象中的元素)。但是深拷贝需要访问并复制每一个元素,因此它的时间复杂度是 O(m),而 m 是对象中所有元素的总数(包括嵌套结构的元素)。
举个例子:
import copy
a = [[1, 2], [3, 4], [5, 6]]
b = copy.deepcopy(a)  # 递归复制整个嵌套列表

在这个例子中,copy.deepcopy 会递归地复制每个嵌套列表。

总结:
  • copy.deepcopy(a) 的时间复杂度是 O(m),其中 m 是对象中所有元素的总数量,包括嵌套对象的元素。
  • 它递归地复制整个对象的所有内容,确保所有对象都是新创建的副本,不会与原始对象共享引用。

总结对比:

方法时间复杂度说明
a.copy()O(n)仅复制对象的第一层结构,嵌套的对象仍然引用原对象,因此适用于不含深层嵌套的对象或不需要复制嵌套对象的场景。
copy.deepcopy(a)O(m)递归地复制对象及其嵌套的所有内容,适用于需要完全独立副本的情况,其中 m 是所有元素的总数量。
  • 浅拷贝 (a.copy()) 适用于结构比较简单或不需要修改嵌套结构的情况,时间复杂度较低。
  • 深拷贝 (copy.deepcopy(a)) 适用于需要完全独立副本,且包含嵌套结构的情况,但时间复杂度较高,因为需要递归地复制每一层的内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不染_是非

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值