本文主要介绍二叉树的四种遍历方式:前序、中序、后序和层次。以下图为例,说明这四种遍历方式:
前序遍历(DLR):先访问根节点,后访问左子树,再访问右子树。根-左-右,例如:ABDCEFGH
中序遍历(LDR):先访问根节点,后访问左子树,再访问右子树。左-根-右,例如:BDAFEHGC
后序遍历(LRD):先访问根节点,后访问左子树,再访问右子树。左-右-根,例如:DBFHGECA
层次遍历:从根节点开始,从上到下,从左至右,依次访问每个节点。例如:ABCDEFGH
非递归遍历
前序遍历(DLR):先访问根节点,后访问左子树,再访问右子树。根-左-右,例如:ABDCEFGH
中序遍历(LDR):先访问根节点,后访问左子树,再访问右子树。左-根-右,例如:BDAFEHGC
后序遍历(LRD):先访问根节点,后访问左子树,再访问右子树。左-右-根,例如:DBFHGECA
层次遍历:从根节点开始,从上到下,从左至右,依次访问每个节点。例如:ABCDEFGH
0.定义
二叉树的二叉链表存储表示
typedef int ElemType;
typedef struct BiNode
{
ElemType data;
struct BiNode *lchild, *rchild;
}BiNode,*BiTree;
void visit(BiTree root)
{
if(NULL != root)
cout << root->data << endl;
}
1.先序遍历
递归遍历
void preOrder(BiTree root)
{
if(NULL != root)
{
visit(root);
preOrder(root->lchild);
preOrder(root->rchild);
}
}
非递归遍历
void preOrder(BiTree root)
{
stack<BiTree> s;
BiTree p = root;
while((NULL != p)|| !s.empty())
{
if( NULL != p)//访问根节点,根指针进栈,遍历左子树
{
visit(root);
s.push(p);
p = p->lchild;
}else//根指针出栈,遍历右子树
{
p = s.top();
s.pop();
p = p->rchild;
}
}
}
2.中序遍历
递归遍历
void inOrder(BiTree root)
{
if(NULL != root)
{
inOrder(root->lchild);
visit(root);
inOrder(root->rchild);
}
}
非递归遍历
void inOrder(BiTree root)
{
stack<BiTree> s;
BiTree p = root;
while(NULL != p || !s.empty())
{
if(NULL != p)//根指针进栈,遍历左子树
{
s.push(p);
p = p->lchild;
}else//访问根节点,根指针出栈,遍历右子树
{
p = s.top();
visit(p);
s.pop();
p = p->rchild;
}
}
}
3.后序遍历
递归遍历
void postOrder(BiTree root)
{
if(NULL != root)
{
postOrder(root->lchild);
postOrder(root->rchild);
visit(root);
}
}
非递归遍历
void postOrder(BiTree root)
{
stack<BiTree> s;//节点指针栈
stack<int> flag;//访问标记栈,0表示访问过左子树,1表示访问过右子树
BiTree p = root;
while((NULL != p) || !s.empty())
{
while(NULL != p)//一直访问左孩子,直到左孩子指针为空
{
s.push(p);//根指针p进栈
p = p->lchild;//p指向左孩子
flag.push(0);//表示访问过左子树
}
if(flag.top() == 1)//访问过右子树
{
p = s.top();
s.pop();//根指针出栈
visit(p);
flag.pop();//标记出栈
p = NULL;
}else//访问过左子树
{
p = s.top();//获取根指针
if(!s.empty())
{
p = p->rchild;//访问右子树
flag.pop();//更改访问标记
flag.push(1);//右子树已访问过
}
}
}
}
4.层次遍历
void levelOrder(BiTree root)
{
queue<BiTree> q;
BiTree p = root;
if(NULL == p)
return;
q.push(p);//根指针进队
while(!q.empty())
{
p = q.front();
q.pop();//根指针出队
visit(p);//访问根节点
if( NULL != p->lchild)//左孩子不空,进队
q.push(p->lchild);
else if(NULL != p->rchild)//右孩子不空,进队
q.push(p->rchild);
}
}