树形结构是一类重要的非线性数据结构。其中以树和二叉树最为常用。直观看来,树是以分支关系定义的层次结构。
树是n个结点的有限集,在任意一颗非空树中,有且仅有一个特定称为根的结点,当n>1时,其余结点可分为m个互不相交的有限集
T1,T2,..Tm,其中每一个集合本身又是一颗树,并且称为根的子树。
二叉树是度不大于2的有序树(每个结点最多两颗子树,子树有左右之分)。
下面给出
首先是辅助宏的定义:
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define UNDERFLOW -2
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define NULL 0
typedef int Status;
typedef char TElemType;
二叉树的存储结构定义:
//二叉树的二叉链式存储结构定义
typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild,*rchild; //左孩子结点 右孩子结点
}BiTNode,*BiTree;
先序创造二叉树各节点 注意输入时空指针不要丢 输入空格是空树,停止 否则创造根节点 递归创造左子树 递归创造右子树.
Status CreatBiTree(BiTree &T){
/*先序创造二叉树各节点 注意输入时空指针不要丢
输入空格是空树,停止 否则创造根节点 递归创造左子树
递归创造右子树*/
TElemType e;
scanf("%c",&e);
if(e==' ')
T=NULL;
else{
T=(BiTree)malloc(sizeof(BiTNode));
if(!T)//存储分配失败
exit(OVERFLOW);
T->data=e;
T->lchild=NULL;
T->rchild=NULL;
CreatBiTree(T->lchild);
CreatBiTree(T->rchild);
}
return OK;
}
销毁以T为结点的二叉树 注意他的子孙结点也要释放 树为空什么都不做 否则递归释放左子树 递归释放右子树 释放根节点
Status DestroyBiTree(BiTree &T){
/*销毁以T为结点的二叉树 注意他的子孙结点也要释放
树为空什么都不做 否则递归释放左子树 递归释放右子树
释放根节点*/
if(T){
DestroyBiTree(T->lchild);
DestroyBiTree(T->rchild);
free(T);
T=NULL;//不可丢
}
return OK;
}
输出e 输出二叉树 调用先序遍历函数 用函数传递给其参数visit即可.
Status PrintTElem(TElemType e){
//输出e 输出二叉树 调用先序遍历函数 用函数传递给其参数visit即可
printf("%c",e);
return OK;
}
求二叉树的树深 如果T为空 d=0 否则递归求出左子树的树深 再递归求出右子树的树深 最后树的深度为两个树深最大值加一
int TreeDepth(BiTree T){
/*求二叉树的树深
如果T为空 d=0 否则递归求出左子树的树深 再递归求出右子树的树深
最后树的深度为两个树深最大值加一*/
int d,d1,d2;
if(!T)
d=0;
else{
d1=TreeDepth(T->lchild);
d2=TreeDepth(T->rchild);
d=d1>d2?d1+1:d2+1;
}
return d;
}
递归法求结点个数 如果树为空 结点数为0 否则结点数是 递归求得左子树的结点数加上递归求得右子树的结点数加一.
int NodeCount(BiTree T){
/*递归法求结点个数
如果树为空 结点数为0
否则结点数是 递归求得左子树的结点数加上递归求得右子树的结点数加一*/
if(!T)
return 0;
else
return 1+NodeCount(T->lchild)+NodeCount(T->rchild);
}
递归法求叶子结点的个数 如果树为空叶子数为0 如果是只有一个根节点叶子数是1 否则先递归求左子树与右子树的叶子数 整个数结点数就是左右子树结点之和。
int LeafCount(BiTree T){
/*递归法求叶子结点的个数
如果树为空叶子数为0 如果是只有一个根节点叶子数是1
否则先递归求左子树与右子树的叶子数 整个数结点数就是左右子树结点之和*/
if(!T)
return 0;
if(!T->lchild&&!T->rchild)
return 1;
else
return LeafCount(T->lchild)+LeafCount(T->rchild);
}
先序遍历二叉树.如果树不空 先访问根节点 在递归的先序遍历左子树 在递归的先序遍历右子树.
Status PreOrderTraverse(BiTree T,Status (*visit)(TElemType)){
//先序遍历二叉树
//如果树不空 先访问根节点 在递归的先序遍历左子树 在递归的先序遍历右子树
if(T){
if(visit(T->data))
if(PreOrderTraverse(T->lchild,visit))
if(PreOrderTraverse(T->rchild,visit))
return OK;
return ERROR;//只要一次失败就返回ERROR
}
return OK;
}
中序遍历二叉树 如果树不空 先在递归的先序遍历左子树 再访问根节点 再递归的先序遍历右子树.
Status InOrderTraverse(BiTree T,Status (*visit)(TElemType)){
//中序遍历二叉树
//如果树不空 先在递归的先序遍历左子树 再访问根节点 再递归的先序遍历右子树
if(T) {
if(InOrderTraverse(T->lchild,visit))
if(visit(T->data))
if(InOrderTraverse(T->rchild,visit))
return OK;
return ERROR;
}
return OK;
}
后序遍历二叉树 如果树不空 先在递归的先序遍历左子树 再递归的先序遍历右子树 再访问根节点 .
Status PostOrderTraverse(BiTree T,Status(*visit)(TElemType)){
//后序遍历二叉树
//如果树不空 先在递归的先序遍历左子树 再递归的先序遍历右子树 再访问根节点
if(T){
if(PostOrderTraverse(T->lchild,visit))
if(PostOrderTraverse(T->rchild,visit))
if(visit(T->data))
return OK;
return ERROR;
}
return OK;
}
基于先序遍历求叶子结点数 count为计数器 初值0 函数返回值为叶子结点数.实际将先序遍历中的visit函数换成判断当前结点是否是叶子结点 是就加一的操作即可.
int PreOrder_LeafCount(BiTree T,int &count){
//基于先序遍历求叶子结点数 count为计数器 初值0 函数返回值为叶子结点数
//实际将先序遍历中的visit函数换成判断当前结点是否是叶子结点 是就加一的操作即可
if(T){
if(!T->lchild&&!T->rchild)
count++;
else{
PreOrder_LeafCount(T->lchild,count);
PreOrder_LeafCount(T->rchild,count);
}
}
return count;
}
复制T树给X T不变, 如果树空X赋值BULL.
Status CopyBiTree(BiTree T,BiTree &X){
//复制T树给X T不变
//如果树空X赋值BULL
if(!T)
X=NULL;
else{//否则 创造结点 在递归复制左子树和右子树
X=(BiTree)malloc(sizeof(BiTNode));
if(!X)//存储分配失败
exit(OVERFLOW);
X->data=T->data;
X->lchild=NULL;
X->rchild=NULL;
CopyBiTree(T->lchild,X->lchild);
CopyBiTree(T->rchild,X->rchild);
}
return OK;
}
将树各节点的左右孩子互换.
Status ExchangeBiTree(BiTree &T){
//将树各节点的左右孩子互换
BiTNode * temp;
if(T){//如果树存在 交换左右孩子
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
ExchangeBiTree(T->lchild);//递归左子树 互换左右孩子
ExchangeBiTree(T->rchild);//递归右子树 互换左右孩子
}
return OK;
}
从树中查找第一个结点等于x的结点 若找到则返回TRUE 并用p带回该节点的地址 若找不到函数返回FALSE p赋值为NULL.
Status LocateNode(BiTree T,TElemType x,BiTree &p){
//从树中查找第一个结点等于x的结点 若找到则返回TRUE 并用p带回该节点的地址
//若找不到函数返回FALSE p赋值为NULL
if(!T){
p=NULL;
return FALSE;
}
else if(T->data==x){
p=T;
return TRUE;
}
else{
//递归左右子树
if(LocateNode(T->lchild,x,p))
return TRUE;
else if(LocateNode(T->rchild,x,p))
return TRUE;
else{
p=NULL;
return FALSE;
}
}
}
已知树T中某结点值等于x 定位到该节点的双亲结点 若双亲结点存在 即不是根节点 则parent_p返回双亲结点的地址 LR=0 是双亲的左孩子 LR=1是双亲的右孩子 返回TRUE 否则parent_p=NULL 返回FALSE.
Status LocateParent(BiTree T,TElemType x,BiTree &parent_p,int &LR){
/*已知树T中某结点值等于x 定位到该节点的双亲结点 若双亲结点存在 即不是根节点
则parent_p返回双亲结点的地址 LR=0 是双亲的左孩子 LR=1是双亲的右孩子 返回TRUE
否则parent_p=NULL 返回FALSE*/
if(T->data==x){
parent_p=NULL;
return FALSE;
}
else if(T->lchild&&T->lchild->data==x){
LR=0;
parent_p=T;
return TRUE;
}
else if(T->rchild&&T->rchild->data==x){
LR=1;
parent_p=T;
return TRUE;
}
else{
//递归左右子树
if(T->lchild&&LocateParent(T->lchild,x,parent_p,LR))
return TRUE;
else if(T->rchild&&LocateParent(T->rchild,x,parent_p,LR))
return TRUE;
else{
parent_p=NULL;
return FALSE;
}
}
}
删除根结点值为x的子树 若存在x结点删除成功 返回OK 否则返回x不存在ERROR.
Status DeleteChild(BiTree &T,TElemType x){
//删除根结点值为x的子树 若存在x结点删除成功 返回OK 否则返回x不存在ERROR
BiTNode *p,*parent_p;
int LR;
if(LocateNode(T,x,p)){ //定位x 所在结点
if(LocateParent(T,x,parent_p,LR)){//如果x有双亲结点
if(!LR) //是左孩子
DestroyBiTree(parent_p->lchild);
else if(LR==1)//是右孩子
DestroyBiTree(parent_p->rchild);
}
else//x是根节点
DestroyBiTree(T);
}
else//x结点不存在
return ERROR;
}
非递归中序遍历方法1: T入栈,重复如下操作至栈空:{ 只要栈顶元素不为空则[其左孩子入栈]。最后栈顶必为空,出栈。
若下一个栈顶元素不空则出栈访问且右孩子入栈.
Status InOrderTraverse_NonRecur_1(BiTree T,Status (*visit)(TElemType)){
/*非递归中序遍历方法1
T入栈,重复如下操作至栈空:
{ 只要栈顶元素不为空则[其左孩子入栈]。最后栈顶必为空,出栈。
若下一个栈顶元素不空则出栈访问且右孩子入栈 */
SqStack S;
InitStack(S);
BiTNode * p=T;
while(p||!StackEmpty(S)){
while(p){
Push(S,p);
p=p->lchild;
}
Pop(S,p);
visit(p->data);
p=p->rchild;
}
return OK;
}
非递归中序遍历方法2.何时递归 根节点不空将左孩子入栈做新根节点 何时不递归 根节点为空不递归 从后以前的空根节点出栈 访问下一个栈顶元素并将右孩子入栈 当栈中无元素时遍历完成.
Status InOrderTraverse_NonRecur_2(BiTree T,Status (*visit)(TElemType)){
/*非递归中序遍历方法2
何时递归 根节点不空将左孩子入栈做新根节点
何时不递归 根节点为空不递归 从后以前的空根节点出栈 访问下一个栈顶元素并将右孩子入栈
当栈中无元素时遍历完成*/
SqStack S;
InitStack(S);
BiTNode *p;
if(!T){
printf("空树");
return ERROR;
}
else{
Push(S,T);
while(!StackEmpty(S)){
//p的左孩子入栈 直到p为空指针 此循环后栈顶元素是NULL 相当于走到左子树外
while(GetTop(S,p)&&p)
Push(S,p->lchild);
Pop(S,p);//左子树是空树 对应的空指针出栈 下一步将访问根节点
if(!StackEmpty(S)){
//栈内有元素说明没有遍历完 下一步访问栈顶根结点 之后栈顶跟结点的右孩子入栈
Pop(S,p);
visit(p->data);
Push(S,p->rchild);
}
}
return OK;
}
}