前言
通过看书和上网搜索资料,我觉得目前的创建二叉树的算法以及遍历二叉树和遍历结果的存储都很麻烦。
所以我写了一种新的创建二叉树的算法,相比目前的算法来讲更符合人们输入的习惯,效率有一定的提高,而没有增加复杂度。
我另外还写了一种新的二叉树遍历的算法,相对目前的几种遍历的方法来讲,最大的不同点在于它是一层层往下遍历的,算法可读性较好;而书上所有的遍历都是先从头结点出发到叶子结点,再往回遍历,算法可读性较差。
而目前对二叉树遍历结果的存储一般都是通过栈来实现的,比如书上的130页,但是这个算法不停地入栈出栈,效率低,并且算法可读性差。所以,我在遍历中加了一个双向链表来存储遍历结果,算法效率较高。
|
A
/
B
/ \
C D
/ \
E F
\
G
完整的调试结果如下:
一.创建二叉树的新算法
目前创建二叉树的方法是按照遍历的顺序输入和按照层序的顺序输入。
1.按照遍历的顺序输入创建二叉树。比如书上的131页,用户必须得先知道要输入的二叉树的遍历结果,而要知道二叉树的遍历结果有两种方法,一种是用已经写好的求二叉树遍历的程序来求,但这需要已经建立好的二叉树才行,这就与前面成了一个矛盾。另一种方法是通过笔算来求遍历结果,但这个也很麻烦。
2.按照层序的顺序输入创建二叉树。按照满二叉树的形式输入数据,空节点全部都要输入。这个方法相对第一种方法来讲更符合人们的输入习惯,只需要一层层地输入数据就行,但有个缺点,就算某一层只有一个节点的话,也必须要输入很多的空格来表示该层其它的空结点,效率很低,非常麻烦。
所以,我写了一种新的创建二叉树的算法。它的优点有:1.相比遍历创建二叉树,它是一层层输入各结点数据的,并且输入都有相应的提示,更符合人们的输入习惯;2.相比层序法,它不需要输入那些空结点,并且有相应的输入提示,大大提高了输入的效率。
这种新的创建二叉树的方法的时间复杂度与遍历方法创建二叉树的时间复杂度相同,都是,n代表二叉树的深度。
首先定义二叉树
typedef struct YLNode{
int data;
int ceng;
struct YLNode *lchild;
struct YLNode *rchild;
}YLNode,*YL;
跟普通的相比,多了int ceng;这个来记录二叉树的层数,也就是深度。
然后创建二叉树,详见第13页附录里面的源程序的main函数。
printf("请输入第");printf("%d",w[b]->ceng); printf("层的结点");printf("%c",w[b]->data);printf("的左子树\n");
dl=getchar(); //输入对应的数据
getchar();
if(dl!=' ') //如果不为空
{
YLNode *ll;
ll=(YLNode *)malloc(sizeof(YLNode)); //新的空间
ll->data=dl;
ll->ceng=(w[b]->ceng)+1; //层数为当前结点层数加一
e++;
w[e]=ll;
w[b]->lchild=ll;
}
else w[b]->lchild=NULL; //否则为空
跟层序法类似,但是比层序法的优点在于,不用按照满二叉树的那种方法输入很多的空格。只需要输入必要的左子树和右子树就行。建立书上131页算法6.4同样二叉树,我的算法不需要按照先序遍历的方式输入,只需要按层输入就行。但与层序法相比的优点又在于,不需要输入很多的空结点。
调试结果如下:
二.遍历二叉树的新算法(以中序遍历为例)
首先,定义双向链表。
typedef struct SH{
int depth;
YLNode *address;
struct SH *prior;
struct SH *next;
}SH,*SHLinkList;//双向链表
其中的address是YLNode类型的,用来存放每一个结点的空间位置。遍历函数先把头结点加入双向链表,然后对头结点分析,如果有左子树,则把左子树插到头结点的左边。如果有右子树,把子树插到头结点的右边。
if((zz->address)->lchild)
{
flag=1;
SH *ll;
ll=(SH *)malloc(sizeof(SH));
ll->address=(zz->address)->lchild;
ll->depth=cb+1;
(zz->prior)->next=ll;
ll->prior=zz->prior;
ll->next=zz;
zz->prior=ll;
}
以此方法,一层层向下分析。分别设cb和ce为开始层和结尾层,以此来控制循环。直到有一层所有的结点都没有子树,则跳出循环。
zz=tt->next;
printf("\n中序遍历的结果是:\n");
while((zz->next)!=NULL)
{
printf("%c",(zz->address)->data);
zz=zz->next;
}
然后再用双向链表按顺序输出遍历的结果。详见第8页附录里面的源程序的中序遍历。
三.新的算法与以前算法的混合检验
1、检验新的创建二叉树的算法。用新的算法创建二叉树,用旧的递归遍历的算法。
void inorder(struct node *T)
{
if(!T)
return;
else
{
inorder(T->lchild );
cout<<T->data;
inorder(T->rchild );
}
}
详见第15页附录里面的混合检验1,用中序遍历检验。调试成功,结果如下:
2、检验新的遍历算法。用书上131页的算法6.4先序遍历法创建二叉树,用新的遍历的算法来遍历。
详见第17页附录里面的混合检验2,用书上131页的算法6.4先序建立二叉树,再用新的遍历算法遍历。调试成功,结果如下。
巧克力
附录:
//源程序
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#define NULL 0
typedef struct YLNode{
int data; //结点数据
int ceng; //结点的层数
struct YLNode *lchild;
struct YLNode *rchild;
}YLNode,*YL;
typedef struct SH{ //双向链表
int depth; //深度
YLNode *address; //在遍历的时候,在链表上存放每个结点的地址
struct SH *prior;
struct SH *next;
}SH,*SHLinkList;//双向链表
void zhongxu(YLNode *Head) //中序遍历
{
SH *HH,*tt,*ww,*zz;
HH=(SH *)malloc(sizeof(SH)); //对应二叉树头结点
tt=(SH *)malloc(sizeof(SH)); //链表头结点
ww=(SH *)malloc(sizeof(SH)); //链表尾结点
zz=(SH *)malloc(sizeof(SH)); //链表中间的结点
HH->address=Head; //用来放二叉树头结点的地址
HH->prior=tt;
HH->next=ww;
HH->depth=1;
tt->prior=NULL;
tt->next=HH;
ww->next=NULL;
ww->prior=HH;
int cb=1,ce=1; //cb代表开始的层数,ce代表结束的层数
zz=tt->next; //链表头结点的后一个
while(cb<=ce)
{
char flag=0;
int bb=0;
zz=tt->next; //定位链表头结点的后一个
while((zz->next)!=NULL) //到达尾结点时跳出
{
//跳过不属于这一层的点
while(zz->depth!=cb) { if(zz->next==ww) {bb=1;break; } zz=zz->next; }
if(bb==1) break;
if((zz->address)->lchild) //如果有左子树,则插入当前结点的前面
{
flag=1;
SH *ll;
ll=(SH *)malloc(sizeof(SH));
ll->address=(zz->address)->lchild;
ll->depth=cb+1;
(zz->prior)->next=ll;
ll->prior=zz->prior;
ll->next=zz;
zz->prior=ll;
}
if((zz->address)->rchild) //如果有右子树,则插入到当前结点的后面
{
flag=1;
SH *rr;
rr=(SH *)malloc(sizeof(SH));
rr->depth=cb+1;
rr->address=(zz->address)->rchild;
(zz->next)->prior=rr;
rr->next=zz->next;
rr->prior=zz;
zz->next=rr;
}
zz=zz->next; //分析链表上下一个点
}
if(flag==1) ce++; //结束层加一
//if(flag==0) break;
cb++; //分析下一层的点
}
zz=tt->next; //链表头结点的后一个
printf("\n中序遍历的结果是:\n");
while((zz->next)!=NULL)
{
printf("%c",(zz->address)->data);
zz=zz->next;
}
printf("\n");
}
void qianxu(YLNode *Head) //前序遍历
{
SH *HH,*tt,*ww,*zz;
HH=(SH *)malloc(sizeof(SH));
tt=(SH *)malloc(sizeof(SH));
ww=(SH *)malloc(sizeof(SH));
zz=(SH *)malloc(sizeof(SH));
HH->address=Head;
HH->prior=tt;
HH->next=ww;
HH->depth=1;
tt->prior=NULL;
tt->next=HH;
ww->next=NULL;
ww->prior=HH;
int cb=1,ce=1;
zz=tt->next;
while(cb<=ce)
{
char flag=0;
int bb=0;
zz=tt->next;
while((zz->next)!=NULL)
{
while(zz->depth!=cb) { if(zz->next==ww) {bb=1;break; } zz=zz->next; }
if(bb==1) break;
if((zz->address)->rchild)
{
flag=1;
SH *rr;
rr=(SH *)malloc(sizeof(SH));
rr->depth=cb+1;
rr->address=(zz->address)->rchild;
(zz->next)->prior=rr;
rr->next=zz->next;
rr->prior=zz;
zz->next=rr;
}
if((zz->address)->lchild)
{
flag=1;
SH *ll;
ll=(SH *)malloc(sizeof(SH));
ll->address=(zz->address)->lchild;
ll->depth=cb+1;
(zz->next)->prior=ll;
ll->next=zz->next;
ll->prior=zz;
zz->next=ll;
}
zz=zz->next;
}
if(flag==1) ce++;//if(flag==0) break;
cb++;
}
zz=tt->next;
printf("\n前序遍历的结果是:\n");
while((zz->next)!=NULL)
{
printf("%c",(zz->address)->data);
zz=zz->next;
}
printf("\n");
}
void houxu(YLNode *Head) //后序遍历
{
SH *HH,*tt,*ww,*zz;
HH=(SH *)malloc(sizeof(SH));
tt=(SH *)malloc(sizeof(SH));
ww=(SH *)malloc(sizeof(SH));
zz=(SH *)malloc(sizeof(SH));
HH->address=Head;
HH->prior=tt;
HH->next=ww;
HH->depth=1;
tt->prior=NULL;
tt->next=HH;
ww->next=NULL;
ww->prior=HH;
int cb=1,ce=1;
zz=tt->next;
while(cb<=ce)
{
char flag=0;
int bb=0;
zz=tt->next;
while((zz->next)!=NULL)
{
while(zz->depth!=cb) { if(zz->next==ww) {bb=1;break; } zz=zz->next; }
if(bb==1) break;
if((zz->address)->lchild)
{
flag=1;
SH *ll;
ll=(SH *)malloc(sizeof(SH));
ll->address=(zz->address)->lchild;
ll->depth=cb+1;
(zz->prior)->next=ll;
ll->prior=zz->prior;
ll->next=zz;
zz->prior=ll;
}
if((zz->address)->rchild)
{
flag=1;
SH *rr;
rr=(SH *)malloc(sizeof(SH));
rr->depth=cb+1;
rr->address=(zz->address)->rchild;
(zz->prior)->next=rr;
rr->prior=zz->prior;
rr->next=zz;
zz->prior=rr;
}
zz=zz->next;
}
if(flag==1) ce++;//if(flag==0) break;
cb++;
}
zz=tt->next;
printf("\n后序遍历的结果是:\n");
while((zz->next)!=NULL)
{
printf("%c",(zz->address)->data);
zz=zz->next;
}
printf("\n");
}
void main()
{
YLNode *w[100],*Head; // 定义w[]为100个元素的YLNode的数组
printf("请输入头结点的数据\n");
int d,dl,dr,b=0,e=0; //b为开始层数,e为结束层数
d=getchar();
getchar();
if(d!=' ')
{
w[0]=(YLNode *)malloc(sizeof(YLNode));
w[0]->data=d;
w[0]->ceng=1; //头结点的层数
Head=w[0];
}
while(b<=e)
{
while(w[b]->data==NULL) b++;
printf("请输入第");printf("%d",w[b]->ceng); printf("层的结点");printf("%c",w[b]->data);printf("的左子树\n");
dl=getchar();
getchar();
if(dl!=' ')
{
YLNode *ll;
ll=(YLNode *)malloc(sizeof(YLNode));
ll->data=dl;
ll->ceng=(w[b]->ceng)+1; //层数为当前结点层数的下一层
e++;
w[e]=ll;
w[b]->lchild=ll; //创建关系
}
else w[b]->lchild=NULL; //否则字数为空
printf("请输入第");printf("%d",w[b]->ceng); printf("层的结点");printf("%c",w[b]->data);printf("的右子树\n");
dr=getchar();
getchar();
if(dr!=' ')
{
YLNode *rr;
rr=(YLNode *)malloc(sizeof(YLNode));
rr->data=dr;
rr->ceng=(w[b]->ceng)+1;
e++;
w[e]=rr;
w[b]->rchild=rr;
}
else w[b]->rchild=NULL;
b++;
}
printf("\n");
qianxu(Head);
zhongxu(Head);
houxu(Head);
}
//混合检验1
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#define NULL 0
typedef struct YLNode{
int data;
int ceng;
struct YLNode *lchild;
struct YLNode *rchild;
}YLNode,*YL;
typedef struct SH{
int depth;
YLNode *address;
struct SH *prior;
struct SH *next;
}SH,*SHLinkList;//双向链表
void inorder(YLNode *T) //递归中序遍历
{
if(!T)
return;
else
{
inorder(T->lchild );
printf("%c",T->data);
inorder(T->rchild );
}
}
void main()
{
YLNode *w[100],*Head;
printf("请输入头结点的数据\n");
int d,dl,dr,b=0,e=0;
d=getchar();
getchar();
if(d!=' ')
{
w[0]=(YLNode *)malloc(sizeof(YLNode));
w[0]->data=d;
w[0]->ceng=1;
Head=w[0];
}
while(b<=e)
{
while(w[b]->data==NULL) b++;
printf("请输入第");printf("%d",w[b]->ceng); printf("层的结点");printf("%c",w[b]->data);printf("的左子树\n");
dl=getchar();
getchar();
if(dl!=' ')
{
YLNode *ll;
ll=(YLNode *)malloc(sizeof(YLNode));
ll->data=dl;
ll->ceng=(w[b]->ceng)+1;
e++;
w[e]=ll;
w[b]->lchild=ll;
}
else w[b]->lchild=NULL;
printf("请输入第");printf("%d",w[b]->ceng); printf("层的结点");printf("%c",w[b]->data);printf("的右子树\n");
dr=getchar();
getchar();
if(dr!=' ')
{
YLNode *rr;
rr=(YLNode *)malloc(sizeof(YLNode));
rr->data=dr;
rr->ceng=(w[b]->ceng)+1;
e++;
w[e]=rr;
w[b]->rchild=rr;
}
else w[b]->rchild=NULL;
b++;
}
printf("\n");
inorder(Head); //递归中序遍历
printf("\n");
printf("\n");
}
//混合检验2
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#define NULL 0
typedef struct BitNode{
int data;
struct BitNode *lchild;
struct BitNode *rchild;
}BitNode,*BiTTree;
typedef struct SH{
int depth;
BitNode *address;
struct SH *prior;
struct SH *next;
}SH,*SHLinkList;//双向链表
struct BitNode * creatbitree(struct BitNode *r)
{
char a;
a=getchar();
getchar();
if(a==' ') return r=NULL;
else
{ r=(struct BitNode*)malloc(sizeof(BitNode));
r->data=a;
r->lchild=creatbitree(r->lchild);
r->rchild=creatbitree(r->rchild);
}
return r;
}
void zhongxu(BitNode *Head)
{
SH *HH,*tt,*ww,*zz;
HH=(SH *)malloc(sizeof(SH));
tt=(SH *)malloc(sizeof(SH));
ww=(SH *)malloc(sizeof(SH));
zz=(SH *)malloc(sizeof(SH));
HH->address=Head;
HH->prior=tt;
HH->next=ww;
HH->depth=1;
tt->prior=NULL;
tt->next=HH;
ww->next=NULL;
ww->prior=HH;
int cb=1,ce=1;
zz=tt->next;
while(cb<=ce)
{
char flag=0;
int bb=0;
zz=tt->next;
while((zz->next)!=NULL)
{
while(zz->depth!=cb) { if(zz->next==ww) {bb=1;break; } zz=zz->next; }
if(bb==1) break;
if((zz->address)->lchild)
{
flag=1;
SH *ll;
ll=(SH *)malloc(sizeof(SH));
ll->address=(zz->address)->lchild;
ll->depth=cb+1;
(zz->prior)->next=ll;
ll->prior=zz->prior;
ll->next=zz;
zz->prior=ll;
}
if((zz->address)->rchild)
{
flag=1;
SH *rr;
rr=(SH *)malloc(sizeof(SH));
rr->depth=cb+1;
rr->address=(zz->address)->rchild;
(zz->next)->prior=rr;
rr->next=zz->next;
rr->prior=zz;
zz->next=rr;
}
zz=zz->next;
}
if(flag==1) ce++;//if(flag==0) break;
cb++;
}
zz=tt->next;
printf("\n中序遍历的结果是:\n");
while((zz->next)!=NULL)
{
printf("%c",(zz->address)->data);
zz=zz->next;
}
printf("\n");
}
void main()
{
printf("先序输入\n");
BitNode *Head;
Head=creatbitree(Head); /*创建二叉树*/
zhongxu(Head);
}
2011年12月22日