说到二叉树,最基本的操作就是遍历。四种遍历方式:前序,种序,后序,层序。本篇博客主要叙述如何用递归解决以上操作,非递归方式会另外记录。
二叉树的定义
我在这了采用了孩子表示法,主要是为了实现二叉树的操作,用孩子表示法便于我们找到两个孩子结点。
typedef char TreeNodeType;
typedef struct TreeNode{
TreeNodeType data;
struct TreeNode* rchild;
struct TreeNode* lchild;
}TreeNode;
前序
首先来构造一棵二叉树。
我们先来依据我们学到的前序遍历的遍历方式(VRL)得出前序遍历的一个结果:
ABDEGCF
然后,再来分析在计算机的角度他将如何遍历。二叉树本身就是递归定义的,那么我们遍历时也要采用递归的方式,访问每一个结点,访问的意思是说,对访问到的某一个结点进行某一种操作。比如:打印。
所以前序的遍历思路总结如下:
首先,访问根节点。
递归地对左子树进行访问。
递归地对右子树进行访问。
void PreOrder(TreeNode* root)
{
if(root==NULL)
{
return;
}
//先访问根节点
printf("%c ",root->data);
//在递归的访问左子树
PreOrder(root->lchild);
//在递归的访问右子树
PreOrder(root->rchild);
}
中序
还是上面那棵树,我们先来写一下中序遍历的结果是什么:DBGEACF
思路是:
递归地对左子树进行访问
访问根节点
递归地对右子树进行访问。
void InOrder(TreeNode* root)
{
if(root==NULL)
{
return;
}
//在递归的访问左子树
InOrder(root->lchild);
//先访问根节点
printf("%c ",root->data);
//在递归的访问右子树
InOrder(root->rchild);
}
后序
后序遍历结果是:
DGEBFCA
思路是:
递归地对左子树进行访问
递归地对右子树进行访问。
最后,访问根节点
void PostOrder(TreeNode* root)
{
if(root==NULL)
{
return;
}
//在递归的访问左子树
PostOrder(root->lchild);
//在递归的访问右子树
PostOrder(root->rchild);
//先访问根节点
printf("%c ",root->data);
}
测试结果如下:
层序
层序比较好想,但是代码实现并不简单,还是上面那那棵树,层序结果是ABCDEFG
但是,用代码来解决就不是那么好想,需要借助一个队列来实现。
首先,先将根节点入队列,然后取队列首元素,出队列。
然后,将左右结点入队列,再取队首元素然后出队列
再将该节点的左右孩子结点入队列,然后取队首元素,然后出队列。
重复以上过程,直至没有左右结点可以入队列时,循环结束。
void LevelOrder(TreeNode* root)
{
if(root==NULL)
{
return;
}
SeqQueue q;
SeqQueueInit(&q);
SeqQueuePush(&q,root);
while(1)
{
SeqQueType front;
int ret=SeqQueueTop(&q,&front);
if(ret==0)
{
break;
}
//打印当前值
printf("%c ",front->data);
//出队列当前队首元素
SeqQueuePop(&q);
//分别入队列左右子树
if(front->lchild!=NULL)
{
SeqQueuePush(&q,front->lchild);
}
if(front->rchild!=NULL)
{
SeqQueuePush(&q,front->rchild);
}
}
}