一、树的基本术语:
结点的度:结点拥有的子树数
树的度:树内各结点的度的最大值
叶子:度为0的结点
分支结点:度不为0的结点
深度:树中结点的最大层次
二、二叉树
在讨论一般树之前,我们讨论二叉树:1)每个结点最多只有两棵子树;2)二叉树的子树有左右之分
1、二叉树的基本性质
。。。。。
2、二叉树的存储结构
顺序存储结构仅适用于完全二叉树,所以一般使用链式存储结构(二叉链表、三叉链表);
二叉树的二叉链表存储表示
:
typedef
struct
BiTNode{
TElemType data;
struct
BitNode *lchild,*rchild;
}BiTNode,*BiTree;
|
三、二叉树的基本操作
#include
<iostream>
#include
<cstdio>
#include
<cstring>
#include
<cstdlib>
using
namespace
std;
typedef
struct
BiTNode
{
char
data;
struct
BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
int
Max(
int
x,
int
y)
{
return
x>y?x:y;
}
void
Create(BiTree &T)
//
先序建一颗二叉树
{
char
ch;
scanf(
"%c"
,&ch);
if
(ch==
'#'
)
T=NULL;
else
{
T=(BiTNode *)malloc(
sizeof
(BiTNode));
T->data=ch;
Create(T->lchild);
Create(T->rchild);
}
}
void
Preorder(BiTree &root)
//
先序遍历打印二叉树
{
if
(root!=NULL)
{
printf(
"%c "
,root->data);
Preorder(root->lchild);
Preorder(root->rchild);
}
}
void
Inorder(BiTree &root)
//
中序遍历打印二叉树
{
if
(root!=NULL)
{
Inorder(root->lchild);
printf(
"%c "
,root->data);
Inorder(root->rchild);
}
}
void
Postorder(BiTree &root)
//
后续遍历打印二叉树
{
if
(root!=NULL)
{
Postorder(root->lchild);
Postorder(root->rchild);
printf(
"%c "
,root->data);
}
}
void
Preorderleaf(BiTree &root)
//
先序遍历输出叶子节点
{
if
(root!=NULL)
{
if
(root->lchild==NULL&&root->rchild==NULL)
printf(
"%c "
,root->data);
Preorderleaf(root->lchild);
Preorderleaf(root->rchild);
}
}
int
LeafCount(BiTree &root)
//
统计叶子节点的个数
{
int
leaf;
if
(root==NULL)
leaf=0;
else
if
(root->lchild==NULL&&root->rchild==NULL)
leaf=1;
else
leaf=LeafCount(root->lchild)+LeafCount(root->rchild);
return
leaf;
}
int
PostTreeDepth(BiTree &root)
//
统计树的高度
{
int
hl,hr,max;
if
(root!=NULL)
{
hl=PostTreeDepth(root->lchild);
hr=PostTreeDepth(root->rchild);
max=Max(hl,hr);
return
max+1;
}
else
return
0;
}
void
dowork()
{
BiTree cam;
Create(cam);
Preorder(cam);
//
先序遍历
printf(
"\n"
);
Inorder(cam);
//
中序遍历
printf(
"\n"
);
Postorder(cam);
//
后续遍历
printf(
"\n"
);
printf(
"
叶子节点:
"
);
Preorderleaf(cam);
printf(
"\n"
);
printf(
"
叶子节点的个数为
:%d\n"
,LeafCount(cam));
printf(
"
树的深度为
:%d\n"
,PostTreeDepth(cam));
}
int
main()
{
dowork();
return
0;
}
|
下面的代码是可以运行的,在《零基础学算法》中有,直接拷贝过来。
main.cpp中
#include <stdio.h>
#include "3-1 BinTree.c"
void oper(ChainBinTree *p) //操作二叉树结点数据
{
printf("%c ",p->data); //输出数据
return;
}
ChainBinTree *InitRoot() //初始化二叉树的根
{
ChainBinTree *node;
if(node=(ChainBinTree *)malloc(sizeof(ChainBinTree))) //分配内存
{
printf("\n输入根结点数据:");
scanf("%s",&node->data);
node->left=NULL;
node->right=NULL;
return BinTreeInit(node);
}
return NULL;
}
void AddNode(ChainBinTree *bt) //添加结点
{
ChainBinTree *node,*parent;
DATA data;
char select;
if(node=(ChainBinTree *)malloc(sizeof(ChainBinTree))) //分配内存
{
printf("\n输入二叉树结点数据:");
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.添加到左子树\n2.添加到右子树\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)(); //指向函数的指针
oper1=oper; //指向具体操作的函数
do{
printf("\n1.设置二叉树根元素 2.添加二叉树结点\n");
printf("3.先序遍历 4.中序遍历\n");
printf("5.后序遍历 6.按层遍历\n");
printf("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");
break;
case '6'://按层遍历
printf("\n按层遍历的结果:");
BinTree_Level(root,oper1);
printf("\n");
break;
case '7'://二叉树的深度
printf("\n二叉树深度为:%d\n",BinTreeDepth(root));
break;
case '0':
break;
}
}while(select!='0');
BinTreeClear(root);//清空二叉树
root=NULL;
getch();
return 0;
}
3-1BinTree.cpp中
#include <stdio.h>
#include <stdlib.h>
#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;
}
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->left=node;
break;
case 2://添加到右结点
if( bt->right) //右子树不为空
{
printf("右子树结点不为空!\n");
return 0;
}else
bt->right=node;
break;
default:
printf("参数错误!\n");
return 0;
}
return 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 BinTreeIsEmpty(ChainBinTree *bt) //检查二叉树是否为空,为空则返回1,否则返回0
{
if(bt)
return 0;
else
return 1;
}
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;
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;
}
}
}
void BinTreeClear(ChainBinTree *bt) // 清空二叉树,使之变为一棵空树
{
if(bt)
{
BinTreeClear(bt->left); //清空左子树
BinTreeClear(bt->right);//清空右子树
free(bt);//释放当前结点所占内存
bt=NULL;
}
return;
}
void BinTree_DLR(ChainBinTree *bt,void (*oper)(ChainBinTree *p)) //先序遍历
{
if(bt)//树不为空,则执行如下操作
{
oper(bt); //处理结点的数据
BinTree_DLR(bt->left,oper);
BinTree_DLR(bt->right,oper);
}
return;
}
void BinTree_LDR(ChainBinTree *bt,void(*oper)(ChainBinTree *p)) //中序遍历
{
if(bt)//树不为空,则执行如下操作
{
BinTree_LDR(bt->left,oper); //中序遍历左子树
oper(bt);//处理结点数据
BinTree_LDR(bt->right,oper); //中序遍历右子树/
}
return;
}
void BinTree_LRD(ChainBinTree *bt,void (*oper)(ChainBinTree *p)) //后序遍历
{
if(bt)
{
BinTree_LRD(bt->left,oper); //后序遍历左子树
BinTree_LRD(bt->right,oper); //后序遍历右子树/
oper(bt); //处理结点数据
}
return;
}
void oper(ChainBinTree *p) //操作二叉树结点数据
{
printf("%c ",p->data); //输出数据
return;
}
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;
}