首先来介绍树,我们常见树是由根和枝叶组成,而对于我们学习数据结构中的树,它是由根,左子树和右子树构成。它其实在某种意义上是有一定规律的,所以我们将学习它的遍历。(有非常详细的思路)
先来介绍遍历的概念:遍历是指从根结点出发,按照某种次序依次访问树中所有节点,使得每个节点被访问一次且仅被访问一次。
之前学习的栈和队列实际其实是一种线性表,而对于树来说它由根出发可以有无数种路径,而计算机只能处理线性序列,当我们研究树的遍历,可以将树的节点用某种顺序来链接起来,这将给程序的实现带来了好处。
二叉树其实只是一种非常特殊的结构,它的每个节点最多只有两个子节点。
遍历思路:
前序的遍历顺序:根--->左子树--->右子树。树里的每个节点其实都可以作为根,当我们认为A是根的时候,那么BDE作为它的左子树,CFG作为右子树。先遍历根,那么就是先走A,然后遍历左子树时遇到B,即B又作为根,D和E分别作为B左子树和右子树,往下走继续左子树,遇到D,D又作为根,它的左右子树为空,即B的左子树遍历完成,然后是B的右子树,遇到E又作为根,E左右子树为空,那么它的右子树遍历完成,B的整个树遍历完成,因为BDE是作为A的左子树,那么接下来遍历A的右子树,遇到C又作为根,F和G分别为左右子树,接下来思路和前面一致。整体顺序:A-->B-->D-->E-->C-->F-->G
对于这里的理解非常重要,这其实就是一种递归的思想,把大问题分成若干个相同思路的小问题去解决,那你会发现仅仅用几行代码就能解决问题。(前序,中序,后序思路几乎一致)
节点的结构体:
typedef char BTtype;
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left;//左子树
struct BinaryTreeNode* right;//右子树
BTtype date;
}BTNode;
前序:
void PrevOrder(BTNode* root)//前序
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%c ", root->date);//根
PrevOrder(root->left);//左子树
PrevOrder(root->right);//右子树
}
中序:
void InOrder(BTNode* root)//中序
{
if (root == NULL)
{
printf("NULL ");
return;
}
InOrder(root->left);//左子树
printf("%c ", root->date);//根
InOrder(root->right);//右子树
}
后序:
void PostOrder(BTNode* root)//后序
{
if (root == NULL)
{
printf("NULL ");
return;
}
PostOrder(root->left);//左子树
PostOrder(root->right);//右子树
printf("%c ", root->date);//根
}
层序遍历思路:
利用队列先进先出的特点,先将A入队列,然后判断队列为不为空,不为空把A取出并记录,然后将A的左右子树B,C入队列,取A的左子树B并记录,将B的左右子树D,E入队列,取A的右子树C并记录,将C的左右子树F,G入队列,然后一直取,直到队列为空。整体顺序为:A--->B--->C--->D---E--->F--->G
代码:
xxxxxxxxxx
void LeveOder(BTNode* root)//层序遍历法,利用队列
{
Queue q;
QueueInit(&q);
if (root)
{
QueuePush(&q, root);//先入根
}
while (!QueueEmpty(&q))//判空
{
BTNode* front = QueueFirst(&q);//出根并记录
printf("%c ", front->date);
QueuePop(&q);
if (front->left)
{
QueuePush(&q, front->left);//入左子树
}
if (front->right)
{
QueuePush(&q, front->right);//入右子树
}
}
QueueDestroy(&q);
}
这里代码的逻辑主要采用的递归思想,所以一定要把握好把大问题化解成若干个相同小问题去解决。