遍历二叉树
首先判断是否为空树
一、以二叉链表为存储结构
/*-----二叉树的二叉链表的存储结构-----*/
typedef int Telemtype;
typedef struct BiTNode
{
Telemtype data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
- 递归算法注意设置递归出口。
- 非递归算法用栈实现,栈用来保存走过的路径。
非递归算法中,后序遍历要判断,在返回根结点时,是从左子树返回还是右子树返回。设置一个标志量,加入二叉链表结点中。
1.先序遍历二叉链表
递归算法
/*-----先序遍历二叉树的二叉链表,递归算法-----*/
void preorder_traverse(BiTree T)
{
if(T==NULL) return;//递归出口,空树
printf("%d",T->data);
preorder_traverse(T->lchild);
preorder_traverse(T->rchild);
}
非递归算法
/*先序遍历二叉树的二叉链表,非递归算法,用栈实现*/
void inorder_traverse(BiTree T)
{
BiTree p=T;
InitStack(S);//初始化栈
while(p||!StackEmpty(S))
{
if(p!=NULL)//根指针进栈,访问根结点,遍历左子树
{
Push(S,p);
printf("%d",p->data);//访问根结点
p=p->lchild;//遍历左子树
}
else//根结点退栈,遍历右子树
{
Pop(S,p);
p=p->rchild;//遍历右子树
}
}
}
/*先序遍历二叉树的二叉链表,非递归算法,用栈实现,与上一个比较*/
void inorder_traverse(BiTree T)
{
BiTree p=T;
InitStack(S);//初始化栈
while(p||!StackEmpty(S))
{
while(p!=NULL)//一直遍历到左子树最下边,边遍历边访问并保存根节点到栈中(路径)
{
Push(S,p);
printf("%d",p->data);//访问根结点,入栈
p=p->lchild;//遍历左子树
}
if(!StackEmpty(S))//根结点出栈,遍历右子树
{
Pop(S,p);
p=p->rchild;//遍历右子树
}
}
}
2.中序遍历二叉树
递归算法
/*中序遍历二叉树的二叉链表,递归算法*/
void preorder_traverse(BiTree T)
{
if(T==NULL) return;//递归出口,空树
preorder_traverse(T->lchild);
printf("%d",T->data);
preorder_traverse(T->rchild);
}
非递归算法
/*中序遍历二叉树的二叉链表,非递归算法,用栈实现*/
void inorder_traverse(BiTree T)
{
BiTree p=T;
InitStack(S);//初始化栈
while(p||!StackEmpty(S))
{
if(p!=NULL)//根指针进栈,遍历左子树
{
Push(S,p);
p=p->lchild;//遍历左子树
}
else//根指针退栈,访问根结点,遍历右子树
{
Pop(S,p);
printf("%d",p->data);//访问根结点
p=p->rchild;//遍历右子树
}
}
}
/*中序遍历二叉树的二叉链表,非递归算法,用栈实现,与上一个比较*/
void inorder_traverse(BiTree T)
{
BiTree p=T;
InitStack(S);//初始化栈
while(p||!StackEmpty(S))
{
while(p!=NULL)//一直遍历到左子树最下边,边遍历边保存根节点到栈中(路径)
{
Push(S,p);
p=p->lchild;//保存路径
}
if(!StackEmpty(S))
{
Pop(S,p);
printf("%d",p->data);//出栈,访问根结点
p=p->rchild;//遍历右子树
}
}
}
3.后序遍历二叉树
递归算法
/*后序遍历二叉树的二叉链表,递归算法*/
void preorder_traverse(BiTree T)
{
if(T==NULL) return;//递归出口,空树
preorder_traverse(T->lchild);
preorder_traverse(T->rchild);
printf("%d",T->data);
}
/*后序遍历二叉树的二叉链表,非递归算法,用栈实现*/
/*设置一个标志量flag,加入结点中0表示从左子树返回,1表示从右子树返回。只有从右子树返回时,才访问根结点*/
void inorder_traverse(BiTree T)
{
BiTree p=T;
InitStack(S);//初始化栈
while(p||!StackEmpty(S))
{
if(p!=NULL)//根指针进栈,遍历左子树
{
Push(S,p);
p->flag=0;//去访问该结点的左子树
p=p->lchild;//遍历左子树
}
else//第一个else
{
Pop(S,p);//根结点先出栈,判断是否要访问
if(p->flag==0)//只访问过左子树,不访问根结点
{
Push(S,p);//根结点重新入栈,保存路线
p->flag=1;//去访问该结点的右子树
p=p->rchild;//遍历右子树
}
else//右子树访问过,访问根结点,根结点已退栈
{
printf("%d",p->data);//访问根结点
p=NULL;//注意置空指针!
/*NULL使之进入第一个else,根结点再次退栈,判断从左子树还是右子树退栈*/
}
}
}
}
4.层序遍历二叉树
使用队列实现
/*层序遍历二叉树的二叉链表,用队列实现*/
void levelorder_traverse(BiTree T)
{
//判断是否为空树
if(T==NULL) return;
InitQueue(Q);//初始化队列
Push(Q,T);//根结点入队
while(!QueueEmpty(Q))
{
BiTree p=front(Q);//取队头元素,访问
printf("%d",p->data);
if(p->lchild!=NULL)//左子树不为空则入队
Push(Q,T);//根结点入队
if(p->rchild!=NULL)//右子树不为空则入队
Push(Q,T);//根结点入队
}
}
可推广到用队列实现树的层序遍历
二、 以线索链表为存储结构
中序遍历
/*中序遍历二叉树的双向线索链表,非递归算法,不需要用栈*/
void inorder_traverse_Thr(BiThrTree T)//T为头结点
{
BiThrTree p=T->lchild;//p指向根结点
while(p!=T)//非空树或遍历未结束
{
while(p->LTag==Link)//遍历左子树
p=p->lchild;
printf("%d",p->data);//访问根结点
while(p->RTag==Thread&&p->rchild!=T)
{
p=p->rchild;//访问后继节点
printf("%d",p->data);
}
p=p->rchild;//遍历右子树
}
}
中序线索化二叉链表
/*中序线索化二叉树的双向线索链表,Thrt为头结点*/
BiThrTree pre;//全局变量
void inorder_Threading(BiThrTree T,BiThrTree /*&*/ Thrt)
{
//建头结点,为头结点Thrt分配空间
if(!(Thrt=(BiThrTree)malloc(sizeof(BiThrNode)))) exit(0);
Thrt->LTag=Link;Thrt->RTag=Thread;
Thrt->rchild=Thrt;//右指针回指
if(T==NULL) Thrt->lchild=Thrt;//若二叉树为空,则左指针回指
else
{
Thrt->lchild=T;//双向
pre=Thrt;
InThreading(T);//中序线索化二叉树
pre->RTag=Thread;pre->rchild=Thrt;//最后一个结点线索化
Thrt->rchild=pre;//双向
}
}
/*中序线索化二叉树,递归算法*/
void InThreading(BiThrTree p)
{
if(p==NULL) return;//递归出口
//左子树线索化
InThreading(p->lchild);
//若遇到左子树为空,即左指针为空指针,前驱线索
if(p->lchild==NULL)
{
p->LTag=Thread;p->lchild=pre;
}
//若遇到右子树为空,即右指针为空指针,后继线索
if(pre->rchild==NULL)
{
pre->RTag=Thread;pre->rchild=p;
}
//保持pre指向p的前驱
pre=p;
//右子树线索化
InThreading(p->rchild);
}