二叉树
二叉树是比较常用的数据结构之一,二叉树的遍历则有前序遍历,中序遍历、后序遍历以及层序遍历四种方法。前三种的遍历方法是根据树根被访问的顺序而命名的。
我们把二叉树的左、中、右节点分别用L、V和R来表示,那么按照访问次序其实可以有六种访问顺序,分别为LVR、LRV、RVL、RLV、VLR和VRL。在这个基础上,我们规定左子树的访问必须在右子树之前,也就有了前序、中序以及后序遍历:VLR、LVR、LRV。
二叉树的定义
首先定义二叉树的定义:
using Position = struct Node*;
using BinTree = Position;
struct Node
{
DataType data;
BinTree left;
BinTree right;
}
二叉树的遍历
前序遍历
前序遍历的过程为:
①访问根节点;
②前序访问其左子树;
③前序访问其右子树。
其实现可以用递归和非递归两种方式来实现,下面分别介绍两种实现方式。
递归方式
void preOrderTravel(BinTree BT)
{
if(BT != nullptr)
{
cout<<BT->data<<endl;
preOrderTravel(BT->left);
preOrderTravel(BT->right);
}
}
非递归方式
void preOrderTravel(BinTree BT)
{
BinTree t;
stack<BinTree> s;
t = BT;
while(t || !s.empty())
{
if(t)
{
cout<<t->data;
s.push(t)
t = t->left;
}
else if(!s.empty())
{
t = s.top();
s.pop();
t = t->right;
}
}
}
从非递归的遍历方式可以看出,当以前序的方式遍历时,每遇到一个节点,首先输出它的值,然后把它入栈,最后令该节点等于该节点的左子树。
中序遍历
递归方式
void inOrderTravel(BinTree BT)
{
if(BT)
{
inOrderTravel(BT->left);
cout<<BT->data;
inOrderTravel(BT->right);
}
}
可以看出来,递归方式的中序遍历和前序遍历的差别在于输出数据的行数变化,前序是先输出在递归遍历左子树,而中序是先递归处理左子树再输出。
非递归方式
void inOrderTravel(BinTree BT)
{
stack<BinTree> s;
while(BT || !s.empty())
{
if(BT)
{
s.push(BT);
BT = BT->left;
}
else if(!s.empty())
{
BT = s.top();
s.pop();
cout<<BT->data<<endl;
BT = BT->right;
}
}
}
这里也可以看出来,非递归的中序遍历方式和前序遍历的区别也是输出位置的不同;
后序遍历
事实上,后序遍历的递归和非递归方式也是只是输出的位置不同而已,这里给出代码
递归方式
void postOrderTravel(BinTree BT)
{
if(BT)
{
postOrderTravel(BT->left);
postOrderTravel(BT->right);
cout<<BT->data<<endl;
}
}
非递归方式
void postOrderTravel(BinTree BT)
{
stack<BinTree> s;
while( BT || !s.empty())
{
if(BT)
{
s.push(BT);
BT = BT->left;
}
else if(!s.empty())
{
BT = s.top();
s.pop();
if(BT->right)
{
s.push(BT);
BT = BT->right;
}
cout<<BT->data<<endl;
}
}
}
层序遍历
最后是层序遍历,层序遍历的特点是每次遍历节点时,都把节点的左右子树压入队列中,从而达到自上而下遍历整棵树的目的。
void levelTravel(BinTree BT)
{
if(!BT)return;
queue<BinTree> q;
BinTree T;
q.push(BT);
while(!q.empty())
{
T = q.front();
q.pop();
cout<<T->data<<endl;
if(T->left)
q.push(T->left);
if(T->right)
q.push(T->right);
}
}