打印二叉树中所有节点的祖先。我们可以在小于 O(n^2) 的时间复杂度内完成它吗?

Posted

技术标签:

【中文标题】打印二叉树中所有节点的祖先。我们可以在小于 O(n^2) 的时间复杂度内完成它吗?【英文标题】:Print ancestors of all nodes in a Binary Tree. Can we do it in less than O(n^2) time complexity? 【发布时间】:2016-05-30 15:54:23 【问题描述】:

这是在二叉树中打印特定节点的祖先的标准算法,它需要 O(n) 时间复杂度。

bool print(Node *node,int target)
    if(node==NULL)
       return false;
    if(node->target==target)
       return true;
    if(print(node->left)||print(node->right))
       cout << node->data;
       return true;
    
return false;

问题是我们是否需要打印所有节点的 的所有祖先,并将每个节点的祖先存储在一个数组中。时间复杂度是多少?我们能不能比 O(n^2) 做得更好,即不遍历每个节点并找到祖先。如果可能的话怎么做?

【问题讨论】:

未指定。以什么顺序?如果一个节点是多个节点的祖先,是否必须多次打印?而且您似乎没有假设树是平衡的。 这是一个非常奇怪的算法 - 使用从子到父的指针会容易得多。 执行此操作所需的时间与输出的大小成正比。对于 O(N log N) 的平衡树。对于不平衡的树,它是 O(N^2) @PeterG。我希望每个节点的所有祖先都分别在数组中。每个节点都应该有自己的数组。 @Alan Stokes 订单可能是从孩子到父母或父母到孩子。 【参考方案1】:

如果你想要一个 array 对应于树中的每个节点,那么你不能做得比 O(N2) 最坏的情况更好,因为所有的总大小arrays 是最坏的情况 O(N2) (在树中的每个节点最多有一个孩子的情况下)。如果您希望树在某种程度上是平衡的,这将减少到 O(N log N)。

您可以通过共享数据来实现 O(N) 构造,对每个节点使用链表而不是数组。实际上,这相当于为每个节点计算一个父链接,因为链表只是对父链接的遍历。但是您无法避免打印成本,因为当您打印出所有祖先链时,您将打印平均 O(N log N) / 最坏情况 O(N2) 个项目。

父链接构造算法与您介绍的算法基本相同:递归遍历设置子节点的父链接到当前节点的树。要打印每个节点的祖先链,您可以在遍历树时使用父链接。

【讨论】:

【参考方案2】:

它可以在O(n*h) 中完成,其中h 是树的高度,通过实现一个DFS,跟踪当前打开的节点。

类似 c++ 的简单伪代码可以是:

void PrintAll(const Node& node) 
  open = std::unordered_set<Node>;  // empty hash set
  PrintAll(node, &open);

void PrintAll(const Node& node, std::unordered_set* open) 
  if (node == null) 
     return;
  for (const Node& ancestor: open)
     cout << ancestor<< "," << node;
  open->add(node);
  PrintAll(node.left, open);
  PrintAll(node.right, open);
  open->remove(node);

警告:在这里,我们不打印(node, node)(每个节点也是它自己的祖先)。如果我们想这样做,可以通过在打印循环之前将node 添加到open 来轻松修复。 另外,您可以让unordered_set 只存储数据,而不是整个节点。

【讨论】:

【参考方案3】:

以下代码将完成这项工作:

使用语言:Java

//  Algorithm for printing the ancestors of a Node.
static boolean findAncestors(Node root, Node a)

    if(root==null)
    
        return false;
    
    else if(root==a)
    
        System.out.print("Printing ancestors of node " + a.data + " : " + a.data);
        return true;
    
    else
    
        boolean var=false;
        var=findAncestors(root.left, a);
        if(var)
        
            System.out.print(", " + root.data);
            return true;
        

        var=findAncestors(root.right, a);
        if(var)
        
            System.out.print(", " + root.data);
            return true;
        

    
    return false;

【讨论】:

以上是关于打印二叉树中所有节点的祖先。我们可以在小于 O(n^2) 的时间复杂度内完成它吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在任何二叉树中找到两个节点的最低共同祖先?

在二叉树中找到两个节点最近公共祖先

如果不是树中的所有这些节点,Python会在二叉树中找到两个节点的最低共同祖先

2022-05-22:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 pq,最近公共祖先表示为一个节点 x,满足 x 是 p

236. 二叉树的最近公共祖先[中等]

如何在任何二叉树中找到两个节点的最低共同祖先?