二叉树的递归&非递归遍历及其他函数功能的实现

来源:互联网 发布:和女生网络聊天用语 编辑:程序博客网 时间:2024/05/18 01:31

二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序,中序,后序以及层序四种遍历方法。因为树的定义本身就是递归定义,所以前三种遍历方式采用递归不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。层序的实现则要用到队列里的“先进先出”的原理来实现。

先来介绍一下要实现的函数:

template<class T>class BinaryTree{typedef BinaryTreeNode<T> Node; public:BinaryTree():_root(NULL){}BinaryTree(const T* a,size_t size,const T& invalid);BinaryTree(const BinaryTree<T>& b);BinaryTree& operator=(const BinaryTree<T>& b);~BinaryTree();void PrevOrder();     //前序遍历void InOrder();       //中序遍历void PostOrder();    //后序遍历void LevelOrder();   //队列实现层序遍历void PrevOrder_NonR();     //非递归前序遍历void InOrder_NonR();       //非递归中序遍历void PostOrder_NonR();     //非递归后序遍历size_t Size();         //元素个数size_t Depth();        //深度size_t LeafSize();     //叶子节点个数size_t GetKLevel(size_t k);    //求第k层的节点个数Node* FindNode(const T& d=T())      //找某个数字的节点位置{return _FindNode(_root,d);}

1.前序

遍历过程是:根节点---左子树---右子树


(1)递归实现:

template<class T>void BinaryTree<T>::PrevOrder()     //前序遍历{_PrevOrder(_root);}template<class T>void BinaryTree<T>::_PrevOrder(Node* root){//根节点--左子树--右子树if(NULL==root){return;}cout<<root->_data<<" ";_PrevOrder(root->_left);_PrevOrder((root->_right));}


(2)非递归实现:

根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,可看做是一个根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问完其左子树时,再访问它的右子树。过程如下:

对于任一当前结点cur:

1)访问结点cur,并将结点cur入栈;

2)判断结点cur的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点cur,再进入循环);若不为空,则将cur的左孩子置为当前的结点cur并压入栈中;

3)直到cur为NULL并且栈为空,则遍历结束。


template<class T>void BinaryTree<T>::PrevOrder_NonR()     //非递归前序遍历{//根节点--左子树--右子树stack< Node* > s;    //存放Node*节点Node* cur=_root;while(cur||!s.empty()){  while(cur){cout<<cur->_data<<" ";s.push(cur);cur=cur->_left;}//走完while循环后表示左子树已访问完Node* top=s.top();s.pop();cur=top->_right;}}

2.中序

遍历过程:左子树---根节点---右子树

(1)递归实现:

template<class T>void BinaryTree<T>::InOrder()      //中序遍历{_InOrder(_root);}template<class T>void BinaryTree<T>::_InOrder(Node* root)        {//左子树--根节点--右子树if(NULL==root){return ;}else{_InOrder(root->_left);cout<<root->_data<<" ";_InOrder(root->_right);}}

(2)非递归实现:

根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。过程如下:

对于任一结点cur

1)若其左孩子不为空,则将cur入栈并将cur的左孩子置为当前的cur,然后对当前结点cur再进行相同的处理;

2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的cur置为栈顶结点的右孩子;

3)直到cur为NULL并且栈为空则遍历结束


测试用例:int a[10]={1,2,3,'#','#',4,'#','#',5,6};

template<class T>void BinaryTree<T>::InOrder_NonR()   //非递归中序遍历{stack< Node* > s;Node* cur=_root;while(cur||!s.empty()){//中序遍历(出栈)是3,2,4,1,6,5while(cur){s.push(cur);cur=cur->_left;      }cur=s.top();cout<<cur->_data<<" ";s.pop();               cur=cur->_right;//入栈顺序先是1 2 3,然后3没有左孩子出了while循环后先输出3并返回到上一级2处,//此时cur指针指向右子树,再次进入while循环,由于2的右节点不为空,所以压入4,//然后打印2,再打印2的右节点4,4的左右节点均为空时返回到1处并输出,此时栈为空//但当前节点(指向的是1的右节点)不为空,所以压入5,5的左节点不为空再压入6,然//后pop出6,5}}

3.后序

遍历过程:左子树---右子树---根节点

(1)递归实现:

template<class T>void BinaryTree<T>::PostOrder()     //后序遍历{_PostOrder(_root);}template<class T>void BinaryTree<T>::_PostOrder(Node* root){//左子树--右子树--根节点if(NULL==root){return;}else{_PostOrder(root->_left);_PostOrder(root->_right);cout<<root->_data<<" ";}}


