c语言二叉树的先序创建、(先中后序)遍历以及存在的问题
问题来源
在学习先序遍历的顺序创建二叉树的时候,首先自己写了如下的代码:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<math.h>
typedef struct BiTreeNode
{
char Data;
struct BiTreeNode* Lchild;
struct BiTreeNode* Rchild;
}BiTreeNode,*BiTree;
void CreateBiTree(BiTree T)
{
if(T == NULL){
return;
}
else{
char ch;
scanf("%c",&ch);
if(ch == '#'){
T = NULL;
}
else{
T = (BiTree)malloc(sizeof(BiTreeNode));
if(T == NULL)
exit(OVERFLOW);
T->Data = ch;
CreateBiTree(T->Lchild);
CreateBiTree(T->Rchild);
}
}
}
void PreOrderTraverse(BiTree T)
{
if(T == NULL)
return;
else{
printf("%c",T->Data);
PreOrderTraverse(T->Lchild);
PreOrderTraverse(T->Rchild);
}
}
void InOrderTraverse(BiTree T)
{
if(T == NULL)
return;
else{
InOrderTraverse(T->Lchild);
printf("%c",T->Data);
InOrderTraverse(T->Rchild);
}
}
void PostOrderTraverse(BiTree T)
{
if(T == NULL)
return;
else{
PostOrderTraverse(T->Lchild);
PostOrderTraverse(T->Rchild);
printf("%c",T->Data);
}
}
int main(void)
{
BiTree T;
CreateBiTree(T);
InOrderTraverse(T);
printf("\n");
PostOrderTraverse(T);
return 0;
}
查找分析
满怀成就感的写完了上面的代码😎,编译通过💪,无比自信的运行后😁,瞬间绝望😰,出现的现象是:能够输入树的信息,但是却没有输出。如果是遍历函数出现了问题可以通过静态构造二叉树的方式进行测试,于是,我又写了如下的代码:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<math.h>
typedef struct BiTreeNode
{
char Data;
struct BiTreeNode* Lchild;
struct BiTreeNode* Rchild;
}BiTreeNode,*BiTree;
void PreOrderTraverse(BiTree T)
{
if(T == NULL)
return;
else{
printf("%c",T->Data);
PreOrderTraverse(T->Lchild);
PreOrderTraverse(T->Rchild);
}
}
void InOrderTraverse(BiTree T)
{
if(T == NULL)
return;
else{
InOrderTraverse(T->Lchild);
printf("%c",T->Data);
InOrderTraverse(T->Rchild);
}
}
void PostOrderTraverse(BiTree T)
{
if(T == NULL)
return;
else{
PostOrderTraverse(T->Lchild);
PostOrderTraverse(T->Rchild);
printf("%c",T->Data);
}
}
int main(void)
{
BiTree a=NULL;
BiTree b = NULL;
BiTree c = NULL;
a = (BiTree)malloc(sizeof(BiTreeNode));
b = (BiTree)malloc(sizeof(BiTreeNode));
c = (BiTree)malloc(sizeof(BiTreeNode));
a->Rchild = b;
b->Lchild = c;
a->Lchild = NULL;
b->Rchild = NULL;
c->Lchild = NULL;
c->Rchild = NULL;
a->Data = 'A';
b->Data = 'B';
c->Data = 'C';
PreOrderTraverse(a);
printf("\n");
InOrderTraverse(a);
printf("\n");
PostOrderTraverse(a);
return 0;
}
可以成功输出如下的信息:
由此可以判断,遍历函数是没有问题的,必定是二叉树的创建函数出现了问题,经过查找相关的资料以及代码,将二叉树的创建函数修改成下面这样的形式:
void CreateBiTree(BiTree *T) //引用值传递
{
if(*T == NULL){
return;
}
else{
char ch;
scanf("%c",&ch);
if(ch == '#'){
*T = NULL;
}
else{
*T = (BiTree)malloc(sizeof(BiTreeNode));
if(*T == NULL)
exit(OVERFLOW);
(*T)->Data = ch;
CreateBiTree(&(*T)->Lchild); //构造左子树
CreateBiTree(&(*T)->Rchild); //构造右子树
}
}
}
修改以后运行代码,成功了!在这里卡了很久,一直不理解为啥会这样???😵😵😵为什么??
后面又看到使用BiTree
作为返回值的算法,如下:
BiTree CreateBiTree() //以BiTree为返回值
{
char ch;
BiTree T;
scanf("%c",&ch);
if(ch == '#'){
T = NULL;
}
else{
T = (BiTree)malloc(sizeof(BiTreeNode));
if(T == NULL)
exit(OVERFLOW);
T->Data = ch;
T->Lchild = CreateBiTree(); //构造左子树
T->Rchild = CreateBiTree(); //构造右子树
}
return T;
}
同样实现了需求。
结论总结
经过很久的查找资料和思考,我觉得一些文章都还是没有说清楚。现在自己总结如下:
-
首先我们在
main
函数中定义了一个BiTree
(即结构体)类型的指针变量T
,注意:此时该指针实际上只是个野指针,我们不知道T
指向了内存中的哪块空间; -
我们希望
T
指向二叉树的根结点,就要将根结点的地址赋值给T
; -
在我自己写的代码中,犯了一个错误:在
main
函数中调用CreateBiTree
函数,将变量T
传给CreateBiTree
函数,该函数也确实创建了一棵二叉树,并且在该函数中的T
也确实是指向了这棵二叉树,但是 ,在main函数中T
的值并没有改变,也就意味着,在main
函数中T
并没有指向我们创建的二叉树。于是我写了下面的代码进行验证:#include<stdio.h> #include<malloc.h> #include<stdlib.h> #include<math.h> typedef struct BiTreeNode { char Data; struct BiTreeNode* Lchild; struct BiTreeNode* Rchild; }BiTreeNode,*BiTree; void CreateBiTree(BiTree T) { if(T == NULL){ return; } else{ char ch; scanf("%c",&ch); if(ch == '#'){ T = NULL; } else{ T = (BiTree)malloc(sizeof(BiTreeNode)); printf("在二叉树构造函数中,动态申请内存后T的值为:%X\n",T); if(T == NULL) exit(OVERFLOW); (T)->Data = ch; CreateBiTree(T->Lchild); CreateBiTree(T->Rchild); } } } void PreOrderTraverse(BiTree T) { if(T == NULL) return; else{ printf("%c",T->Data); PreOrderTraverse(T->Lchild); PreOrderTraverse(T->Rchild); } } void InOrderTraverse(BiTree T) { if(T == NULL) return; else{ InOrderTraverse(T->Lchild); printf("%c",T->Data); InOrderTraverse(T->Rchild); } } void PostOrderTraverse(BiTree T) { if(T == NULL) return; else{ PostOrderTraverse(T->Lchild); PostOrderTraverse(T->Rchild); printf("%c",T->Data); } } int main(void) { BiTree T; printf("在main函数中,T的值为:%X\n",T); CreateBiTree(T); printf("在main函数中,调用二叉树构建函数后,T的值为:%X\n",T); InOrderTraverse(T); printf("\n"); PostOrderTraverse(T); return 0; }
运行后,测试结果如下:
可以看到,结果正是我上面说的那种样子。
将二叉树的创建修改为引用值传递后,得到如下的结果:
通过这篇文章,感觉自己对相关知识的理解更深入了一步。希望对看完这篇文章的人也有所帮助。