[转载]二叉树逆序遍历的迭代解法

来源:互联网 发布:imagelab mac 下载 编辑:程序博客网 时间:2024/05/22 16:41

原文地址:Binary Tree Post-Order Traversal Iterative Solution


从Hint开始翻译的,前面忽略……

通常,在树里没有父指针的情况下有必要使用基于堆栈的解法。试图理解下简单的逆序遍历二叉树的例子。什么时候应该输出一个节点的值?注意下什么情况是跑遍了整个树。试图用一个变量来存储上一个节点。他对我们爬遍这棵树有什么帮助?

 

解法:

         我们使用prev来存储遍历队列的前一个节点。假设curr为当前节点并在栈的顶端。当prev为curr的父节点时,我们开始向下爬树。在这种情况下,我们尝试去遍历curr的左孩子,如果存在的话(将左孩子压进栈里)。如果(左孩子)不存在,就对右孩子进行。如果左右孩子都不存在(即为叶子节点),输出curr的值并将它删除。

         如果prev是curr的左孩子节点,我们是在从左边向上爬树。我们看下curr的右孩子。尝试从右孩子向下遍历(即将右孩子压进栈),否则输出curr的值并将它移出栈。

         如果prev是curr的右孩子,则我们在从右边向上爬树。这种情况下,输出curr的值并将它移出栈。

void postOrderTraversalIterative(BinaryTree *root) {  if (!root) return;  stack<BinaryTree*> s;  s.push(root);  BinaryTree *prev = NULL;  while (!s.empty()) {    BinaryTree *curr = s.top();    // we are traversing down the tree    if (!prev || prev->left == curr || prev->right == curr) {      if (curr->left) {        s.push(curr->left);      } else if (curr->right) {        s.push(curr->right);      } else {        cout << curr->data << " ";        s.pop();      }    }     // we are traversing up the tree from the left    else if (curr->left == prev) {      if (curr->right) {        s.push(curr->right);      } else {        cout << curr->data << " ";        s.pop();      }    }    // we are traversing up the tree from the right    else if (curr->right == prev) {      cout << curr->data << " ";      s.pop();    }    prev = curr;  // record previously traversed node  }}


上面的方法比较容易理解,但是有一些冗余代码。我们可以重构掉冗余代码。现在他看起来更简洁了。注意下输出curr值部分的语句块是如何重构成一个单独的另一个语句块。只要迭代器在下次迭代能确保进入else语句块,就不用担心value不会被输出。

void postOrderTraversalIterative(BinaryTree*root) {  if(!root) return;  stack<BinaryTree*>s;  s.push(root);  BinaryTree*prev = NULL;  while(!s.empty()) {    BinaryTree*curr = s.top();    if(!prev || prev->left == curr || prev->right == curr) {      if(curr->left)        s.push(curr->left);      elseif (curr->right)        s.push(curr->right);    }else if (curr->left == prev) {      if(curr->right)        s.push(curr->right);    }else {      cout<< curr->data << " ";      s.pop();    }    prev= curr;  }}

替代解法:

一种替代解法是使用两个栈。尝试在一张纸上解决。我想这十分magical and beautiful。你会认为这种方法很魔幻,但实际上它确实做着逆序前置遍历的工作。也就是说,遍历的顺序是个节点,右孩子跟在左孩子后面。 This yields post-order traversal in reversed order.使用第二个栈可以将它反转为正确的顺序。

工作步骤:

将根节点压进第一个栈。

将节点从第一个栈删除,压进第二个栈。

然后将左孩子压进第一个栈(右孩子跟着)

重复第2、3步骤知道第一个栈为空。

一旦完成,第二个栈被反转好的所有节点。从第二个栈中一个一个移出节点,工作就完成了。

void postOrderTraversalIterativeTwoStacks(BinaryTree *root) {  if (!root) return;  stack<BinaryTree*> s;  stack<BinaryTree*> output;  s.push(root);  while (!s.empty()) {    BinaryTree *curr = s.top();    output.push(curr);    s.pop();    if (curr->left)      s.push(curr->left);    if (curr->right)      s.push(curr->right);  }  while (!output.empty()) {    cout << output.top()->data << " ";    output.pop();  }}


0 0
原创粉丝点击