(2)非递归实现:

这种遍历方式的非递归其实还是不好想的,要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点cur,先将其入栈。如果cur不存在左孩子和右孩子,则可以直接访问它;或者cur存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将cur的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

以下图来分析一下它的过程:



首先将1入栈,cur指向栈顶元素1,不满足pop条件,然后依次push进5,2;此时栈顶元素为2(cur指向),仍然不满足pop条件,再次压入2的右孩子,左孩子,此时栈中为1 5 2 4 3,栈顶元素为3,满足其左右孩子为空的条件,进行pop 3,然后cur指向4,prev指向3,再次进行pop 4的操作,此时cur指向2,prev指向4,进行pop 2,

此时栈中只剩下1,cur指向它,不满足往下执行,push进5,cur指向5,还是不满足往下执行,push进6,此时满足pop条件进行pop 6,prev指向6,依然满足pop条件,再次pop 5pop 1就结束了。


template<class T>void BinaryTree<T>::PostOrder_NonR()   //非递归后序遍历{//后序遍历是先左再右再根节点  (出栈)3,4,2,6,5,1Node* cur=_root;Node* prev=NULL;stack<Node*> s;s.push(cur);while (!s.empty()){cur=s.top();if((cur->_left==NULL && cur->_right==NULL)||(prev!=NULL)&& (prev==cur->_left || prev==cur->_right)){cout<<cur->_data<<" ";s.pop();prev=cur;}else{if (cur->_right){s.push(cur->_right);}if(cur->_left){s.push(cur->_left);}}}}


4.层序

拿上图来说,层序就是1---2---5---3---4---6

对于层序遍历,需要借助队列的“先进先出”的特点来实现,下面是代码实现:

template<class T>void BinaryTree<T>::LevelOrder()    //层序遍历{//利用队列的“先进先出”的特点if(NULL==_root){return ;}queue<Node*> q;         //队列,存放Node*类型的节点Node* cur=_root;q.push(cur);   //如果根节点不为空,则将其根节点(第一层)push进去while(!q.empty()){cur=q.front();cout<<cur->_data<<" ";q.pop();if(cur->_left){q.push(cur->_left);}if(cur->_right){q.push(cur->_right);}}cout<<endl;}



下面是整个实现过程:

Binarytree.h

