- 创建二叉树节点(递归)
- 先序遍历(递归)
- 中序遍历(递归)
- 后序遍历(递归)
- 复制二叉树(先序递归)
- 求二叉树的深度(递归)
- 求二叉树的节点数(递归)
- 注意:遍历中的“访问”是一抽象操作,可以指代任何操作,本文仅以“打印、输出”作为“访问”操作!
注:树及二叉树的算法大多都是利用递归的思路去求解,因为树结构本身就是逐级发散,在算法中以一个跟节点和它的左右孩子组成一个单元,通过递归一层一层的访问一个单元的子目录,从而找到二叉树的所有节点。
需要注意的细节:
- creat中的输入顺序是按前序遍历的顺序输入
- 输入格式:在二叉树中区分左右两个分支节点,也就是一个根结点(root)的左,右孩子可以相互独立,可以只有左孩子,也可以只有右孩子,所以在输入的过程中遇到空节点需要用“#”来代替,如下图二叉树:
- 注意:若输入时想用空格或者回车键隔开每个输入变量,则需在scanf后(代码第20行处)加入一个getchar();来抵消回车或空格键。
- 先序遍历:先访问根,DLR(根,左,右),输出跟节点的内容,递归查找当前左孩子的“根系”,递归查找当前右孩子的“根系”。
- 中序遍历:中间访问根,LDR(左,根,右),先递归查找当前左孩子的“根系”,输出当前根节点内容,递归查找当前右孩子的“根系”
- 后序遍历:后续访问根,LDR(左,右,根),先查递归查找当前左孩子的“根系”,再递归查找当前右孩子的“根系”,最后输出根节点内容。
- 层序遍历:根据逐层的次序从上往下,逐层输出,需要借助队列来实现(此处不演示)
- 先序遍历,中序遍历,后序遍历,也可以不使用递归算法,因为递归算法本身就是一层一层的放进系统的堆栈中,然后由栈顶向栈底处理,那么能用递归实现的也一定可以用堆栈来实现。
- 在建立二叉树的过程中,我们不难发现,我们需要浪费一大部分的空指针,这些虚节点和空指针没有任何的指向,我们在建立n个结点的二叉树中共有2n个指针域,足足有n+1个空指针域,造成巨大的浪费。那么我们怎么样才能避免这种浪费呢?或者是说如何能利用上这些空指针?——线索化二叉树。
完整代码:
#include <stdio.h>
#include <stdlib.h>
typedef char dataType;
typedef struct BiNode
{
dataType elem; //根节点的元素值
struct BiNode *lchild; //根节点的左孩子
struct BiNode *rchild; //根节点的右孩子
}BiTree;
BiTree *creat() //创建二叉树,以先序方式填入
{
dataType value;
BiTree *t;
scanf("%c",&value); //为节点读入字符
/*getchar();如果输入字符用空格或回车隔开的话,则需要用getchar()抵消空格或回车*/
if(value=='#') //如果读入字符为 # 则建立虚节点
{
t=NULL;
}
else
{
t=(BiTree *)malloc(sizeof(BiTree));
t->elem=value;
t->lchild=creat(); //递归调用,处理根节点的左孩子
t->rchild=creat(); //递归调用,处理根节点的右孩子
}
return t;
}
void preorder(BiTree *t) //先序遍历
{
if(t) //判断t不为空
{
printf("%c ",t->elem);
preorder(t->lchild);
preorder(t->rchild);
}
}
void inorder(BiTree *t) //中序遍历
{
if(t) //判断t不为空
{
inorder(t->lchild);
printf ("%c ",t->elem);
inorder(t->rchild);
}
}
void postorder(BiTree *t) //后续遍历
{
if(t) //判断t不为空
{
postorder(t->lchild);
postorder(t->rchild);
printf("%c ",t->elem);
}
}
BiTree *copy(BiTree *t) //复制顺序与前序遍历一致
{
BiTree *New;
if(t==NULL)
{
New=NULL;
return;
}
New=(BiTree *)malloc(sizeof(BiTree));
New->elem=t->elem; //复制根节点
New->lchild=copy(t->lchild); //递归复制左孩子
New->rchild=copy(t->rchild); //递归复制右孩子
return New;
}
int Depth(BiTree *t) //
{
int n,m;
if(t==NULL)
{
return 0;
}
n=Depth(t->lchild); //递归查找左孩子的深度
m=Depth(t->rchild); //递归查找右孩子的深度
if(n>m)
{
return(n+1);
}
else
return(m+1);
}
int CountNode(BiTree *t)
{
int n,m;
if(t==NULL)
{
return 0;
}
n=CountNode(t->lchild);
m=CountNode(t->rchild);
return(n+m+1);
}
int main()
{
BiTree *root,*NewTree;
int depth,Node;
printf("Input:");
root=creat();
//---------------Tree的遍历-------------------
printf("\n");
printf("Tree:\n");
printf("Preorder:");
preorder(root);
printf("\n");
printf("inorder:");
inorder(root);
printf("\n");
printf("Postorder:");
postorder(root);
printf("\n");
//-----Tree复制到NewTree后,NewTree的遍历------
printf("\n");
printf("Copy Tree to NewTree:\n");
printf("NewTree:");
NewTree=copy(root);
printf("Preorder:");
preorder(NewTree);
printf("\n");
printf("inorder:");
inorder(NewTree);
printf("\n");
printf("Postorder:");
postorder(NewTree);
printf("\n");
//---------计算Tree的深度-----------
printf("\n");
depth=Depth(NewTree);
printf("Calculate 'Tree' Depth: %d\n",depth);
//---------计算Tree的节点数-----------
printf("\n");
Node=CountNode(root);
printf("Calculate 'Tree' NoDE: %d\n",Node);
return 0;
}
输出结果:
错误示例:
此处大可不必这么去判断t是否为空,如果按此处执行,则当每次递归执行到虚节点处,则会判定树为空,如下图。
参考:
- 数据结构(C语言版,严蔚敏,吴伟民)