二叉树是应用非常广泛的结构,其基本实现如下:
结点结构:也就是使用二叉链表实现
typedef struct Node //树结点结构
{
char data;
struct Node *lchild;
struct Node *rchild;
}BitreeNode,*Bitree;
//先序建立二叉树
Bitree create()
{
Bitree T;
char ch;
scanf("%c",&ch);
if(ch=='#')
T=NULL;
else
{
T=(Bitree)malloc(sizeof(BitreeNode));
if(!T)
exit(0);
T->data=ch;
T->lchild=create();
T->rchild=create();
}
return T;
}
树结构结点用得是孩子兄弟表示法
当输入#时代表该结点为空,但由于是扩展二叉树,这个结点依旧需要输入。
二叉树的遍历
仔细看书理解二叉树的前中后层序遍历的每一步实现过程,特别是递归和返回到上一级递归的过程
/*遍历二叉树*/
//前序遍历
void Preorder(Bitree T)
{
if(T==NULL)
return;
else
{
printf("%c",T->data);
Preorder(T->lchild);
Preorder(T->rchild);
}
}
//中序遍历
void Inorder(Bitree T)
{
if(T==NULL)
return;
else
{
Preorder(T->lchild);
printf("%c",T->data);
Preorder(T->rchild);
}
}
//后序遍历
void Postorder(Bitree T)
{
if(T==NULL)
return;
else
{
Preorder(T->lchild);
Preorder(T->rchild);
printf("%c",T->data);
}
}
如在中序中,Inorder为NULL后才会执行printf,即打印的第一个结点是从根节点开始执行左子树遍历后找到的第一个无左孩子的结点
在后序中,Post(T->lchild),Post(T->rchild),都为NULL后才会执行printf,即输出的结点是叶子结点
二叉树的销毁
//销毁以T为根结点的树
Bitree Destory(Bitree T) //释放所有结点,并将指向树根的指针置空
{
if(T)
{
Destory(T->lchild);
Destory(T->rchild);
free(BT);
}
return NULL;
}
另一种写法
void Destory(Bitree T)
{
if(T)
{
Destory(T->lchild);
Destory(T->rchild);
delete T;
T=NULL;
}
}
注意:用后序进行销毁最好,先序的话根被销毁之前需要两个变量保存T的左右孩子,中序则需要保存右孩子
此算法可用于销毁整棵树或子树,T是根指针
二叉树结点的查找
//查找二叉树中结点值为c的结点
Bitree FindNode(Bitree T,char c)
{
if(T==NULL)
return;
else if(T->data==c) //c是根结点时
return T;
Bitree BT=NULL;
BT=FindNode(BT->lchild,c);
if(BT==NULL) //说明左子树结点不存在c
BT=FindNode(BT->rchild,c);
return BT;
}
需要注意的是讨论c是否是根结点
Bitree FindNode(Bitree BT,const char &c)效率更佳
二叉树深度
//求二叉树的深度
int BitreeDepth(Bitree T)
{
if(T==NULL)
return 0;
else
{
int left=BitreeDepth(T->lchild);
int right=BitreeDepth(T->rchild);
return (left>right?left:right)+1;
}
}
求二叉树中某结点的双亲结点
//求二叉树中某结点的双亲结点
Bitree GetParent(Bitree T,char c)
{
if(!T||T->data==c) //当c不存在于树中或根结点是c
return NULL;
if((T->lchild&&T->lchild->data==c)||(T->lchild&&T->rchild->data==c))
return T;
Bitree parent=NULL;
parent=GetParent(T->lchild,c);
if(parent==NULL)
parent=GetParent(T->rchild,c);
return parent;
}
求二叉树中结点的最大最小值
//结点的最大最小值
Bitree MaxNode(Bitree T)
{
if(T==NULL)
return NULL;
Bitree Max=T;
Bitree t=MaxNode(T->lchild);
if(t!=NULL)
{
if(t->data>Max->data)
Max=t;
}
t=MaxNode(T->rchild);
if(t!=NULL)
{
if(t->data>Max->data)
Max=t;
}
return Max;
}
需要注意左右子树是否存在,求最小值的算法一样。
求二叉树中叶子结点,非叶子结点的个数
//求叶子结点的个数
int Leaves(Bitree T)
{
int count=0;
if(T==NULL)
return 0;
if(T->lchild==NULL&&T->rchild==NULL)
count++;
else
{
count+=Leaves(T->lchild);
count+=Leaves(T->rchild);
}
return count;
}
//非叶子结点的个数
int NotLeaves(Bitree T)
{
int count;
if(T==NULL||(T->lchild==NULL&&T->rchild==NULL))
return 0;
else
{
count=1;
count+=NotLeaves(T->lchild);
count+=NotLeaves(T->rchild);
}
return count;
}
将二叉树的结点左右孩子互换
//交换二叉树的左右孩子
void exchange(Bitree T)
{
if(T==NULL)
return NULL;
Bitree t=NULL;
if(T->lchild!=NULL&&T->rchild!=NULL) //左右都不为空时交换
{
t=T->lchild;
T->lchild=T->rchild;
T->rchild=t;
}
exchange(T->lchild);
exchange(T->rchild);
}
要注意的是exchang要递归两次分别进行根结点左右子树的互换
全部代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
char data;
struct Node *lchild;
struct Node *rchild;
}BitreeNode,*Bitree;
//先序建立二叉树
Bitree create()
{
Bitree T;
char ch;
scanf("%c",&ch);
if(ch=='#')
T=NULL;
else
{
T=(Bitree)malloc(sizeof(BitreeNode));
if(!T)
exit(0);
T->data=ch;
T->lchild=create();
T->rchild=create();
}
return T;
}
/*遍历二叉树*/
//前序遍历
void Preorder(Bitree T)
{
if(T==NULL)
return;
else
{
printf("%3c",T->data);
Preorder(T->lchild);
Preorder(T->rchild);
}
}
//中序遍历
void Inorder(Bitree T)
{
if(T==NULL)
return;
else
{
Preorder(T->lchild);
printf("%3c",T->data);
Preorder(T->rchild);
}
}
//后序遍历
void Postorder(Bitree T)
{
if(T==NULL)
return;
else
{
Preorder(T->lchild);
Preorder(T->rchild);
printf("%3c",T->data);
}
}
//层序遍历
//销毁以T为根结点的树
Bitree Destory(Bitree T)
{
if(T)
{
Destory(T->lchild);
Destory(T->rchild);
free(T);
}
return NULL;
}
/*
void Destory(Bitree T)
{
if(T)
{
Destory(T->lchild);
Destory(T->rchild);
delete T;
T=NULL;
}
}*/
//查找二叉树中结点值为c的结点
Bitree FindNode(Bitree T,char c)
{
if(T==NULL)
return NULL;
else if(T->data==c) //c是根结点时
return T;
Bitree BT=NULL;
BT=FindNode(BT->lchild,c);
if(BT==NULL) //说明左子树结点不存在c
BT=FindNode(BT->rchild,c);
return BT;
}
//求二叉树的深度
int BitreeDepth(Bitree T)
{
if(T==NULL)
return 0;
else
{
int left=BitreeDepth(T->lchild);
int right=BitreeDepth(T->rchild);
return (left>right?left:right)+1;
}
}
//求二叉树中某结点的双亲结点
Bitree GetParent(Bitree T,char c)
{
if(!T||T->data==c) //当c不存在于树中或根结点是c
return NULL;
if((T->lchild&&T->lchild->data==c)||(T->lchild&&T->rchild->data==c))
return T;
Bitree parent=NULL;
parent=GetParent(T->lchild,c);
if(parent==NULL)
parent=GetParent(T->rchild,c);
return parent;
}
//结点的最大最小值
Bitree MaxNode(Bitree T)
{
if(T==NULL)
return NULL;
Bitree Max=T;
Bitree t=MaxNode(T->lchild);
if(t!=NULL)
{
if(t->data>Max->data)
Max=t;
}
t=MaxNode(T->rchild);
if(t!=NULL)
{
if(t->data>Max->data)
Max=t;
}
return Max;
}
//求叶子结点的个数
int Leaves(Bitree T)
{
int count=0;
if(T==NULL)
return 0;
if(T->lchild==NULL&&T->rchild==NULL)
count++;
else
{
count+=Leaves(T->lchild);
count+=Leaves(T->rchild);
}
return count;
}
//非叶子结点的个数
int NotLeaves(Bitree T)
{
int count;
if(T==NULL||(T->lchild==NULL&&T->rchild==NULL))
return 0;
else
{
count=1;
count+=NotLeaves(T->lchild);
count+=NotLeaves(T->rchild);
}
return count;
}
//交换二叉树的左右孩子
void exchange(Bitree T)
{
if(T==NULL)
return;
Bitree t=NULL;
if(T->lchild!=NULL&&T->rchild!=NULL) //左右都不为空时交换
{
t=T->lchild;
T->lchild=T->rchild;
T->rchild=t;
}
exchange(T->lchild);
exchange(T->rchild);
}
int main()
{
Bitree T=NULL;
T=create();
printf("二叉树创建成功\n");
printf("二叉树的深度:");
printf("%d",BitreeDepth(T));
printf("\n叶子结点数:");
printf("%d",Leaves(T));
printf("\n前序遍历:\n");
Preorder(T);
printf("\n");
printf("中序遍历:\n");
Inorder(T);
printf("\n");
printf("后序遍历:\n");
Postorder(T);
return 0;
}
我们输入一个简单的二叉树验证,#代表空节点,按照前序遍历顺序二叉树表示为:ab##c##:
运行情况:
需要注意的是创建二叉树就要以扩展二叉树的形式输入,即空的结点用#补起来。