二叉树的遍历定义
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
其中搜索路线我们这里介绍4中:前序遍历,中序遍历,后续遍历,层次遍历。
前序遍历
若二叉树非空,则依次执行如下操作:
⑴ 访问根结点;
⑵ 遍历左子树;
⑶ 遍历右子树
该二叉树遍历结果为:G D A F E M H Z
递归算法
//定义结构体下面通用
typedef struct BTNode
{
Elemtype data;
BTNode *lchild;
BTNode *rchild;
}BTNode;
/*
递归遍历算法写起来比较简单根据前序遍历步骤即可
*/
void PreOrder(BTNode *p)
{
if(p != NULL)
{
cout<<p->data<<" ";
PreOrder(p->lchild);
PreOrder(p->rchild);
}
}
非归算法
void NicePreOrder(BTNode *p)
{
if(p == NULL) return;
stack<BTNode *>st;
st.push(p);
while(!st.empty())
{
p = st.top();
st.pop();
cout<<p->data<<" ";
if(p->rchild != NULL)
st.push(p->rchild);
if(p->lchild != NULL)
st.push(p->lchild);
}
}
中序遍历
若二叉树非空,则依次执行如下操作:
⑴ 遍历左子树;
⑵ 访问根结点;
⑶ 遍历右子树
该二叉树遍历结果为:A D E F G H M Z
递归算法
/*
递归遍历算法写起来比较简单根据中序遍历步骤即可
*/
void InOrder(BTNode *p)
{
if(p!= NULL)
{
PreOrder(p->lchild);
cout<<p->data<<" ";
PreOrder(p->rchild);
}
}
非递归算法
/*该算法核心思想就是先一路向左将所有结点压栈,
最后判断当前结点其是否有右孩子有的话就压栈没
有则取栈顶元素打印并且弹出。*/
void NiceInOrder(BTNode *p)
{
if(p == NULL) return;
stack<BTNode *>st;
while(p != NULL || !st.empty())
{
while(p != NULL)
{
st.push(p);
p = p->lchild;
}
p = st.top();
st.pop();
cout<<p->data<<" ";
p = p->rchild;
}
}
后序遍历
若二叉树非空,则依次执行如下操作:
⑴ 遍历左子树;
⑵ 遍历右子树;
⑶ 访问根结点
该二叉树遍历结果为:A E F D H Z M G
递归算法
/*
递归遍历算法写起来比较简单根据后序遍历步骤即可
*/
void PastOrder(BTNode *p)
{
if(p!= NULL)
{
PreOrder(p->lchild);
PreOrder(p->rchild);
cout<<p->data<<" ";
}
}
非递归算法(两个栈)
/*因为后序遍历的根节点在最后访问,所以需要用两个栈来实现
stRes用来存储结果最终将里面的所有元素打印,值得注意的是
因为我们用到了两个栈,所以先将左孩子压栈,再压右孩子,这
样就使得压入stRes中时先压右再压左,打印的时候也就符合后
序遍历的规则了*/
void NicePastOrder(BTNode *p)
{
if(p == NULL) return;
stack<BTNode *>st;
stack<BTNode *>stRes;
st.push(p);
while(!st.empty())
{
p = st.top();
st.pop();
stRes.push(p);
if(p->lchild != NULL)
st.push(p->lchild);
if(p->rchild != NULL)
st.push(p->rchild);
}
while(!stRes.empty())
{
p = stRes.top();
cout<<p->data<<" ";
stRes.pop();
}
}
非递归算法(带标志位的一个栈)
/*
只使用一个栈便可以达到后序非递归遍历大大节省了内存消耗,因为后序
遍历是先左再右再根,所以我们需要知道右孩子什么时候被打印,接下来
才可以打印根结点。其中我们设置标志位为tag,将每次打印后的结点设
置为标志位,用以判断p->rchild是否和tag相等来选择是否该打印此时
的根节点。
*/
void NicePastOrder2(BTNode *p)
{
if(p == NULL) return;
stack<BTNode *>st;
BTNode *tag = NULL;
while(p != NULL || !st.empty())
{
while(p != NULL)
{
st.push(p);
p = p->lchild;
}
p = st.top();
st.pop();
if(p->rchild == NULL || p->rchild == tag)
{
cout<<p->data<<" ";
tag = p;
p = NULL;
}
else
{
st.push(p);
p = p->rchild;
}
}
}
层次遍历
若二叉树非空,则依次执行如下操作:
逐层,从左向右访问节点
该二叉树遍历结果为:G D M A F H Z E
递归算法
/*
层次遍历的递归采用的是广度优先遍历,我们在LevelOrder中进行递归调用
当层数为0时打印,再在levelOrder中将每层最终结果打印
*/
void LevelOrder(BTNode *p,int level)
{
if(p == NULL) return;
if(level == 0)
cout<<p->data<<" ";
LevelOrder(p->lchild,level-1);
LevelOrder(p->rchild,level-1);
}
void levelOrder(BTNode *p,int level)
{
for(int i=0 ;i<=level; i++)
LevelOrder(p,i);
}
非递归算法
/*
非递归层序遍历比较简单,我们利用队列的性质即可,先将左孩子入队,
再将右孩子入队,然后进行打印
*/
void NiceLevelOrder(BTNode *p)
{
if(p == NULL) return;
queue<BTNode *>qu;
qu.push(p);
while(!qu.empty())
{
p = qu.front();
cout<<p->data<<" ";
qu.pop();
if(p->lchild != NULL)
qu.push(p->lchild);
if(p->rchild != NULL)
qu.push(p->rchild);
}
}