树算法题
目录
1、计算二叉树中所有结点个数
2、计算二叉树中所有叶子节点的个数
3、计算二叉树中所有双分支的节点个数
4、计算二叉树的深度
5、找出二叉树中最大值的点
6、判断两个二叉树是否相似(指都为空或者都只有一一个根节点,或者左右子树都相似)
7、把二叉树所有节点左右子树交换
8、输出先序遍历第k个结点的值
9、求二叉树中值为x的层号
10、树中元素为x的结点,删除以它为根的子树
11、先序非递归遍历二叉树
12、中序非递归遍历二叉树
13、后序非递归遍历二叉树
14、计算二叉树的带权路径长度
15、找到p和q最近公共祖先结点r
16、层次遍历
17、判断二叉树是否为完全二叉树
1、计算二叉树中所有结点个数
int CntNode(BiTree T){
int k=0;
if(T){
k++;
k+=CntNode(T->lchild);
k+=CntNode(T->rchild);
}
return k;
}
2、计算二叉树中所有叶子节点的个数
int LeafNode(BiTree T){
int k=0;
if(T){
if(T->lchild==NULL&&T->rchild==NULL)
k++;
else{
k+=LeafNode(T->lchild); //统计左子树叶子结点
k+=LeafNode(T->rchild); //统计右子树叶子结点
}
}
return k;
}
3、计算二叉树中所有双分支的节点个数
int DNodes(BiTree T){
if(T==NULL)
return 0;
else if(T->lchild!=NULL&&T->rchild!=NULL)//双分支结点
return DNodes(T->lchild)+DNodes(T->rchild)+1;
else//单分支结点或叶子结点
return DNodes(T->lchild)+DNodes(T->rchild);
}
4、计算二叉树的深度
int Deepth(BiTree T){
int hl=0,hr=0; //hl是左子树高度,hr是右子树高度
if(T==NULL)
return 0;
else{
hl=Deepth(T->lchild); //遍历左子树求高度
hr=Deepth(T->rchild); //遍历右子树求高度
return hl>hr?hl+1:hr+1; //返回子树高度较高的+根结点
}
}
5、找出二叉树中最大值的点
//基于中序遍历的非递归算法
ElemType Inorder(BiTree T){
ElemType max=-1;
InitStack(S);
p=T;
while(p||!StakEmpty(S)){
if(p){
p=p->lchild;
Push(S,p); //入栈
}
else{
Pop(S,p); //出栈
if(p->data>max)
max=p->data;
p=p->rchild;
}
}
return max;
}
6、判断两个二叉树是否相似(指都为空或者都只有一一个根节点,或者左右子树都相似)
bool IsSimilar(BiTree T1, BiTree T2){
if(T1==NULL&&T1==NULL) //都为空树
return true;
else if(T1==NULL||T1==NULL) //只有一个棵树为空
return false;
else //递归判断子树
return IsSimilar(T1-lchild,T2->lchild) && IsSimilar(T1-rchild,T2->rchild);
}
7、把二叉树所有节点左右子树交换
/**
先交换左子树中的结点
再交换右子树中的结点
最后交换左右子树,基于后序遍历
**/
void SwaptTree(BiTree T){
BiTree temp;
if(T){
SwaptTree(T->lchild); //递归交换左子树
SwaptTree(T->rchild); //递归交换右子树
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
}
}
8、输出先序遍历第k个结点的值
int cnt=0; //全局变量,统计结点个数
Status pre_k(BiTree T,int k){
if(T){
cnt++;
if(cnt==k){
print(T->data); //输出第k个结点的值
return OK;
}
else{
if(pre_k(T->lchild,k))
return OK;
if(pre_k(T->rchild,k))
return OK;
}
}
return ERROR;
}
9、求二叉树中值为x的层号
int h=1;
void levelnum(BiTree T,ElemType x){
if(T){
if(x==T->data)
cout<<h; //打印层号
++h;
levelnum(T->lchild,x);
levelnum(T->rchild,x);
--h;
}
}
10、树中元素为x的结点,删除以它为根的子树
void Del_x(BTree T)//基于后序递归遍历删除结点
{
if(T)
{
Del_x(T->lchild);
Del_x(T->rchild);
free(T);
}
}
//基于层序遍历
void Search(BTree T,TElemType x){
SqQueue Q;//定义顺序队列
InitQueue(Q);//初始化队列
BTree p;
if(T){
if(T->data==x){
Del_x(T);
exit(0);
}
EnQueue(Q,T);
while(!QueueEmpty(Q)){
DeQueue(Q,p);
if(p->lchild){
if(p->lchild->data==x){
Del_x(p->lchild);
p->lchild=NULL;//恢复树的结构
}
else
EnQueue(p->lchild);
}
if(p->rchild){
if(p->rchild->data==x){
Del_x(p->rchild);
p->rchild=NULL;//恢复树的结构
}
else
EnQueue(p->rchild);
}
}
}
}
11、先序非递归遍历二叉树
void PreOrder(BiTree T){
InitStack(S);
p=T;
while(p||!StackEmpty(S)){
if(p){
Visit(p);
p=p->lchild;
Push(S,p);
}
else{
Pop(S,p);
p=p->rchild;
}
}
}
12、中序非递归遍历二叉树
void InOrder(BiTree T){
InitStack(S);
p=T;
while(p||!StackEmpty(S)){
if(p){
p=p->lchild;
Push(S,p);
}
else{
Pop(S,p);
Visit(p);
p=p->rchild;
}
}
}
13、后序非递归遍历二叉树
void PostOrder(BiTree T){
InitStack(S); //初始化栈
p=T;r=NULL; //r指向上一个被访问的结点
while(p||!StackEmpty(S){
if(p){
Push(S,p);
p=p->rchild; //一直走到最左边
}
else{
GetTOP(S,p); //查看栈顶元素
if(p->rchild&&p->rchild!=r)
p=p->rchild;
else{
Pop(S,p);
Visit(p);
r=p; //r记录被访问的结点
p=NULL; //清空p结点
}
}
}
}
14、计算二叉树的带权路径长度
typedef struct BTNode{
int weight;
struct BTNode *lchild,*rchild;
}BTNode,*BiTree;
int WPL=0; //全局变量求带权路径长度
int get_wpl(BiTree T, int deep){ //deep初始值为1
if(T){
get_wpl(T->lchild,deep+1); //中序遍历左子树
if(T->rchild==NULL&&T->lchild==NULL)
WPL+=(deep-1)*T->weight;
get_wpl(T->rchild,deep+1); //中序遍历右子树
}
}
15、找到p和q最近公共祖先结点r
/*
以二链表存储的二叉树上找某结点的所有祖先,某两个结点的最近公共祖先,从根结点到某结点的路径,根结点到每个叶子结点以及最远叶子的路径等。均应采取后序非递归遍历。因为后序遍历最后访问根结点,当访问到某结点时,栈中所有元素均为该结点的祖先。
找p和q的最近共同祖先结点r,不失一般性,设p在q的左边。后序遍历必然先遍历到结点p,栈中元素均为p的祖先。将栈复制到另一辅助栈中再继续遍历到结点q时,将中元素从栈顶开始逐个到辅助中去匹配,第一个匹配(即相等)的元素就是结点p和g的最近公共祖先。
*/
typedef struct {
BiTree t;
int tag; //tag=0表示左孩子已被访问,1表示右孩子已被访问
}Stack;
BiTree Ancestor(BiTree T,BiTNode *p,BiTNode *q){
Stack s[],s1[]; //栈,容量足够大
top=0,top1=0; //栈顶指针,top1是s1的栈顶指针
bt=T;
while(bt!=NULL||top>0){
while(bt!=NULL && bt!=p && bt!=q){
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild;
}
if(bt==p){//假定p在q的左侧,遇结点p 时,栈中元素均为p的祖先结点
for(i=1;i<=top;i++)//将p的祖先结点放到辅助栈s1中
s1[i]=s[i];
top1=top; //修改栈顶指针
}
if(bt==q){//找到q结点
for(i=top;i>0;i--){//将栈中元素到s1去匹配
pp=s[i].t;
for(j=top1;j>0;j--){
if(s1[j].t==pp){
cout<<"共同祖先已找到";
return pp;
}//if
}//for
}//for
}//if
while(top!=0&& s[top].tag==1) top--; //退栈
if(top!=0){s[top].tag=1;bt=s[top].t->rchild;} //沿右分支向下遍历
}
return NULL;
}
16、层序遍历
void LevelTraverse(BiTree T)
{
int i, j;
BiTree p[100]; //树指针数组,用来模拟队列
i = j = 0;
if(T)
p[j++] = T;
while(i<j)
{
printf("%c ", p[i]->data);
if(p[i]->lchild)
p[j++] = p[i]->lchild;
if(p[i]->rchild)
p[j++] = p[i]->rchild;
i++;
}
}
void LevelTraverse(BiTree T)
{
if(T){
InitQueue(Q); //初始化队列
EnQueue(Q,T); //入队
while(!QueueEmpty(Q)){
DeQueue(Q,p);
Visit(p);
if(p->lchild)
EnQueue(p->lchild);
if(p->rchild)
EnQueue(p->rchild);
}
}
}
17、判断二叉树是否为完全二叉树
//基于层序遍历,将所有结点入队,包括空结点,结点出队时若当前结点为空,则判断后一结点,后一结点不空则不是完全二叉树(不满足完全二叉树的形状)。
bool isCompleteTree(BiTree T){
if(T==NULL)
return true;
InQueue(Q);
EnQueue(Q,T);
while(!QueueEmpty(Q)){
DeQueue(Q,p);
if(p){ //所有结点入队,包括空结点
EnQueue(Q,p->lchild);
EnQueue(Q,p->rchild);
}
else{
while(!QueueEmpty(Q)){
DeQueue(Q,p);
if(p)
return false; //不是完全二叉树
}
}
}
return true;
}
18、层序遍历求二叉树高度
int deepth(BiTree T){
if(T==NULL)
return 0;
//初始化队列
BiTree Q[maxsize];
int level=0,last=0; //last指向每层最右结点
int front=-1,rear=-1;
Q[++rear]=T; //根节点入队
BiTree p;
while(front<rear){ //队列非空
p=Q[++front]; //出队
if(p->lchild)
Q[++rear]=p->lchild;
if(p->rchild)
Q[++rear]=p->rchild;
if(last==rear){
level++; //层数+1
last=rear; //last指向下层
}
}
return level;
}