二叉树遍历之非递归算法

Posted sole_cc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树遍历之非递归算法相关的知识,希望对你有一定的参考价值。

在前一篇文章二叉树遍历递归算法对二叉树遍历的递归算法做了总结,这篇文章就来对二叉树遍历的非递归算法做个汇总。还是与上一篇文章一样的顺序,一一汇总先序、中序、后序以及层序遍历的非递归算法。


1、先序遍历(非递归算法)

先序遍历非递归访问,使用即可实现。先序遍历的非递归访问在所有的遍历中算是最简单的了。主要思想就是先将根结点压入栈,然后根结点出栈并访问根结点,而后依次将根结点的右孩子、左孩子入栈,直到栈为空为止。代码如下:

[cpp] view plaincopy
  1. void preOrderIter(struct node *root)  
  2.   
  3.     if (root == NULL) return;  
  4.     stack<struct node *> s;  
  5.     s.push(root);  
  6.     while (!s.empty())   
  7.         struct node *nd = s.top();  
  8.         cout << nd->data << " ";  
  9.         s.pop();  
  10.         if (nd->right != NULL)  
  11.             s.push(nd->right);  
  12.         if (nd->left != NULL)  
  13.             s.push(nd->left);  
  14.       
  15.     cout << endl;  
  16.   

先序遍历的非递归算法另一算法,也是用的栈,只是稍微复杂点,当左子树遍历完后,需要回溯并遍历右子树。

[cpp] view plaincopy
  1. void preOrderIter2(struct node *root)  
  2.   
  3.     stack<struct node *> s;  
  4.     while (root != NULL || !s.empty())   
  5.         if (root != NULL)   
  6.             cout << root->data << " "//访问结点并入栈  
  7.             s.push(root);                
  8.             root = root->left;         //访问左子树  
  9.          else   
  10.             root = s.top();            //回溯至父亲结点  
  11.             s.pop();  
  12.             root = root->right;        //访问右子树  
  13.           
  14.       
  15.     cout << endl;  
  16.   
本算法有一个地方要注意的是,每次从栈中pop出结点时,表示该结点以及该的左子树已经访问完了,接下来访问其右子树。

2、中序遍历(非递归算法)(数据结构的课本上有算法可以参考,此处给出的算法和课本上的不一样

中序遍历非递归算法也是采用栈实现,与上面的先序遍历算法2类似,只是访问根结点的时机不同。

[cpp] view plaincopy
  1. void inOrderIter(struct node *root)  
  2.   
  3.     stack<struct node *> s;  
  4.     while (root != NULL || !s.empty())   
  5.         if (root != NULL)   
  6.             s.push(root);  
  7.             root = root->left;  
  8.           
  9.         else   
  10.             root = s.top();  
  11.             cout << root->data << " ";  //访问完左子树后才访问根结点  
  12.             s.pop();  
  13.             root = root->right;        //访问右子树  
  14.           
  15.       
  16.     cout << endl;  
  17.   

当然,中序遍历非递归算法还有很多种,比如修改二叉树结点结构加入一个字段来标示结点是否被访问过等,但是都比该算法复杂,且修改了原来的二叉树结构,所以在这里就不啰嗦了,有兴趣的可以移步这里二叉树非递归访问,后续如果有时间我会对二叉树遍历非递归算法通过在结点添加一个标记的方法再做一个总结。


3、后序遍历(非递归算法)

后序遍历的非递归算法较复杂,使用一个栈可以实现,但是过程很繁琐,这里可以巧妙的用两个栈来实现后序遍历的非递归算法。注意到后序遍历可以看作是下面遍历的逆过程:即先遍历某个结点,然后遍历其右孩子,然后遍历其左孩子。这个过程逆过来就是后序遍历。算法步骤如下:

  1. Push根结点到第一个栈s中。
  2. 从第一个栈s中Pop出一个结点,并将其Push到第二个栈output中。
  3. 然后Push结点的左孩子和右孩子到第一个栈s中。
  4. 重复过程2和3直到栈s为空。
  5. 完成后,所有结点已经Push到栈output中,且按照后序遍历的顺序存放,直接全部Pop出来即是二叉树后序遍历结果。

[cpp] view plaincopy
  1. void postOrderIter(struct node *root)  
  2.   
  3.     if (!root) return;  
  4.     stack<struct node*> s, output;  
  5.     s.push(root);  
  6.     while (!s.empty())   
  7.         struct node *curr = s.top();  
  8.         output.push(curr);  
  9.         s.pop();  
  10.         if (curr->left)  
  11.             s.push(curr->left);  
  12.         if (curr->right)  
  13.             s.push(curr->right);  
  14.       
  15.       
  16.     while (!output.empty())   
  17.         cout << output.top()->data << " ";  
  18.         output.pop();  
  19.       
  20.     cout << endl;  
  21.   

4、层序遍历(非递归算法)

如果不考虑分层换行打印,则用一个队列可以很容易的通过非递归实现层序遍历。但是要每打印一层换一行,就显得稍微复杂了一点。可以有两种方法,第一种使用两个队列,代码很简练,第二种方法则是使用一个队列,代码稍显复杂。

方法一:使用两个队列

第一个队列currentLevel用于存储当前层的结点,第二个队列nextLevel用于存储下一层的结点。当前层currentLevel为空时,表示这一层已经遍历完成,可以打印换行符了。

然后将第一个空的队列currentLevel与队列nextLevel交换,然后重复该过程直到结束。这个算法比较好理解。

[cpp] view plaincopy
  1. void levelOrderIter(struct node* root)  
  2.   
  3.     if (!root) return;  
  4.     queue<struct node *> currentLevel, nextLevel;  
  5.     currentLevel.push(root);  
  6.     while (!currentLevel.empty())   
  7.         struct node *currNode = currentLevel.front();  
  8.         currentLevel.pop();  
  9.         if (currNode)   
  10.             cout << currNode->data << " ";  
  11.             nextLevel.push(currNode->left);  
  12.             nextLevel.push(currNode->right);  
  13.           
  14.         if (currentLevel.empty())   
  15.             cout << endl;  
  16.             swap(currentLevel, nextLevel);  
  17.           
  18.       
  19.   
  20. 二叉树中序遍历(递归和非递归)算法C语言实现

    java 二叉树 深度优先递归遍历

    数据结构二叉树的基础操作( 1.创建二叉树2.先序遍历3.中序排序4.后序遍历 5.层序遍历6. 统计节点的数目 7.交换左右子树 8.计算并输出该二叉树的深度)

    递归遍历二叉树

    二叉树几种遍历算法的非递归实现

    二叉树的递归遍历