二叉树是最多具有两个子节点的树,它的创建与之前的链表,队列都不同,之前的链表之类的创建以及使用只需要传地址的值,但是二叉树的创建需要借助递归不停的传实际的地址进去,因此用到了二级指针,二叉树的结构体的定义包含了该树节点,以及它的左孩子指针和右孩子指针。
二叉树结构体如下:
typedef char data_t;
typedef struct Tree
{
data_t data;
struct Tree *leftchild;
struct Tree *rightchild;
}Tree,*Tree_p;
二叉树的创建借助到递归:
我们把空节点以'#'代表,因此当传入的字符是'#'时,代表当前节点没有子节点,如A##,代表的是A是根节点,但是A没有左孩子和右孩子,该二叉树已经结束了。当传入的字符不是'#'时,从传入的树的地址开辟空间,然后把字符赋给当前节点的值,此节点的值就已经有了,那我们就要创建它的左孩子和右孩子,因此再次调用函数本身,分别传的是当前节点的左孩子地址和当前节点的右孩子地址。
void create_tree(Tree_p *tree,char * data,int *index)
{
char ch=data[*index];
*index+=1;
if('#'==ch)
*tree=NULL;
else
{
*tree=(Tree_p)malloc(sizeof(Tree));
(*tree)->data=ch;
create_tree(&((*tree)->leftchild),data,index);
create_tree(&((*tree)->rightchild),data,index);
}
}
二叉树的前序打印:在之前的创建中,每当遇到'#'时,就会让当时的指针指向NULL,因此在遍历的时候我们首先判断当前的指针是否为空,如果不为空,则说明该节点有值。那该节点有值的话那么就可能存在左孩子和右孩子,那我们依然需要通过递归去遍历他的左孩子和右孩子。前序遍历只是在遍历他的左孩子和右孩子之前先打印该节点的值。
void preorder(Tree_p tree)
{
if(NULL==tree)
return ;
else
{
printf(" %c ",tree->data);
preorder(tree->leftchild);
preorder(tree->rightchild);
}
}
二叉树的中序遍历:中序遍历的区别在于打印的时候是在遍历左孩子之后打印该节点的值,然后遍历右孩子
void inorder(Tree_p tree)
{
if(NULL==tree)
return ;
else
{
inorder(tree->leftchild);
printf(" %c ",tree->data);
inorder(tree->rightchild);
}
}
二叉树的后序遍历:区别在于先遍历该节点的左孩子和右孩子之后再打印该节点的值。
void postorder(Tree_p tree)
{
if(NULL==tree)
return ;
else
{
postorder(tree->leftchild);
postorder(tree->rightchild);
printf(" %c ",tree->data);
}
}
主函数:
int main(int argc,char * argv[])
{
Tree_p tree;
int index=0;
create_tree(&tree,argv[1],&index);
preorder(tree);
puts("");
inorder(tree);
puts("");
postorder(tree);
puts("");
}
运行结果: