0

就在我坐下来写代码莫里斯序遍历我想这个例子,我有点困惑就如何在这种特殊情况下,它会工作:根据morris inorder,这棵树的下一步是什么?

 80 
    / \ 
    60  100 
    \  /
    70 90 
    /
    65 
/
63 
    \ 
    64 

第1步:

60 
    \ 
    70 
/ \ 
    65  80 
/  \ 
63  100 
\  /
    64  90 

据我所知,下一步70中的算法将成为65的正确孩子,那么60会发生什么?我很确定我错过了一些微不足道的东西,但不幸的是我无法将它放在手指上。

public void MorrisInorder() { 
    BSTNode<T> p = root, tmp; 
    while (p != null) 
     if (p.left == null) { 
      visit(p); 
      p = p.right; 
     } 
     else { 
      tmp = p.left; 
      while (tmp.right != null && // go to the rightmost node of 
        tmp.right != p) // the left subtree or 
        tmp = tmp.right; // to the temporary parent of p; 
      if (tmp.right == null) {// if 'true' rightmost node was 
        tmp.right = p;  // reached, make it a temporary 
        p = p.left;  // parent of the current root, 
      } 
      else {     // else a temporary parent has been 
        visit(p);   // found; visit node p and then cut 
        tmp.right = null; // the right pointer of the current 
        p = p.right;  // parent, whereby it ceases to be 
      }      // a parent; 
     } 
} 

代码我正在关注morris inorder遍历。

+0

我用于编码序遍历,而不是莫里斯序遍历而不同这样的事实它使用线程而不是堆栈或递归。我想问你,如果你明白基本的inorder遍历,或者你只能使用morris版本。 –

+0

@Setilă我很好地理解inorder遍历,并且我刚刚完成了对添加,删除,搜索方法的Threaded树的编码。我为morris inorder遵循的代码如上。 – ChrisOdney

回答

2

直接回答你的问题,我认为这个数字是不准确,你的情况的第1步,从节点“80”边缘节点“60”不应该被删除。步骤1中唯一的改变是将节点“70”的右点重定向到节点“80”(参见步骤1),这指示算法经过节点“80”的左子树之后的返回路径。

步骤1:

 80 
    /^ \ 
    60 | 100 
    \ | /
    70 90 
    /
    65 
/
63 
    \ 
    64 

添加来自节点“70”返回路径到节点“80”,作为当前节点“60”的左侧点之后为NULL,则当前节点将被设置作为节点“70”。同时,节点“65”的右侧点将被重定向到节点“70”

步骤2:

 80 
    /^ \ 
    60 | 100 
    \ | /
    70 90 
    /^ 
/| 
    65 
/
63 
    \ 
    64 

详情莫里斯的序遍历的代码被列为如下。

假设我们有一个节点结构等:

/* A binary tree tNode has data, pointer to left child 
and a pointer to right child */ 
struct tNode 
{ 
    int data; 
    struct tNode* left; 
    struct tNode* right; 
}; 

和遍历是:

/* Function to traverse binary tree without recursion and 
without stack */ 
void MorrisTraversal(struct tNode *root) 
{ 
    struct tNode *current,*pre; 

    if(root == NULL) 
    return; 

    current = root; 
    while(current != NULL) 
    { 
    /* This means there is no left sub-tree for current node, 
     then just print current node, and go to the right "child" node. 
     The right "child" node may be either its true child node, 
     or the returning path for "60" sub-tree (like "70" to "80") */ 
    if(current->left == NULL) 
    { 
     printf(" %d ", current->data); 
     current = current->right;  
    }  
    else 
    { 
     /* before going to the left sub-tree, we need to find a returning path 
     to current node (such as when current node is "80", and we want to 
     go to "60", so we need to save the returning path from left sub-tree 
     to "80"). It is easy to imagine that we need to return to the current 
     node when we arriving the right-most node of current left sub-tree. 
     Therefore, we just go to the right-most node (the first condition in 
     while) and set the returning path at "pre->right == NULL" block, as 
     well as updating the current node. Another situation is that when we 
     arrive at the left-most leaf node (if not exist, it means current->left 
     is NULL, and we won't go into this block), we have already set the right 
     point of left-most leaf node as the returning node (it un-satisfies the 
     second condition of while loop), and then we will recover the right 
     point of this leaf node in the next "else" block. 
      */ 
     pre = current->left; 
     while(pre->right != NULL && pre->right != current) 
     pre = pre->right; 

     /* Make current as right child of its inorder predecessor */ 
     if(pre->right == NULL) 
     { 
     pre->right = current; 
     current = current->left; 
     } 

     /* Revert the changes made in if part to restore the original 
     tree i.e., fix the right child of predecssor */ 
     else `enter code here` 
     { 
     pre->right = NULL; 
     printf(" %d ",current->data); 
     current = current->right;  
     } /* End of if condition pre->right == NULL */ 
    } /* End of if condition current->left == NULL*/ 
    } /* End of while */ 
} 
+0

我故意省略了右边的右边的孩子重定向,忘了在提问中提到。我认为我的代码中存在一个错误(使用代码编辑我的问题),在该代码之后使用该代码不会使所有节点成为某个其他节点的正确子节点。 – ChrisOdney

+0

我不知道“所有节点”是什么意思。该算法仅重定向每个分支中最右边节点的节点的右子节点(极端情况是某些节点没有右子节点,然后它们的非右子节点将它们的右点重定向到他们的父母直接)。 –

相关问题