二叉树的遍历非递归

来源:互联网 发布:计算机数据单位 编辑:程序博客网 时间:2024/06/01 09:11

题目:给定一颗二叉树,如下图:


要求:

前序遍历输出结果:1 2 4 6 7 5 9 10 3 8

中序遍历输出结果:6 4 7 2 9 5 10  1 3 8

后序遍历输出结果:6 7 4 9 10 5 2 8 3 1

结构如下:

struct Node
{
Node(int val)
:_left(NULL)
,_right(NULL)
,_val(val)
{}
Node* _left;
Node* _right;
int _val;
};


前序遍历

分析:
前序遍历的递归定义:先根节点,后左子树,再右子树。有了中序遍历的基础,不用我再像中序遍历那样引导了吧。
首先,我们遍历左子树,边遍历边打印,并把根节点存入栈中,以后需借助这些节点进入右子树开启新一轮的循环。还得重复一句:所有的节点都可看做是根节点。

void PrevSort_Tree(Node* root)//前序遍历{assert(root);if(root->_left ==NULL&&root->_right ==NULL){cout<<root->_val;return ;}Node* cur=root;stack<Node*> s;s.push(root);while (!s.empty())  //循环结束条件与前两种不一样{cout << cur->_val <<" ";/*栈的特点:先进后出先被访问的根节点的右子树后被访问*/if (cur->_right )s.push(cur->_right );if (cur->_left )cur = cur->_left ;else{//左子树访问完了,访问右子树cur= s.top();s.pop();}}cout << endl;}


中序遍历:
中序遍历的递归定义:先左子树,后根节点,再右子树。如何写非递归代码呢?一句话:让代码跟着思维走。我们的思维是什么?思维就是中序遍历的路径。假设,你面前有一棵二叉树,现要求你写出它的中序遍历序列。如果你对中序遍历理解透彻的话,你肯定先找到左子树的最下边的节点。

void InSort_Tree(Node* root){assert(root);if(root->_left ==NULL&&root->_right ==NULL){cout<<root->_val;return ;}Node* cur=root;stack<Node*> s;while (!s.empty()||cur)  //循环结束条件与前两种不一样{while(cur){s.push(cur);cur = cur->_left ;}if(!s.empty()){//左子树访问完了,访问右子树cur= s.top();s.pop();cout<<cur->_val <<" ";cur=cur->_right ;}}cout << endl;}


后续遍历:
后序遍历递归定义:先左子树,后右子树,再根节点。后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;若是位于右子树,则直接访问根节点。
void PostOrderTraverse(Node* root)//非递归后序遍历,用一个标记标记右子树是否访问过  {   if (root == NULL)               return;      stack<Node*> s;  //pCur:当前访问节点,pLastVisit:上次访问节点      Node* pCur, *pLastVisit;      pCur = root;      pLastVisit = NULL;          while (pCur)  //先把pCur移动到左子树最下边      {          s.push(pCur);          pCur = pCur->_left ;      }      while (!s.empty())  //走到这里,pCur都是空,//并已经遍历到左子树底端(看成扩充二叉树,则空,亦是某棵树的左孩子)      {                  pCur = s.top();          s.pop();          //一个根节点被访问的前提是:无右子树或右子树已被访问过          if (pCur->_right  == NULL || pCur->_right  == pLastVisit)          {              cout << pCur->_val <<" ";              //修改最近被访问的节点              pLastVisit = pCur;          }          /*这里的else语句可换成带条件的else if:         else if (pCur->lchild == pLastVisit)//若左子树刚被访问过,则需先进入右子树(根节点需再次入栈)         因为:上面的条件没通过就一定是下面的条件满足。仔细想想!         */          else          {              //根节点再次入栈              s.push(pCur);              //进入右子树,且可肯定右子树一定不为空              pCur = pCur->_right ;              while (pCur)              {                  s.push(pCur);                  pCur = pCur->_left ;              }          }      }      cout << endl;                                                                                                                     }  


代码测试如下:
void test1(){BinaryTree t;Node* node1=new Node(1);Node* node2=new Node(2);Node* node3=new Node(3);Node* node4=new Node(4);Node* node5=new Node(5);Node* node6=new Node(6);Node* node7=new Node(7);Node* node8=new Node(8);Node* node9=new Node(9);Node* node10=new Node(10);node1->_left=node2;node1->_right=node3;node2->_left=node4;node2->_right=node5;node3->_left =node8;node4->_left =node6;node4->_right=node7;node5->_left =node9;node5->_right =node10;cout<<"PrevSort:";t.PrevSort_Tree(node1);cout<<"InSort:";t.InSort_Tree(node1);cout<<"PostSort:";t.PostOrderTraverse(node1);}int main(){test1();system("pause");return 0;}


测试结果:


层序遍历详见博客:http://blog.csdn.net/wodeqingtian1234/article/details/75646566

原创粉丝点击