#pragma once#include<iostream>#include<queue>#include<stack>#include<assert.h>using namespace std;template<class T>struct BinaryTreeNode{BinaryTreeNode(const T& d):_data(d),_left(NULL),_right(NULL){}T _data;BinaryTreeNode<T>* _left;BinaryTreeNode<T>* _right;};template<class T>class BinaryTree{typedef BinaryTreeNode<T> Node; public:BinaryTree():_root(NULL){}BinaryTree(const T* a,size_t size,const T& invalid);BinaryTree(const BinaryTree<T>& b);BinaryTree& operator=(const BinaryTree<T>& b);~BinaryTree();void PrevOrder();     //前序遍历void InOrder();       //中序遍历void PostOrder();    //后序遍历void LevelOrder();   //队列实现层序遍历void PrevOrder_NonR();     //非递归前序遍历void InOrder_NonR();       //非递归中序遍历void PostOrder_NonR();     //非递归后序遍历size_t Size();         //元素个数size_t Depth();        //深度size_t LeafSize();     //叶子节点个数size_t GetKLevel(size_t k);    //求第k层的节点个数Node* FindNode(const T& d=T())      //找某个数字的节点位置{return _FindNode(_root,d);}    public:Node* _CreateBinaryTree(const T* a,size_t size,const T& invalid,size_t& index);    Node* _CopyBinaryTree(Node* root);    void _Destroy(Node* root);void _PrevOrder(Node* root);    void _InOrder(Node* root);void _PostOrder(Node* root);size_t _Size(Node* root);size_t _Depth(Node* root);size_t _LeafSize(Node* root);size_t _GetKLevel(size_t k,Node* root);Node* _FindNode(Node* root,const T& d){if (NULL==root){return NULL;}if (root->_data==d){return root;}Node* ret=_FindNode(root->_left,d);     if(NULL==ret){ret=_FindNode(root->_right,d);   //左子树没找到再去右子树找}return ret;}protected:Node* _root;};template<class T>BinaryTree<T>::BinaryTree(const T* a,size_t size,const T& invalid){size_t index=0;_root=_CreateBinaryTree(a,size,invalid,index);}template<class T>BinaryTreeNode<T>* BinaryTree<T>::_CreateBinaryTree(const T* a,size_t size,const T& invalid,size_t& index){assert(a);    Node* root=NULL;if(index<size && a[index]!=invalid){root=new Node(a[index]);      root->_left=_CreateBinaryTree(a,size,invalid,++index);//创建左子树root->_right=_CreateBinaryTree(a,size,invalid,++index);//创建右子树}return root;}template<class T>BinaryTree<T>::BinaryTree(const BinaryTree<T>& b){_root=_CopyBinaryTree(b._root);}template<class T>BinaryTreeNode<T>* BinaryTree<T>::_CopyBinaryTree(Node* root){Node* newroot=NULL;if(root){newroot=new Node(root->_data);        newroot->_left=(_CopyBinaryTree(root->_left));newroot->_right=(_CopyBinaryTree(root->_right));}return newroot;}//传统写法//template<class T>//BinaryTree<T>& BinaryTree<T>::operator=(const BinaryTree<T>& b)//{//if(this!=&b)//{//Node* tmp=_CopyBinaryTree(b._root);//_Destroy(_root);//_root=tmp;//}//return *this;//}//现代写法template<class T>BinaryTree<T>& BinaryTree<T>::operator=(const BinaryTree<T>& b){if(this!=&b){BinaryTree<T> tmp(b);std::swap(_root,tmp._root);}return *this;}template<class T>BinaryTree<T>::~BinaryTree(){_Destroy(_root);_root=NULL;}template<class T>void BinaryTree<T>::_Destroy(Node* root){Node* cur=root;while(cur){_Destroy(cur->_left);_Destroy(cur->_right);delete cur;cur=NULL;}}template<class T>void BinaryTree<T>::PrevOrder()     //前序遍历{_PrevOrder(_root);}template<class T>void BinaryTree<T>::_PrevOrder(Node* root){//根节点--左子树--右子树if(NULL==root){return;}cout<<root->_data<<" ";_PrevOrder(root->_left);_PrevOrder((root->_right));}template<class T>void BinaryTree<T>::InOrder()      //中序遍历{_InOrder(_root);}template<class T>void BinaryTree<T>::_InOrder(Node* root)        {//左子树--根节点--右子树if(NULL==root){return ;}else{_InOrder(root->_left);cout<<root->_data<<" ";_InOrder(root->_right);}}template<class T>void BinaryTree<T>::PostOrder()     //后序遍历{_PostOrder(_root);}template<class T>void BinaryTree<T>::_PostOrder(Node* root){//左子树--右子树--根节点if(NULL==root){return;}else{_PostOrder(root->_left);_PostOrder(root->_right);cout<<root->_data<<" ";}}template<class T>void BinaryTree<T>::LevelOrder()    //层序遍历{//利用队列的“先进先出”的特点if(NULL==_root){return ;}queue<Node*> q;         //队列,存放Node*类型的节点Node* cur=_root;q.push(cur);   //如果根节点不为空,则将其根节点(第一层)push进去while(!q.empty()){cur=q.front();cout<<cur->_data<<" ";q.pop();if(cur->_left){q.push(cur->_left);}if(cur->_right){q.push(cur->_right);}}cout<<endl;}template<class T>void BinaryTree<T>::PrevOrder_NonR()     //非递归前序遍历{//根节点--左子树--右子树stack< Node* > s;    //存放Node*节点Node* cur=_root;while(cur||!s.empty()){  while(cur){cout<<cur->_data<<" ";s.push(cur);cur=cur->_left;}//走完while循环后表示左子树已访问完Node* top=s.top();s.pop();cur=top->_right;}}template<class T>void BinaryTree<T>::InOrder_NonR()   //非递归中序遍历{stack< Node* > s;Node* cur=_root;while(cur||!s.empty()){//中序遍历(出栈)是3,2,4,1,6,5while(cur){s.push(cur);cur=cur->_left;      }cur=s.top();cout<<cur->_data<<" ";s.pop();               cur=cur->_right;//入栈顺序先是1 2 3,然后3没有左孩子出了while循环后先输出3并返回到上一级2处,//此时cur指针指向右子树,再次进入while循环,由于2的右节点不为空,所以压入4,//然后打印2,再打印2的右节点4,4的左右节点均为空时返回到1处并输出,此时栈为空//但当前节点(指向的是1的右节点)不为空,所以压入5,5的左节点不为空再压入6,然//后pop出6,5}}template<class T>void BinaryTree<T>::PostOrder_NonR()   //非递归后序遍历{//后序遍历是先左再右再根节点  (出栈)3,4,2,6,5,1Node* cur=_root;Node* prev=NULL;stack<Node*> s;s.push(cur);while (!s.empty()){cur=s.top();if((cur->_left==NULL && cur->_right==NULL)||(prev!=NULL)&& (prev==cur->_left || prev==cur->_right)){cout<<cur->_data<<" ";s.pop();prev=cur;}else{if (cur->_right){s.push(cur->_right);}if(cur->_left){s.push(cur->_left);}}}}template<class T>size_t BinaryTree<T>::Size()   //元素个数{return _Size(_root);}template<class T>size_t BinaryTree<T>::_Size(Node* root)         {static size_t count=0;if(NULL==root){return 0;}_Size(root->_left);++count;          //count的位置不同类似三种遍历方式_Size(root->_right);return count;//if (NULL==root)//{//return 0;//}//return _Size(root->_left)+_Size(root->_right)+1;}template<class T>size_t BinaryTree<T>::Depth()        //深度{return _Depth(_root);}template<class T>size_t BinaryTree<T>::_Depth(Node* root)        {if (NULL==root){return 0;}size_t LeftDepth=_Depth(root->_left);size_t RightDepth=_Depth(root->_right);return LeftDepth>RightDepth ? LeftDepth+1:RightDepth+1;//if(LeftDepth>RightDepth)//{//return LeftDepth+1;  //把根节点算上//}//else//{//return RightDepth+1;//}}template<class T>size_t BinaryTree<T>::LeafSize()     //叶子节点个数{return _LeafSize(_root);}template<class T>size_t BinaryTree<T>::_LeafSize(Node* root)     //叶子节点个数{//叶子节点就是该节点没有左右孩子的节点if(NULL==root){return 0;}else if(root->_left==NULL && root->_right==NULL){return 1;     //返回值形式,递归一次返1,}else{return _LeafSize(root->_left)+_LeafSize(root->_right);}}template<class T>size_t BinaryTree<T>::GetKLevel(size_t k)  //第k层节点个数    {return _GetKLevel(k,_root);}template<class T>size_t BinaryTree<T>::_GetKLevel(size_t k,Node* root)    {assert(k>0);if(NULL==root){return 0;}if(k==1)          {return 1;}size_t leftsz=_GetKLevel(k-1,root->_left);size_t rightsz=_GetKLevel(k-1,root->_right);return leftsz+rightsz;}

