1.求树高
int height(BiT bt)
{
int hl,hr;
if(bt==NULL)return 0;
hl=height(bt->lchild);
hr=height(bt->rchild);
return (hl>hr?hl:hr)+1;
}
2.求树中(出)度为1的结点数目
int f(BiT bt)
{
int nl,nr;
if(bt==NULL)return 0;
nl=f(bt->lchild);
nr=f(bt->rchild);
return nl+nr+(bt->lchild&&!bt->rchild||!bt->lchild&&bt->rchild);
}
(变式)求出度为2的结点数;求叶子数;求总结点数
//求出度为2的结点数
return nl+nr+(bt->lchild&&bt->rchild);
//求叶子数
return nl+nr+(!bt->lchild&&bt->rchild);
//求总结点数
return nl+nr+(bt!=NULL);
3.已知某结点指针*p,求该结点所在层号
int LayerNo(BiT bt,BiT p)
{//递归算法
int n;
if(bt==NULL)return 0;//树空直接返回0
if(bt==p)return 1;//若根结点就是已知结点,则返回1
n=LayerNo(bt->lchild,p);//向左深入
if(n==0)n=LayerNo(bt->rchild,p);//向右深入
if(n==0)return 0;
return n+1;//本层递归带值返回时,应该返回n+1
}
int LayerNo(BiT bt,BiT p)
{//基于层次遍历的非递归算法,用入队元素(bt,k)表示结点bt以及其所在行号k
int k;
if(bt==NULL)return 0;//空树返回0
initQueue(Q);//初始化队列
enQueue(Q,(bt,1));//根结点入队
while(!empty(Q))
{
(bt,k)=delQueue(Q);//队头元素出队
if(bt==p)return k;//若bt即为所求,返回bt所在的行号;否则其左右儿子入队
if(bt->lchild) enQueue(Q,(bt->lchild,k+1));
if(bt->rchild) enQueue(Q,(bt->rchild,k+1));
}
return 0;//p不在该数中,返回0
}
4.已知某结点*p,求其双亲结点(类似问题:已知数值域值,在二叉树中查找结点)
- 有返回值(返回值为求得的双亲指针)
BiT GetParent(BiT bt,BiT p)
{
BiT parent;
if(bt==NULL)return NULL;
if(bt->lchild==p||bt->rchild==p)
return bt;//若bt的左儿子或右儿子为p,则返回bt
parent=GetParent(bt->lchild,p);//向左深入
if(parent)return parent;
return (GetParent(bt->rchild,p));//向右深入
}
- 无返回值(用引用形参(C++)返回双亲指针,或用(二重)指针形参(C)返回双亲指针)
//引用形参
void GetParent(BiT bt,BiT p,BiT &parent)
{
if(bt==NULL||parent!=NULL)return;//parent!=NULL表示结果已经求得,可以返回
if(bt->lchild==p||bt->rchild==p) parent=bt;
void GetParent(bt->lchild,p,parent);
void GetParent(bt->rchild,p,parent);
}
//调用时,需进行赋初值:
BiT parent=NULL;
//pure C
void GetParent(BiT bt,BiT p,BiT *parent)
{
if(bt==NULL||*parent!=NULL)return;//parent!=NULL表示结果已经求得,可以返回
if(bt->lchild==p||bt->rchild==p) *parent=bt;
void GetParent(bt->lchild,p,*parent);
void GetParent(bt->rchild,p,*parent);
}
- 已知数值值域
判定条件改为:
if(bt->data==p->data) result=bt;
5.求最左边的第一个叶子结点的地址
- 基于先序遍历(先序遍历访问的第一个叶子结点即为所求)
BiT f(BiT bt)
{
BiT result;
if(bt==NULL) return NULL;
if(bt->lchild==NULL&&bt->rchild==NULL) return bt;
result=f(bt->lchild);
if(result) return result;
return f(bt->rchild);
}
- 基于后序遍历(后序遍历的第一个访问节点即为所求)
BiT f(BiT bt)
{//有值返回
BiT result;
if(BiT==NULL) return NULL;
result=f(bt->lchild);
if(result) return result;
result=f(bt->rchild);
if(result) return result;
return bt;
}
void f(BiT bt,BiT &p)
{//无值返回
if(bt==NULL||p) return;
f(bt->lchild,p);
f(bt->rchild,p);
if(!p) p=bt;
}
6.求中序(前序、后序)遍历第k个访问结点的指针
BiT f(BiT bt,int &k)
{//有值返回
BiT p;
if(bt==NULL) return NULL;
p=f(bt->lchild,k);
if(k>0)//或者是if(!p)
{
k--;
if(k==0)return bt;
p=f(bt->rchild,k);
}
return p;
}
void f(BiT bt,int &k,BiT &p)
{
if(bt==NULL||k==0) return;
f(bt->lchild,k,p);
if(k>0)
{
k--;
if(k==0)
{
p=bt;
return;
}
f(bt->rchild,k,p);
}
}
7.求某结点*p在二叉树中的访问次序
详情见求二叉树某结点在先序、中序、后序遍历中的访问次序
8.使用堆栈实现前、中、后序遍历的非递归算法
- 先序遍历
void pretravel(BiT bt)
{
initStack(s);
while(bt||!emptyStack(s))
if(bt)
{
visit(bt);
push(s,bt);
bt=bt->lchild;
}
else
{
pop(s,bt);
bt=bt->rchild;
}
}
- 中序遍历
void midtravel(BiT bt)
{
initStack(s);
while(bt||!emptyStack(s))
if(bt)
{
push(s,bt);
bt=bt->lchild;
}
else
{
pop(s,bt);
vist(bt);
bt=bt->rchild;
}
}
- 后序遍历
需要在堆栈元素或二叉树结点中设置标志变量flag;flag=0或1表示从左或右子树返回并出栈
void lastravel(BiT bt)
{
initStack(s);
while(bt||!emptyStack(s))
if(bt)//结点不空
{
flag=0;
push(s,(bt,flag));//入栈
bt=bt->lchild;//向左深入
}
else
{
pop(s,(bt,flag));/*出栈后判断标志变量(此时就是增设标志变量的意义所在:
因为我不知道到底是从左子树返回上来的,还是从右子树返回上来的)*/
if(flag==0)//flag==0表示已经从左子树返回,即将向右子树深入
{
flag=1;
push(s,(bt,flag));
bt=bt->rchild;
}
else//flag==1表示已经从右子树返回,直接访问根结点
{
vist(bt);
bt=NULL;
}
}
}
总结:“入栈”对应递归算法中的“递归深入”,“出栈以及判断标志变量”对应递归算法中的“访问结点”
9.判断二叉树是否为完全二叉树
bool check(BiT bt,int i,int n)
{
if(i>n)return true;
if(bt==NULL) return false;
return check(bt->lchild,2*i,n)&&check(bt->rchild,2*i+1,n);
}
调用时,n为结点总数(需要求得二叉树结点总数)
//调用格式
check(bt,1,n);
10.求二叉树各结点的平衡因子
为二叉链表增加一个整数域bf(balance factor)用于存放该结点的平衡因子;结点平衡因子的概念为:该结点左子树和右子树的高度差
typedef struct node
{
ElemTp data;
int bf;//平衡因子数值域
struct node *lchild,*rchild;
}*BiT,BiTNode;
int f(BiT bt)
{
int hl,hr;
if(bt==NULL)return 0;
hl=f(bt->lchild);
hr=f(bt->rchild);
bt->bf=hl-hr;//左子树高度减去右子树高度
return (hl>hr?hl:hr)+1;
}
//该算法和求二叉树树高的算法很相似,其返回值就是树高
11.判断某一个二叉树是否是平衡二叉树
可以在算法10的基础上通过遍历每个结点的bf域,判断其绝对值是否小于等于1;或者将求树高的算法和判断是否平衡的算法综合一下
int get_bf(bt);
bool BalanceTree(BiT bt,bool &isBalanced)
{
if(bt==NULL||!isBalanced) return false;
if(abs(bt->bf)>1) isBalanced=false;
if(isBalanced)
bool(bt->lchild,isBalanced);
if(isBalanced)
bool(bt->rchild,isBalanced);
return true;
}
//调用时,bool isBalanced=true;
int tst(BiT bt,bool &isBalanced)
{
if(bt==NULL||!isBalanced) return false;
hl=tst(bt->lchild,isBalanced);
if(isBalanced)
{
hr=tst(bt->rchild,isBalanced);
if(isBalanced)
{
isBalanced=abs(hl-hr)<=1;
return max(hl,hr)+1;
}
}
return false;
}
//调用时,bool isBalanced=true;