二叉树递归(非递归)实现先序、中序、后序遍历(附代码)

今天说好的不碰代码的,后来还是没忍住,学了学数据结构和算法,就先讲讲先序中序和后序遍历吧,我还写了代码,一套递归方式实现遍历二叉树,还有两套非递归方式遍历二叉树,

从简单的开始,因为二叉树的所有操作都是要求在能够遍历的基础上啊。

学过数据结构的肯定都明白遍历顺序,

先序遍历就是先自己,然后左子树,然后右子树,

中序遍历就是先左子树,然后自己,然后右子树

后序遍历就是先左子树,然后右子树,然后自己

比如上图这个很简单的二叉树:

先序遍历:1 2 4 5 3 6 7

中序遍历:4 2 5 1 6 3 7

后序遍历:4 5 2 6 7 3 1

具体的遍历方法就是我们上面说的啊。

不说了,我们用代码实现:

先说简单的递归:

class Node //树的节点,没有用c++的模板,我们只说算法,模板慢慢来{public:int data;Node *pLeft = NULL;Node *pRight = NULL;};

Node *pRoot;//简单粗暴的方法初始化一棵树,重点不在这,大家自己进行脑补Node s1;Node s2;Node s3;Node s4;Node s5;Node s6;Node s7;s1.data = 1;s2.data = 2;s3.data = 3;s4.data = 4;s5.data = 5;s6.data = 6;s7.data = 7;pRoot = &s1;s1.pLeft = &s2;s1.pRight = &s3;s2.pLeft = &s4;s2.pRight = &s5;s3.pLeft = &s6;s3.pRight = &s7;接下来才是重点:

void qiandigui(Node *pRoot)//递归方法,先序遍历二叉树{if (pRoot == nullptr){return;}cout << pRoot->data << " ";if (pRoot->pLeft != nullptr){qiandigui(pRoot->pLeft);}if (pRoot->pRight != nullptr){qiandigui(pRoot->pRight);}}void zhongdigui(Node *pRoot)<span style="white-space:pre"></span><span style="font-family: Arial, Helvetica, sans-serif;">//递归方法,中序遍历二叉树</span>{if (pRoot == nullptr){return;}if (pRoot->pLeft != nullptr){zhongdigui(pRoot->pLeft);}cout << pRoot->data << " ";if (pRoot->pRight != nullptr){zhongdigui(pRoot->pRight);}}void houdigui(Node *pRoot)<span style="white-space:pre"></span>//递归方法,后序遍历二叉树{if (pRoot == nullptr){return;}if (pRoot->pLeft != nullptr){houdigui(pRoot->pLeft);}if (pRoot->pRight != nullptr){houdigui(pRoot->pRight);}cout << pRoot->data << " ";}下面开始非递归算法:

注意:和别人的博客不太一样的是,非递归算法,我这里有两套,一套是我自己开始写的,感觉还好,大家可以看看,也可以给我提提意见,还有一套是网上很流行的。

我们先从网上流行的开始:

void stackxianpopulance(Node *pRoot)<span style="white-space:pre"></span>//非递归方法,先序遍历二叉树{stack<Node *> mystack;Node *pnow = pRoot;while (pnow != nullptr || false == mystack.empty()){while (pnow){cout << pnow->data << " ";mystack.push(pnow);pnow = pnow->pLeft;}pnow = mystack.top();mystack.pop();pnow = pnow->pRight;}}void stackzhongpopulance(Node *pRoot)<span style="white-space:pre"></span>//非递归方法,中序遍历二叉树{stack<Node *> mystack;Node *pnow = pRoot;while (pnow != nullptr || false == mystack.empty()){while (pnow){mystack.push(pnow);pnow = pnow->pLeft;}pnow = mystack.top();mystack.pop();cout << pnow->data << " ";pnow = pnow->pRight;}}由于这个后序二叉树,在遍历完左子树后要找到右子树,所以网上很流行的版本今天很晚了,就偷了懒,没有实现,因为博主明天还要考试啊,实现完了估计又到夜里了,

所以就网上找一份给大家看看,为了临时的顶上来:

前序、中序、后序的非递归遍历中,要数后序最为麻烦,如果只在栈中保留指向结点的指针,那是不够的,必须有一些额外的信息存放在栈中。方法有很多,这里只举一种,先定义栈结点的数据结构typedef struct{Node * p; int rvisited;}SNode //Node 是二叉树的结点结构,rvisited==1代表p所指向的结点的右结点已被访问过。lastOrderTraverse(BiTree bt){  //首先,从根节点开始,往左下方走,一直走到头,将路径上的每一个结点入栈。  p = bt;  while(bt){    push(bt, 0); //push到栈中两个信息,一是结点指针,一是其右结点是否被访问过    bt = bt.lchild;  }  //然后进入循环体  while(!Stack.empty()){ //只要栈非空    sn = Stack.getTop(); // sn是栈顶结点    //注意,任意一个结点N,只要他有左孩子,则在N入栈之后,N的左孩子必然也跟着入栈了(这个体现在算法的后半部分),所以当我们拿到栈顶元素的时候,可以确信这个元素要么没有左孩子,要么其左孩子已经被访问过,所以此时我们就不关心它的左孩子了,我们只关心其右孩子。    //若其右孩子已经被访问过,或是该元素没有右孩子,则由后序遍历的定义,此时可以visit这个结点了。    if(!sn.p.rchild || sn.rvisited){      p = pop();      visit(p);    }    else //若它的右孩子存在且rvisited为0,说明以前还没有动过它的右孩子,于是就去处理一下其右孩子。    {       //此时我们要从其右孩子结点开始一直往左下方走,直至走到尽头,将这条路径上的所有结点都入栈。      //当然,入栈之前要先将该结点的rvisited设成1,因为其右孩子的入栈意味着它的右孩子必将先于它被访问(这很好理解,因为我们总是从栈顶取出元素来进行visit)。由此可知,下一次该元素再处于栈顶时,其右孩子必然已被visit过了,所以此处可以将rvisited设置为1。      sn.rvisited = 1;      //往左下方走到尽头,将路径上所有元素入栈      p = sn.p.rchild;      while(p != 0){        push(p, 0);        p = p.lchild;      }    }//这一轮循环已结束,刚刚入栈的那些结点我们不必管它了,下一轮循环会将这些结点照顾的很好。  }}上面这位大哥的代码我们就这么ctrl+c,ctrl+v粘贴过来了,还请那位,如果看见了就算了啊,没准你也是这么来的呢,哈哈。。。

接下来呢,这一套是我自己写的,不知道合不合大家胃口,大家看一看吧,感觉这个改动起来要比上面的populance版本改动起来要好的多啊,比如前序改中序,后序改前序,等等。

废话少说,贴代码:

谁也不跟谁一辈子,有些事情没必要记在心上。

二叉树递归(非递归)实现先序、中序、后序遍历(附代码)

相关文章:

你感兴趣的文章:

标签云: