18.12.2
(基于C语言,欢迎指正)
关于二叉树,我们知道,它的每个结点最多只有两棵子树,是一种很实用很重要很常见的树,一些基本的性质就不废话了,先从二叉树结点设定说起,我们这里用链式来实现
结点的结构体设定
每个结点有一个数据域和两个指针域,数据域用来放你想挂在树上的东西的,这里我们设为字符型char,而两个指针域,一个指向左子树,一个指向右子树
typedef char ElemType;//定义char是ElemType
typedef struct BiNode{//树的每个结点包含一个数据域和两个指针域,两个指针域分别指向左右子树的根结点
ElemType data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;//*BiTree是二叉树结点的结构体指针,一般传入函数的参数就用的是它的地址
初始化一棵树
我这里用的是先序序列来初始化一棵树,即按照根左右的顺序,每遇到一个根结点,就对其做相应的访问,然后在对左子树做处理,最后才是右子树,
注意这里传入的是结点的地址的地址,通过在地址的地址层上修改结点地址,有点绕口,比如说我们定义一个整型变量 int e; 然后想通过指针修改它的值,我们设定一个函数###(int *e),然后我们调用函数的时候要写###(&e),一个道理,只不过我们底下的T在一开始就是地址而不是像e一样是一个普通的值
void CreateBiTree(BiTree *T)//创建一棵树,传入树的结点的地址的地址
{
char ch;
scanf("%c",&ch);
if(ch=='#')
*T=NULL;//使地址指向的结点地址为空
else
{
*T=(BiTree)malloc(sizeof(BiNode));
if(!*T)
exit(1);
(*T)->data=ch;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}
递归遍历树
我们按先序(根左右)递归举例,代码很短很简单,但效率不高毕竟递归嘛,如果我们要写中序的递归,就把 printf 那句挪到 PreOrder(T->lchild) 底下就行了,后序就再往下挪一行,总之按照他们的遍历方法来决定
void PreOrder(BiTree T){//先序遍历
if(!T)
return;
printf("%C ",T->data); //先对根结点做相应操作
PreOrder(T->lchild); //然后访问左子树
PreOrder(T->rchild); //最后才到右子树
}
非递归遍历树
我们还是按照先序来写
思路是这样: 我们先有一棵树,然后还有一个栈,从根结点开始,对访问的每一个根结点先进行相应操作(毕竟是先序,根!左右嘛,先根后左右),然后把该根结点入栈,接下来访问左子树,于是我们就不断往左边走,一直到最左边停下来,发现此时左子树为空了,然后从栈中Pop一个结点,访问它的右子树的根结点,并以该根结点开始继续不断向左
思路就是这样
栈!其实吧,栈不一定是要像之前我们那样设个结构体然后有指针指来指去什么的,其实,栈是一种形式,一种方法,一种数据结构,就是本着先进后出的原则,这里我们用一个简单的数组来实现栈
void Pre(BiTree T){
BiTree p=T; //设置一个标记指针,每次都指向根结点
BiTree a[50]; //设定一个栈,也就是一个BiTree类型的数组
int i=0;
while(p||i){ //结点不为空并且栈不空
if(p){
a[i++]=p; //入栈
printf("%c ",p->data);
p=p->lchild;
}
else{
p=a[i-1]->rchild;
i--;
}
}
}
源程序调试
//二叉树链式存储实现
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType;//定义char是ElemType
typedef struct BiNode{//树的每个结点包含一个数据域和两个指针域,两个指针域分别指向左右子树的根结点
ElemType data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;
void CreateBiTree(BiTree *T)//创建一棵树,传入树的结点的地址的地址
{
char ch;
scanf("%c",&ch);
if(ch=='#')
*T=NULL;//使地址指向的结点地址为空
else
{
*T=(BiTree)malloc(sizeof(BiNode));
if(!*T)
exit(1);
(*T)->data=ch;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}
void PreOrder(BiTree T){//先序遍历
if(!T)
return;
printf("%C ",T->data);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
void InOrder(BiTree T){//中序遍历
if(!T)
return;
InOrder(T->lchild);
printf("%C ",T->data);
InOrder(T->rchild);
}
void PostOrder(BiTree T){//后序遍历
if(!T)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
printf("%C ",T->data);
}
void In(BiTree T){//中序非递归
BiTree p=T;
BiTree a[50];
int i=0;
while(p||i){
if(p){
a[i++]=p;
p=p->lchild;
}
else{
p=a[i-1];
printf("%c ",p->data);
p=a[i-1]->rchild;
i--;
}
}
}
void Pre(BiTree T){//先序非递归
BiTree p=T;
BiTree a[50];
int i=0;
while(p||i){
if(p){
a[i++]=p;
printf("%c ",p->data);
p=p->lchild;
}
else{
p=a[i-1]->rchild;
i--;
}
}
}
int main(){ //主函数调试
BiTree T;
printf("请按先序顺序输入序列,子树为空用#代替,如AB#D##C##\n");
CreateBiTree(&T);
printf("先序遍历结果为:");
PreOrder(T);
printf("\n");
printf("中序遍历结果为:");
InOrder(T);
printf("\n");
/* printf("后序遍历结果为:");
PostOrder(T);
printf("\n");*/
printf("非递归先序遍历结果为:");
Pre(T);
printf("\n非递归中序遍历结果为:");
In(T);
}