C++ 按升序遍历树

C++ 按升序遍历树,c++,recursion,binary-tree,C++,Recursion,Binary Tree,首先,我想知道这是否是一个定义良好的操作:我们首先访问树的所有叶子(从左到右)。然后我们拜访所有的叶子的父母(从左到右)。然后那些父母的所有父母,等等。。。直到最后一个未访问的节点被访问为止。请注意,根节点不一定是最后访问的节点。如果某位家长已经被拜访过,我们干脆忽略它。我想不出一个反例,这个遍历会失败 所以假设它是定义明确的。进行这种遍历最有效的算法是什么?为了简化伪代码,我们可以假设它是一个二叉树。先拿到所有的叶子已经很费时了。但与此同时,我们可以通过在获取叶子时将双亲存储在某个位置来提取每

首先,我想知道这是否是一个定义良好的操作:我们首先访问树的所有叶子(从左到右)。然后我们拜访所有的叶子的父母(从左到右)。然后那些父母的所有父母,等等。。。直到最后一个未访问的节点被访问为止。请注意,根节点不一定是最后访问的节点。如果某位家长已经被拜访过,我们干脆忽略它。我想不出一个反例,这个遍历会失败

所以假设它是定义明确的。进行这种遍历最有效的算法是什么?为了简化伪代码,我们可以假设它是一个二叉树。先拿到所有的叶子已经很费时了。但与此同时,我们可以通过在获取叶子时将双亲存储在某个位置来提取每个连续的双亲。然后我们访问这些父母列表,每个列表在树中比上一个列表高一代。像这样的?我只知道C++,但可以找出其他语言的伪代码。 获取二叉树的所有叶子(已测试):

模板
内联void二进制树::获取叶(const std::shared_ptr&node,
标准::列表和叶子)常数{
如果(!节点)
返回;
如果(节点->isLeaf())
返回叶子。放置回(节点);
获取叶子(节点->左,叶子);
获取叶(节点->右侧,叶);
}
虽然叶子的双亲可以很容易地从这个列表中存储,并将双亲列表传递给其他人,但是所有后续的双亲呢

template <typename T, typename Comparator>
inline void BinaryTree<T, Comparator>::obtainLeaves (const std::shared_ptr<Node>& node,
std::list<std::shared_ptr<Node>>& leaves, std::set<std::shared_ptr<Node>>& parents) const {
    if (!node)
        return;
    if (node->isLeaf()) {
        leaves.emplace_back(node);
        parents.emplace(node->parent);
        return;
    }
    obtainLeaves(node->left, leaves, parents);
    obtainLeaves(node->right, leaves, parents);
}
模板
内联void二进制树::获取叶(const std::shared_ptr&node,
标准::列表和叶,标准::集合和父项)常量{
如果(!节点)
返回;
如果(节点->isLeaf()){
叶。后侵位(节点);
父节点.安放(节点->父节点);
返回;
}
获取叶子(节点->左侧,叶子,父节点);
获取叶子(节点->右侧,叶子,父节点);
}

或者,与其一次性完成,不如先拿树叶。然后通过调用
->parent
来迭代叶列表以获取它们的父对象。然后对这些父母重复这个过程,以此类推。但对我来说,这似乎非常笨拙和耗时,而且也不能很好地检查重复情况。

简单而正确的解决方案:

建造一棵倒立的树。在遍历时,保持一组指向根的反向链接

创建树叶的向量。这样做时,请在哈希映射中记录它们的指针值。现在走吧

现在,对于向量中的每个元素,将其替换为其父元素。并将其添加到哈希映射中。如果hash映射中已经有,则忽略它

重复这个过程,直到你的父母都用完了


这可能不是最佳解决方案。

简单而正确的解决方案:

建造一棵倒立的树。在遍历时,保持一组指向根的反向链接

创建树叶的向量。这样做时,请在哈希映射中记录它们的指针值。现在走吧

现在,对于向量中的每个元素,将其替换为其父元素。并将其添加到哈希映射中。如果hash映射中已经有,则忽略它

重复这个过程,直到你的父母都用完了


这可能不是最优的。

我测试了以下各项,证明它们工作正常。我不知道它的时间复杂度与雅克的解决方案相比如何,甚至不知道它的时间复杂度是多少。我知道每个非叶节点在这里至少被访问两次,这不是一件好事

template <typename T, typename Comparator>
template <typename F, typename... Args>
inline void BinaryTree<T, Comparator>::traverseUpwards (F f, Args&&... args) const {
    std::list<std::shared_ptr<Node>> leaves;
    const std::size_t N = heightOfTree();
    std::vector<std::list<std::shared_ptr<Node>>> parents(N);
    std::set<std::shared_ptr<Node>> alreadyVisited;
    traverseUpwards(root, leaves, parents, alreadyVisited);
    for (const std::shared_ptr<Node>& node : leaves)
        f(node, std::forward<Args>(args)...);
    for (std::size_t i = 0; i < N; i++) {
        for (const std::shared_ptr<Node>& node : parents[i])
            f(node, std::forward<Args>(args)...);
    }
}

