一.二叉树
首先我们聊一聊什么是二叉树,二叉树就是n个节点的有限集合,该集合或者空集(称为空二叉树),或者由一个根节点和两课互不相交的分别称为根节点的左子树和右子树的二叉树组成。
一看这,嗨哟,挺复杂,其实我们只要抓住它的特点就行了,二叉树嘛,①他的每个节点最多有两颗子树,我们可以理解为二胎政策,一个家庭最多有两个孩子,②很重要的一个就是他的左右子树是有顺序的,不能颠倒,这个我们可以理解为家里的两个孩子,一个是哥哥,一个是弟弟,哥哥和弟弟不能混淆,③树中有一颗子树也要区分它是左子树还是右子树,这个和后面讲的遍历关系很大。
二.二叉树的遍历
二叉树的遍历有四种:
1.前序遍历
2.中序遍历
3.后序遍历
4.层序遍历
1.前序遍历
所谓前序遍历就是先遍历根节点,然后遍历节点 的左子树,最后便利根节点的右子树。比如:
大家可以看到,我们从根节点A开始遍历,再到根节点的左子树B,再到B的左子树D,现在B的左子树遍历完了,再到B的右子树E,现在根节点A的左子树遍历完了,再到A的右子树C,因为C没有左子树,所以遍历C的右子树,到这就遍历完了。
遍历顺序为:ABDECF
2.中序遍历
中序遍历,就是先遍历根节点的左子树再访问A节点,最后遍历根节点的右子树。上图:
中序遍历的过程就是:DBEFACF
3.后序遍历
后序遍历大家可能已经猜到了,就是先遍历根节点的左子树,再遍历根节点的右子树,最后遍历根节点。上图:
遍历顺序:DEBFCA
4.层序遍历
层序遍历,顾名思义,就是一层一层的遍历,这个我就不画图了,也是上面的例子,遍历顺序就是:ABCDEF
三.二叉树的创建
为什么要先讲如何遍历二叉树呢?因为创建二叉树和遍历的方法是一样的。
最基础的方法就是用递归实现啦!考虑到递归,我们会想到它的结束条件是什么?这我们就得在输入时加上结束条件了,也就是给树的节点加上空的孩子,使它成为一个满二叉树。如图:
这样,在递归到我们设置好的结束字符时递归就会返回了,上代码:
假设结束字符为”#“,所以我们按前序输入就是:ABD##E##C#F##
/*按前序输入二叉树中的结点的值“#”表示空*/
void createBiTree(BiTree *T) {
TElemType ch;
scanf_s("%c", &ch, 1);
if (ch == '#') {
*T = NULL;
}
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
(*T)->data = ch;
createBiTree(&(*T)->lchild);
createBiTree(&(*T)->rchild);
}
}
四.二叉树的遍历(代码)
//前序遍历整棵树
void PreOrderTraverse(BiTree T,int leval) {
if (NULL == T)
return;
visit(T,leval);//访问节点的操作leval表示该节点所在的层数
PreOrderTraverse(T->lchild,leval + 1);
PreOrderTraverse(T->rchild,leval + 1);
}
//中序遍历整棵树
void InOrderTraverse(BiTree T,int leval) {
if (NULL == T)
return;
PreOrderTraverse(T->lchild,leval + 1);
visit(T,leval);//访问节点的操作leval表示该节点所在的层数
PreOrderTraverse(T->rchild,leval + 1);
}
//后续遍历整棵树
void PostOrderTraverse(BiTree T,int leval) {
if (NULL == T)
return;
PreOrderTraverse(T->lchild,leval + 1);
PreOrderTraverse(T->rchild,leval + 1);
visit(T,leval);//访问节点的操作leval表示该节点所在的层数
}
大家可以发现,在代码实现上,前序、中序、后序遍历的不同就在于访问节点的操作所在的位置不同,很简单吧!
五.完整代码与调试
#include <stdio.h>
#include <stdlib.h>
typedef char TElemType;
typedef struct BiTNode {
TElemType data;
struct BiTree* lchild, * rchild;
}BiTNode, * BiTree;
/*按前序输入二叉树中的结点的值“#”表示空*/
void createBiTree(BiTree* T) {
TElemType ch;
scanf_s("%c", &ch, 1);
if (ch == '#') {
*T = NULL;
}
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
(*T)->data = ch;
createBiTree(&(*T)->lchild);
createBiTree(&(*T)->rchild);
}
}
//访问节点的操作
void visit(BiTree T, int leval) {
printf("%c在第%d层\n", T->data, leval);
return;
}
//前序遍历树
void PreOrderTraverse(BiTree T, int leval) {
if (NULL == T)
return;
visit(T, leval);
PreOrderTraverse(T->lchild, leval + 1);
PreOrderTraverse(T->rchild, leval + 1);
}
//中序遍历整棵树
void InOrderTraverse(BiTree T, int leval) {
if (NULL == T)
return;
InOrderTraverse(T->lchild, leval + 1);
visit(T, leval);//访问节点的操作leval表示该节点所在的层数
InOrderTraverse(T->rchild, leval + 1);
}
//后续遍历整棵树
void PostOrderTraverse(BiTree T, int leval) {
if (NULL == T)
return;
PostOrderTraverse(T->lchild, leval + 1);
PostOrderTraverse(T->rchild, leval + 1);
visit(T, leval);//访问节点的操作leval表示该节点所在的层数
}
int main(void)
{
BiTree T = NULL;
int leval = 1;
createBiTree(&T);
InOrderTraverse(T, leval);
return 0;
}
我们以前序输入创建二叉树:ABD##E##C#F##,以中序遍历的方式访问二叉树的节点:
大家可以看到:中序遍历的结果为:DBEACF
下一期:二叉树的线索化,肝!