test.cpp

#include"binarytree.h"void test(){int a[10]={1,2,3,'#','#',4,'#','#',5,6};BinaryTree<int> b1(a,10,'#');cout<<"前序:";b1.PrevOrder();cout<<endl;cout<<"中序:";b1.InOrder();cout<<endl;cout<<"后序:";    b1.PostOrder();cout<<endl;cout<<"层序:";b1.LevelOrder();cout<<endl;cout<<"非递归前序:";b1.PrevOrder_NonR();cout<<endl;cout<<"非递归中序:";b1.InOrder_NonR();cout<<endl;cout<<"非递归后序:";b1.PostOrder_NonR();cout<<endl;cout<<"b1.Size:"<<b1.Size()<<endl;cout<<"b1.Depth:"<<b1.Depth()<<endl;cout<<"b1.LeafSize:"<<b1.LeafSize()<<endl;cout<<"b1.GetKLevel:"<<b1.GetKLevel(2)<<endl;BinaryTree<int> b2(b1);cout<<"调拷贝构造,前序遍历:";b2.PrevOrder();cout<<endl;BinaryTree<int> b3;b3=b1;cout<<"调赋值操作,前序遍历:";b3.PrevOrder();cout<<endl;cout<<"调赋值操作,中序遍历:";b3.InOrder();cout<<endl;       }void test1(){int a[10]={1,2,3,'#','#',4,'#','#',5,6};BinaryTree<int> b1(a,10,'#');BinaryTreeNode<int> *ret=b1.FindNode(6);assert(ret);cout<<"FindNode6:"<<ret->_data<<endl;    ret=b1.FindNode(8);cout<<"FindeNode8:"<<ret<<endl;   //找不到输出地址00000000}int main(){test();test1();system("pause");return 0;}







0 0
原创粉丝点击