返回

递归调用深拷贝的栈空间风险

前端

爆栈引起的对深拷贝理解

面对庞大数据,递归式深拷贝极易爆栈,风险在于函数调用栈帧无限扩张 。每一次递归调用都会在栈中创建新的栈帧,而递归深度与数据规模正相关。当数据量超出栈容量,就会发生爆栈错误。

如何避免爆栈?

解决爆栈的关键在于控制递归调用深度 。以下方法可行:

  • 迭代代替递归: 将递归算法转换为迭代算法,避免函数调用栈的增长。
  • 限制递归深度: 通过外部变量或参数对递归调用深度设置上限。

对深拷贝的理解

爆栈问题凸显了深拷贝与浅拷贝的本质区别。

  • 浅拷贝: 仅复制对象引用,浅拷贝后的对象与原对象共享底层数据。修改副本会同时影响原对象。
  • 深拷贝: 复制整个对象及其所有子对象,深拷贝后的对象独立于原对象,修改副本不会影响原对象。

递归式深拷贝 是一种利用递归算法遍历对象并生成新对象的深拷贝方法。

示例:

考虑一个包含嵌套列表的列表:

original_list = [[1, 2], [3, 4, [5, 6]]]

递归式深拷贝:

import copy

def deep_copy(obj):
    if isinstance(obj, list):
        return [deep_copy(x) for x in obj]
    else:
        return copy.copy(obj)

new_list = deep_copy(original_list)

避免爆栈:

为了避免爆栈,可以通过以下方式限制递归深度:

  • 设置递归深度上限:
def deep_copy(obj, depth=0):
    if depth > 10:  # 设置递归深度上限为 10
        return copy.copy(obj)
    if isinstance(obj, list):
        return [deep_copy(x, depth + 1) for x in obj]
    else:
        return copy.copy(obj)
  • 使用迭代器:
def deep_copy(obj):
    stack = [obj]
    visited = set()
    new_objects = []

    while stack:
        current_obj = stack.pop()
        if current_obj in visited:
            continue

        visited.add(current_obj)

        if isinstance(current_obj, list):
            new_list = []
            new_objects.append(new_list)
            stack.append(new_list)
            for item in current_obj:
                stack.append(item)
        else:
            new_objects.append(copy.copy(current_obj))

    return new_objects[0]