template <typename T, typename Comparator>
inline void BinaryTree<T, Comparator>::traverseUpwards (const std::shared_ptr<Node>& node,
std::list<std::shared_ptr<Node>>& leaves,
std::vector<std::list<std::shared_ptr<Node>>>& parents,
std::set<std::shared_ptr<Node>>& alreadyVisited) const {
    if (!node)
        return;
    if (node->isLeaf()) {  // e.g. (!node->left && !node->right) for a binary tree.
        leaves.emplace_back(node);
        std::shared_ptr<Node> p = node->parent;
        std::size_t i = 0;
        while (p && alreadyVisited.find(p) == alreadyVisited.end()) {
            parents[i++].emplace_back(p);
            alreadyVisited.emplace(p);
            p = p->parent;
        }
    }
    traverseUpwards(node->left, leaves, parents, alreadyVisited);
    traverseUpwards(node->right, leaves, parents, alreadyVisited);
}

template <typename T, typename Comparator>
inline int BinaryTree<T, Comparator>::heightOfTree (const std::shared_ptr<Node>& node) const {
    return node ? std::max (heightOfTree(node->left), heightOfTree(node->right)) + 1 : -1;
}
模板
模板
内联void BinaryTree::traverseUpwards(F,Args&…Args)常量{
std::列出叶子;
常数std::size_t N=树的高度();
std::载体亲本(N);
std::设置已访问;
横向(根、叶、亲本、已观察到);
for(const std::shared_ptr&node:leaves)
f(节点,标准::转发(参数)…);
对于(std::size\u t i=0;iisLeaf()){//例如二叉树的(!node->left&&&!node->right)。
叶。后侵位(节点);
std::shared_ptr p=node->parent;
标准:尺寸i=0;
while(p&&alreadyVisited.find(p)=alreadyVisited.end()){
父母[i++].emplace_back(p);
就位(p);
p=p->parent;
}
}
向上遍历(节点->左侧,叶,父节点,已访问);
向上遍历(节点->右侧,叶,父节点,已访问);
}
模板
内联int二进制树::heightOfTree(const std::shared_ptr&node)const{
返回节点?std::max(树的高度(节点->左),树的高度(节点->右))+1:-1;
}

我测试了以下各项是否正常工作。我不知道它的时间复杂度与雅克的解决方案相比如何,甚至不知道它的时间复杂度是多少。我知道每个非叶节点在这里至少被访问两次,这不是一件好事

template <typename T, typename Comparator>
template <typename F, typename... Args>
inline void BinaryTree<T, Comparator>::traverseUpwards (F f, Args&&... args) const {
    std::list<std::shared_ptr<Node>> leaves;
    const std::size_t N = heightOfTree();
    std::vector<std::list<std::shared_ptr<Node>>> parents(N);
    std::set<std::shared_ptr<Node>> alreadyVisited;
    traverseUpwards(root, leaves, parents, alreadyVisited);
    for (const std::shared_ptr<Node>& node : leaves)
        f(node, std::forward<Args>(args)...);
    for (std::size_t i = 0; i < N; i++) {
        for (const std::shared_ptr<Node>& node : parents[i])
            f(node, std::forward<Args>(args)...);
    }
}

template <typename T, typename Comparator>
inline void BinaryTree<T, Comparator>::traverseUpwards (const std::shared_ptr<Node>& node,
std::list<std::shared_ptr<Node>>& leaves,
std::vector<std::list<std::shared_ptr<Node>>>& parents,
std::set<std::shared_ptr<Node>>& alreadyVisited) const {
    if (!node)
        return;
    if (node->isLeaf()) {  // e.g. (!node->left && !node->right) for a binary tree.
        leaves.emplace_back(node);
        std::shared_ptr<Node> p = node->parent;
        std::size_t i = 0;
        while (p && alreadyVisited.find(p) == alreadyVisited.end()) {
            parents[i++].emplace_back(p);
            alreadyVisited.emplace(p);
            p = p->parent;
        }
    }
    traverseUpwards(node->left, leaves, parents, alreadyVisited);
    traverseUpwards(node->right, leaves, parents, alreadyVisited);
}

template <typename T, typename Comparator>
inline int BinaryTree<T, Comparator>::heightOfTree (const std::shared_ptr<Node>& node) const {
    return node ? std::max (heightOfTree(node->left), heightOfTree(node->right)) + 1 : -1;
}
模板
模板
内联void BinaryTree::traverseUpwards(F,Args&…Args)常量{
std::列出叶子;
常数std::size_t N=树的高度();
std::载体亲本(N);
std::设置已访问;
横向(根、叶、亲本、已观察到);
for(const std::shared_ptr&node:leaves)
f(节点,标准::转发(参数)…);
对于(std::size\u t i=0;iisLeaf()){//例如(!node->l