二叉树的基本操作:"二叉树基本操作.cpp"
首先定义二叉链式结构:
#include
#include
#define QUEUE_MAXSIZE 50 //队列大小
typedef char DATA; //定义元素类型
typedef struct ChainTree
{
DATA data;
struct ChainTree *left; //左子树结点指针
struct ChainTree *right; //右子树指针
} ChainBinTree;
ChainBinTree *BinTreeInit(ChainBinTree *node) //初始化二叉树根结点
{
if(node!=NULL) //二叉树根结点不为空
return node;
else
return NULL;
}
node为一个二叉树结点的指针,若node结点不空,返回该结点指针的值作为二叉树的根结点
添加结点到二叉树:
int BinTreeAddNode(ChainBinTree *bt,ChainBinTree *node,int n) //添加结点
//bt为父结点,node为子结点,n=1表示添加到左子树,n=2表示添加到右子树
{
if(bt==NULL)
{
printf("父结点不存在,先设置父结点\n");
return 0;
}
switch(n)
{
case 1:
if(bt->left) //左子树不为空
{
printf("左子树结点不为空\n");
return 0;
}else //父结点bt的左子树为空,将结点node添加到左子树
bt->left=node;
break;
case 2:
if(bt->right) //右子树不为空
{
printf("右子树结点不为空\n");
return 0;
} else
bt->right=node; //结点node添加到右子树
break;
default:
printf("参数错误\n");
return 0;
}
return 1; //1表示添加成功
}
获取二叉树的左右子树:
ChainBinTree *BinTreeLeft(ChainBinTree *bt) //返回左子结点
{
if(bt) //根结点存在
return bt->left;
else
return NULL;
}
ChainBinTree *BinTreeRight(ChainBinTree *bt) //返回右子结点
{
if(bt)
return bt->right;
else
return NULL;
}
计算树的深度
int BinTreeDepth(ChainBinTree *bt) //求二叉树深度
{
int dep1,dep2;
if(bt==NULL)
return 0; //对于空树,深度为0
else{
dep1=BinTreeDepth(bt->left);
dep2=BinTreeDepth(bt->right); //递归调用左右子树深度
if(dep1>dep2)
return dep1+1; //加1表示加上根结点,整个树的深度
else
return dep2+1;
}
}
ChainBinTree *BinTreeFind(ChainBinTree *bt,DATA data); //在二叉树中找值为data的结点
{
ChainBinTree *p;
if(bt==NULL)
return NULL;
else{
if(bt->data==data)
return bt;
else{ //分别向左右子树递归查找
if(p=BinTreeFind(bt->left,data))
return p;
else if(p=BinTreeFind(bt->right,data))
return p;
else
return NULL;
}
}
}
清空二叉树:在向二叉树添加结点时,每个结点都是由malloc函数申请分配内存,清空时用free释放
void BinTreeClear(ChainBinTree *bt) //清空二叉树,
{
if(bt)
{
BinTreeClear(bt->left); //清空左子树
BinTreeClear(bt->right); //清空右子树
free(bt);
bt=NULL;
}
return;
}
遍历是对二叉树的基本操作,所谓遍历二叉树就是按照一定规则和顺序走遍二叉树所有子树,使每一个结点都被访问一次
遍历有四种方法:先序遍历,中序遍历,后序遍历,按层遍历。
对下图:D(data)表示根节点,L(left)表示左子树,R(right)表示右子树
先序遍历(DLR):先访问根节点,在按先序遍历左子树,最后按先序遍历右子树
中序遍历(LDR):先按中序遍历左子树,再访问根结点,最后按中序遍历右结点
后序遍历(LRD):先后序遍历左子树,再后序遍历右子树,最后再访问根结点
先序遍历:
//先序遍历
void BinTree_DLR(BinTree)
{
if(bt) //树不为空,
{
oper(bt); //处理结点数据
BinTree_DLR(bt->left,oper); //递归处理左子树和右子树
BinTree_DLR(bt->right,oper);
}
return; //递归结束
}
bt为需要遍历的根结点,函数oper是一个需要对结点进行操作的函数。
//中序遍历
void BinTree_LDR(BinTree)
{
if(bt)
{
BinTree_LDR(bt->left,oper); //中序遍历左子树
oper(bt);
BinTree_LDR(bt->right,oper);
}
return;
}
//后序遍历
void BinTree_LRD(BinTree)
{
if(bt)
{
BinTree_LDR(bt->left,oper);
BinTree_LDR(bt->right,oper);
oper(bt);
}
return;
}
对下图:
先序遍历后各结点顺序:A,B,D,H,I,E,J,K,C,F,L,G。
中序遍历后各节点顺序:H,D,I,B,J,E,K,A,L,F,C,G
后序遍历后各结点顺序:H,I,D,J,K,E,B,L,F,G,C,A
按层遍序:对上面所示的二叉树,共有四层,按层遍历得到的顺序就是:A,B,C,D,E,F,G,H,I,J,K,L
由于二叉树按层遍历,使用循环队列进行处理,实现逐层遍历:
//按层遍历
void BinTree_Level(ChainBinTree *bt,void (*oper)(ChainBinTree *p))
{
ChainBinTree *p;
ChainBinTree *q[QUEUE_MAXSIZE]; //定义一个顺序队列
int head=0,tail=0;
if(bt) //若队首指针不空
{
tail=(tail+1)%QUEUE_MAXSIZE; //计算循环队列的队尾序号
q[tail]=bt; //将二叉树根指针入队
}
while(head!=tail) //队列不为空,进行循环
{
head=(head+1)%QUEUE_MAXSIZE; //计算循环队列的队首序号
p=q[head]; //获取队首元素
oper(p); //处理队首元素
if(p->left!=NULL) //结点有左子树,则左子树指针进队
{
tail=(tail+1)%QUEUE_MAXSIZE;
q[tail]=p->left; //将左子树指针进队
}
if(p->right!=NULL) //结点有右子树;右子树指针进队
{
tail=(tail+1)%QUEUE_MAXSIZE;
q[tail]=p->right;
}
}
return;
}
首先从根结点开始,每层的结点逐步进入队列,这样就可得到按层遍历的效果。
以上是二叉树相关操作,接下来是测试这些操作的:
#include
#include
#include "二叉树基本操作.cpp"
void oper(chainBinTree *p) //操作二叉树结点的数据
{
printf("%c",p->data); //在本例中函数的操作只是输出结点中的字符即可
return;
}
ChainBinTree *InitRoot() //创建二叉树根结点
{
ChainBinTree *node;
if(node=(ChainBinTree *)malloc(sizeof(ChainBinTree)))
{
printf("输入根结点数据:");
scanf("%s",&node->data);
node->left=NULL;
node->right=NULL;
return node; //返回根结点
}
return NULL;
}
void Addnode(ChainBinTree *bt) //给二叉树添加子结点
{
ChainBinTree *node,*parent;
DATA data;
char select;
if(node=(ChainBinTree *)malloc(sizeof(ChainBinTree)))
{
printf("输入二叉树结点数据:");
fflush(stdin); //清空输入缓存区
scanf("%s",&node-data);
node->left=NULL;
node->right->NULL;
printf("输入父结点数据:"); //提示输入父结点数据,将该结点作为新增结点的父结点
fflush(stdin);
scanf("%s",&data);
parent=BinTreeFind(bt,data); //查找指定数据的结点
if(!parent) //没有找到指定 数据 的结点
{
printf("没有找到父结点\n");
free(node); //释放创建结点的内存
return;
}
printf(1.添加到左子树\n 2.添加到右子树\n);
do{
select=getch();
select-='0';
if(select==1||select==2)
BinTreeAddNode(parent,node,select); //新增加的结点添加到指针父结点下,完成结点添加操作
}while(select!=1&&select!=2);
}
return;
}
int main()
{
ChainBinTree *root=NULL; //root是指向二叉树根结点的指针
char select;
void (*oper1)(); //指向函数的指针,将测试程序中编写的函数oper赋值给该指针,用来处理各结点数据
oper1=oper; //指向具体的操作函数
do{
printf("\n1.设置二叉树的根元素 2.添加二叉树的结点\n");
printf("3.先序遍历 4.中序遍历 5.后序遍历 6、按层遍历"\n);
ptintf("7.二叉树的深度 0.退出\n");
select=getch();
switch(select){
case '1':
root=InitRoot();
break;
case '2':
AddNode(root);
break;
case '3':
printf("\n先序遍历结果:");
BinTree_DLR(root,oper1);
printf("\n");
break;
case '4':
printf("\n中序遍历结果:");
BinTree_LDR(root,oper1);
printf("\n");
break;
case '5':
printf("\n后序遍历的结果:");
BinTree_LRD(root,oper1);
printf("\n");
case '6':
printf("按层遍历结果:");
BinTree_level1(root,oper1);
printf("\n");
break;
case '7':
printf("二叉树的深度:%d\n",BinTreeDepth(root));
break;
case '0':
break;
}
}while(select!='0');
BinTreeClear(root); //清空二叉树
root=NULL;
return 0;
}