【问题标题】:Binary Trees -- Tracing through code二叉树——通过代码追踪
【发布时间】:2011-05-25 13:25:55
【问题描述】:

给定下图所示的二叉树,假设调用函数 A(root),确定访问下图所示二叉树节点的顺序。假设树节点和指针的定义如图所示。假设 root 是指向包含 60 的节点的指针。 我对这个问题的回答如下。这是正确的吗?我做错了什么?

                                   60
                                 /    \
                                30     90
                               /  \   / 
                              5   38  77
                               \  /  / \
                               8 32 62  88



struct treeNode{
  int data;
  struct treeNode *left, *right:
  {

struct treeNode *tree_ptr;

void A(struct treeNode *node_ptr){
    if (node_ptr != NULL){
    printf(“%d ,”,node_ptr->data);
    B(node_ptr->left);
    B(node_ptr->right);
   }   
}

void B(struct treeNode *node_ptr){
    if (node_ptr != NULL) {
    A(node_ptr->left);
    printf(“%d ,”,node_ptr->data);
    A(node_ptr->right);
   }
 }   

答案: 在 void A 它说首先打印 node_ptr-> data 所以 60 被打印 然后函数调用 B(node_ptr->left) 然后在 B 内,A 被调用 (node_ptr->left) 然后你打印那个数据是 5。然后 A(node_ptr->right) 被调用回到 A,打印该数据,以便打印 8。现在我不太确定下一步该做什么,但从逻辑上讲,打印 30 是有意义的,但我不确定 ptr 如何从 8 变为 30。然后如果你继续以相同的模式打印 38 并打印 32。 对于右子树... 90 77 62 88

【问题讨论】:

  • 你应该把它标记为homework
  • AFAIK homework 标签已被劝阻。
  • 给出的代码无法编译。你到底是什么意思?
  • @Vivin 也许,但如果一个问题被诚实地标记为这样,我更有可能适当地改变我的答案。
  • @nmichaels 基本上是提供的代码,因此决定了打印出元素的顺序。我只是想验证一下我是否正确

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


【解决方案1】:

上述跟踪对于预购或订单中的情况均不正确 Pre - 60 , 30, 5, 8 35 32 等 在 - 5、8、30、32、35 等

【讨论】:

    【解决方案2】:

    A 是前序遍历,而B 是有序遍历。

    确定打印顺序的一种简单方法是查看您如何访问节点本身。我通常在树的外部画一个轮廓(从根开始,根据你首先遍历的子树向左或向右移动)。如果我正在执行预购遍历,那么每当我沿着它的外部移动时,我都会打印出一个节点。如果我正在执行有序遍历,则仅当我将节点移动到 时才会打印出一个节点(当您查看有序遍历时,这是有道理的,因为您最终会先打印叶子;它们是您在绘制轮廓时移动的第一个节点)。如果我正在执行后序遍历,则仅当我沿着其inside移动时才打印出一个节点。

    更新

    在 5 和 8 之后打印出 30 的原因是您没有执行纯粹的前序遍历。您正在预购和有序遍历之间跳跃。

    确定顺序的一种简单方法是实际写下您的代码在跟踪时所经历的步骤(我经常使用钢笔/铅笔和纸将信息放在一起)。例如,你可以写出这样的调用堆栈:

    A(60)
      printf(60)
      call B(60.left)
        B(30)
          call A(30.left)
            A(5)
              printf(5)
              call B(5.left)
                B(null)
              call B(5.right)
                B(8)
                  call A(8.left)
                    A(null)
                  printf(8)
                  call A(8.right)
                    A(null)
          printf(30)
          call A(30.right)
            A(38)
            ...
    

    您可以轻松查看节点的打印顺序,更重要的是,您可以看到为什么从打印 8“跳”到打印 30(一个递归调用已经结束,您正在回退一级)。

    【讨论】:

    • 这真的很有帮助。谢谢。但是,如果我在预订时打印一个节点,每当我沿着它的外部移动时,这如何解释 30 在 5 和 8 之后打印出来。
    • @Krysten 我已经更新了我的答案,向您展示了调用堆栈。这应该可以解释为什么你从 8 点“跳”到 30 点。
    • 谢谢。我正在处理调用堆栈,但一直迷路。这应该会有很大帮助。
    • 在 A(5) printf(5) 之后调用 B(5.left),我认为在打印 5 之后就转到下一条语句 A(node_ptr->right ) 是 8,然后你打印它。看起来你有它,你回到 A() 并重复 B(node_ptr->left)
    【解决方案3】:

    首先,您的代码中存在大量错误。我猜它应该更像这样:

    struct treeNode{
      int data;
      struct treeNode *left, *right;
    }
    
    treeNode *tree_ptr;
    
    void A(treeNode *node_ptr){
        if (node_ptr != NULL){  /// this could be just if(node_ptr)
            printf(“%d ,”,node_ptr->data);
            B(node_ptr->left);
            B(node_ptr->right);
        }   
    }
    
    void B(treeNode *node_ptr){
        if (node_ptr != NULL) {
            A(node_ptr->left);
            printf(“%d ,”,node_ptr->data);
            A(node_ptr->right);
        }
    }   
    

    您还混合了两种不同的遍历算法。 A() 已预订,B() 已订购。 A()B() 应该称呼自己,而不是互相称呼。 (使用真实变量/函数名称而不是 AB 等的另一个原因。)

    【讨论】:

    • 我认为问题的重点是A和B应该互相调用,以测试学生对代码如何工作的理解。
    • @Anon 哦。这更有意义,尽管从(错误的不可编译的)问题中并不明显。
    【解决方案4】:

    随着时间的推移写出完整的执行堆栈。像这样:

    A(60)
      printf
      B(30)
        A(5)
          ...
        printf
        A(38)
          ...
      B(90)
        ...
    

    (树的其余部分留给读者作为练习。)

    然后从上到下,写下 printf 语句的结果。

    【讨论】:

      猜你喜欢
      • 2015-08-02
      • 1970-01-01
      • 2011-11-28
      • 2013-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-07
      • 1970-01-01
      相关资源
      最近更新 更多