遍历的概念:
“遍历”: 沿某条搜索路径巡访二叉树的结点, 使每个结点均被访问一次, 且仅被访问一次。
用L、D、R表示遍历左子树、访问根结点、遍历右子树,
先左后右的遍历算法:(命名即根据访问根结点的先后次序)
先序遍历:DLR
中序遍历:LDR
后序遍历:LRD
先序遍历思路:
- 若为空树,则空操作
1. 访问根结点
2. 先序遍历左子树
3. 先序遍历右子树
中序遍历思路:
- 若为空树,则空操作
1. 先序遍历左子树
2. 访问根结点
3. 先序遍历右子树
后序遍历思路:
- 若为空树,则空操作
1. 先序遍历左子树
2. 先序遍历右子树
3. 访问根结点
按层次遍历思路:(借助队列先进先出的特性)
1. 初始化队列(置队空)
2. 将树的根指针入队(队列存储类型为树的结点的指针类型)
3. 循环(当满足“队列非空”时执行下面操作)
- 取出队头元素(即队头位置存的结点指针)
- 打印队头元素所指结点的key值
- 若该队头元素所指结点的左孩子非空,入队
- 若该队头元素所指结点的右孩子非空,入队
数据存储结构:
typedef struct BiTree{
ElemType key;//结点值
struct BiTree *left;//左孩子
struct BiTree *right;//右孩子
struct BiTree *p;//双亲
}BiTNode,*BiTree;
代码实现
1.先序遍历
void PreOrder(BiTree bt)
{
if(bt!=NULL)//根指针为bt
{
printf("%d",bt->key);//访问根结点
PreOrder(bt->left);//遍历左子树
PreOrder(bt->right);//遍历右子树
}
}
2.中序遍历
void InOrder(BiTree bt)
{
if(bt!=NULL)//根指针为bt
{
InOrder(bt->left);//遍历左子树
printf("%d",bt->key);//访问根结点
InOrder(bt->right);//遍历右子树
}
}
3.后序遍历
void PostOrder(BiTree bt)
{
if(bt!=NULL)
{
PostOrder(bt->left);//遍历左子树
PostOrder(bt->right);//遍历右子树
printf("%d",bt->key);//访问根结点
}
}
4.按层次遍历
void LevelOrderTraverse(BiTree T)//传入根指针
{
if(T)
{
Queue *Q;//定义一个队列指针Q
BiTree temp;//定义一个中间变量存取出来的指针
InitQueue(Q);//队列初始化 置队空
EnQueue(Q,T);
while(!QueueEmpty(Q))//当队列Q非空时
{
temp=DeQueue(Q);//temp存队头指针
printf("%d",temp->data);//打印队头指针指向的结点的key值
if(temp->left)
EnQueue(Q,temp->left);
if(temp->right)
EnQueue(Q,temp->right);
}
}
}
说明:
这里的队列初始化、入队、出队、判队空具体函数实现看“栈与队列”那一part,不同的是,这里的队列里存的元素类型为树的结点的指针类型BiTree。
遍历算法应用举例
- 统计二叉树中叶子结点的个数
思路:
先序(中序或后序)遍历二叉树,在遍历过程中查找叶子结点并计数。需在遍历算法中新增一个计数的操作,并把Visit操作(此处是printf)改为,若是叶子结点,则计数器加1.
void Leaves(BiTree bt)
{
if(bt!=NULL)
{
if(bt->left==NULL&&bt->right=NULL)/*若是叶子结点时*/
count++;//计数器+1
Leaves(bt->left);
Leaves(bt->right);
}
}
Notes:
1.count设为保存叶子结点数目的全局变量,调用之前初始化值为0
如果将Leaves函数返回值设成int,递归调用时有问题。
2.不论是先序、中序还是后序遍历,求叶子结点数目都是上面的代码,因为该树或其子树的根结点一定不是叶子结点,而if语句的操作只有满足是叶子结点才执行,且总的顺序是从左至右。
- 求二叉树的深度
思路:
首先分析二叉树的深度与它左右子树深度之间的关系。
二叉树深度应为其左、右子树深度的最大值加1。按后序遍历编写深度函数,先分别求得左、右子树深度,再将其中的Visit操作(此处是printf)改为:
深度=左、右子树深度最大值+1
(因为要先求左子树和右子树的深度,再进行max操作,故按后序遍历)
int PostDepth(BiTree bt)
{
int left_h,right_h,max_h;
if(bt==NULL)
return 0;//空树返回0
left_h=PostDepth(bt->left);//求左子树深度
right_h=PostDepth(bt->right);//求右子树深度
max_h=left_h>right_h?left_h:right_h;//左子树和右子树深度较大值
return max_h+1;//返回树的深度
}