二叉树的遍历主要有三种:前序遍历、中序遍历、后序遍历
下面以遍历下颗树为例:
前序遍历:-+a*b-cd/ef
中序遍历:a+b*c-d-e/f
后序遍历:abcd-*+ef/-
递归算法实现
public:
//前序遍历
void preOrder(void(*visit)(BinTreeNode<T> *p))
{
//递归算法
preOrder(root,visit);
}
//中序遍历
void inOrder(void(*visit)(BinTreeNode<T> *p))
{
inOrder(root,visit);
}
//后序遍历
void postOrder(void(*visit)(BinTreeNode<T> *p))
{
postOrder(root,visit);
}
protected:
//前序遍历
void preOrder(BinTreeNode<T>*subTree,void(*visit)(BinTreeNode<T> *p))
{
if(subTree!=NULL)
{
visit(subTree);
preOrder(subTree->leftChild,visit);
preOrder(subTree->rightChild,visit);
}
}
//中序遍历
void inOrder(BinTreeNode<T> *subTree,void(*visit)(BinTreeNode<T> *p))
{
//递归函数,=NULL是终止递归条件
if(subTree!=NULL)
{
inOrder(subTree->leftChild,visit);
visit(subTree);//访问根节点
inOrder(subTree->rightChild,visit);
}
}
//后序遍历
void postOrder(BinTreeNode<T> *subTree,void(*visit)(BinTreeNode<T> *p))
{
if(subTree!=NULL)
{
postOrder(subTree->leftChild,visit);
postOrder(subTree->rightChild,visit);
visit(subTree);
}
}
非递归算法实现
//每一次访问一个节点后,在向左子树遍历下去之前,
//利用这个栈记录该节点的右子女(如果有的话)节点地址,
//以便左子树退回时可以直接从栈中取出右子树的根节点,继续其右子树的前序遍历
void preOrder(void(*visit)(BinTreeNode<T> *p))
{
stack<BinTreeNode<T> *> nodes;
BinTreeNode<T> *temp=root;
nodes.push(NULL);
while(temp!=NULL)
{
visit(temp);
if(temp->rightChild!=NULL)
{
nodes.push(temp->rightChild);
}
if(temp->leftChild!=NULL)
{
temp=temp->leftChild;
}
else
{
temp=nodes.top();
nodes.pop();
}
}
}
//中序遍历
//在一棵子树中首先访问的是中序下的第一个节点
//它位于从根开始的沿着leftchild链走到最左下角的节点,该节点的leftchild为NULL。
//访问完他的数据之后,再遍历它的右子树。如果此右子树又是二叉树,则重复上面的过程,直到该子树遍历完毕。
void inOrder(void(*visit)(BinTreeNode<T> *p))
{
stack<BinTreeNode<T> *> nodes;
//遍历指针,从根节点开始
BinTreeNode<T> *temp=root;
do
{
//遍历指针未到最左下的节点,不空
while(NULL!=temp)
{
//该子树沿途节点进栈
nodes.push(temp);
temp=temp->leftChild;
}
if(!nodes.empty())
{
//栈不为空的时候退栈,访问根节点,遍历指针进入右子女节点
temp=nodes.top();
visit(temp);
nodes.pop();
temp=temp->rightChild;
}
}
while(NULL!=temp||!nodes.empty());
}
//后序遍历
//后序遍历比先前的两种遍历要复杂得多,在遍历完左子树之后还不能访问根节点,
//需要再遍历右子树,等到右子树遍历完毕之后才能访问根节点。所以在栈工作记录中一定先表明刚才是在左子树<1>还是在右子树<2>中。
//首先使用栈暂存根节点的地址,再向左子树遍历下去,此时根节点的tag为1,当访问完根节点的左子树之后从左子树退回,还要去遍历右子树
//此时改跟的tag为2.
//从右子树中退出时才能访问位于栈顶的根节点的值。
void postOrder(void(*visit)(BinTreeNode<T> *p))
{
stack<stacknode<T> > nodes;
stacknode<T> temp;
BinTreeNode<T> *p=root;
do
{
while(NULL!=p)
{
temp.ptr=p;
temp.tag=1;
nodes.push(temp);
p=p->leftChild;
}
int continue1=1;
while(continue1&&!nodes.empty())
{
temp=nodes.top();
nodes.pop();
p=temp.ptr;
switch(temp.tag)
{
case 1:
temp.tag=2;
nodes.push(temp);
continue1=0;
p=p->rightChild;
break;
case 2:
visit(p);
break;
}
}
}
while(!nodes.empty());
}
//层次遍历
//层次遍历从二叉树的根节点开始,自上向下,自左向右,分层依次访问树中的各个节点、
void levelOrder(void (*visit)(BinTreeNode<T> *p))
{
queue<BinTreeNode<T> *> nodes;
BinTreeNode<T> *temp=root;
BinTreeNode<T> *tnode;
nodes.push(temp);
while(!nodes.empty())
{
tnode=nodes.front();
nodes.pop();
visit(tnode);
if(NULL!=tnode->leftChild)
{
nodes.push(tnode->leftChild);
}
if(NULL!=tnode->rightChild)
{
nodes.push(tnode->rightChild);
}
}
}
需要整个工程的完整项目的朋友可以看我的这篇文章,点击进行跳转