实现迭代单栈二进制树复制函数

时间:2017-01-12 10:16:06

标签: algorithm data-structures binary-tree binary-search-tree

作为思考练习,我试图实现迭代树(二进制或二叉搜索树)复制功能。

我的理解是,它可以通过以下方式实现:

  • 只有一个堆栈
  • 不使用包装器(包含对副本和原始节点的引用)
  • 没有节点引用它的父节点(节点中的父节点引用是否与树的真实定义相反[我认为是DAG]?)

我编写了不同的实现来满足上述约束的反转,但我不确定如何使用约束来解决问题。

我没有在算法4 / e中看到任何内容,也没有在网上看到任何东西(超出它的微不足道的陈述)。我考虑使用当前/之前var的顺序和发布顺序的概念,但是在弹出堆栈时我没有看到准确跟踪的方法。我还简要地考虑了哈希映射,但我觉得这仍然只是额外的存储空间。

感谢任何有助于理解我没有看到的方法背后的概念/习语的帮助。

提前致谢。

修改

对我迄今为止尝试过的一些要求。这是2堆栈解决方案,我认为应该能够最简单地转换为1堆栈。

用C ++编写。我是语言新手(但不是编程),并使用C ++ Primer 5 / e(Lippman,Lajole,Moo)[C ++ 11]和互联网自学。如果语言角度的任何代码有误,请告诉我(虽然我知道Code Review Stack Exchange是进行实际审核的地方)。

我有一个模板节点,由代码的其他部分使用。

template<typename T>
struct Node;

typedef Node<std::string> tree_node;
typedef std::shared_ptr<tree_node> shared_ptr_node;

template<typename T>
struct Node final {

public:
    const T value;
    const shared_ptr_node &left = m_left;
    const shared_ptr_node &right = m_right;

    Node(const T value, const shared_ptr_node left = nullptr, const shared_ptr_node right = nullptr) : value(value), m_left(left), m_right (right) {}

    void updateLeft(const shared_ptr_node node) {
        m_left = node;
    }

    void updateRight(const shared_ptr_node node) {
        m_right = node;
    }

private:
    shared_ptr_node m_left;
    shared_ptr_node m_right;
};

然后是2堆栈实现。

shared_ptr_node iterativeCopy2Stacks(const shared_ptr_node &node) {

    const shared_ptr_node newRoot = std::make_shared<tree_node>(node->value);

    std::stack<const shared_ptr_node> s;
    s.push(node);

    std::stack<const shared_ptr_node> copyS;
    copyS.push(newRoot);

    shared_ptr_node original = nullptr;
    shared_ptr_node copy = nullptr;

    while (!s.empty()) {

        original = s.top();
        s.pop();

        copy = copyS.top();
        copyS.pop();

        if (original->right) {
            s.push(original->right);

            copy->updateRight(std::make_shared<tree_node>(original->right->value));
            copyS.push(copy->right);
        }

        if (original->left) {
            s.push(original->left);

            copy->updateLeft(std::make_shared<tree_node>(original->left->value));
            copyS.push(copy->left);
        }
    }

    return newRoot;
}

1 个答案:

答案 0 :(得分:1)

我不熟悉c ++,所以你必须解决伪代码问题:

node copy(treenode n):
    if n == null
        return null

    node tmp = clone(n) //no deep clone!!!

    stack s
    s.push(tmp)

    while !s.empty():
        node n = s.pop()

        if n.left != null:
            n.left = clone(n.left)
            s.push(n.left)
        if n.right != null:
            n.right = clone(n.right)
            s.push(n.right)

    return tmp

请注意,clone(node) 不是深层克隆。基本思想是从根的浅层克隆开始,然后迭代该节点的所有子节点并用浅拷贝替换那些节点(仍然引用原始节点),替换那些节点子节点等。这个算法遍历以DFS方式的树。如果您更喜欢BFS(无论出于何种原因),您只需用队列替换堆栈即可。这段代码的另一个优点是:它可以通过一些小的改动来改变,以适应任意树。

这个算法的递归版本(如果你更喜欢我可怕的prosa上的递归代码):

node copyRec(node n):
    if n.left != null:
        n.left = clone(n.left)
        copyRec(n.left)

    if n.right != null:
        n.right = clone(n.right)
        copyRec(n.right)

    return n

node copy(node n):
    return copyRec(clone(n))

编辑:
如果你想查看工作代码,我在python中创建了一个implementation