第五章 树与二叉树

155_2

05、已知一颗二叉树按顺序存储结构进行存储,设计一个算法,求编号分别为i和j的两个结点的最近的公共祖先结点的值

//求不同编号结点的最近的公共祖先结点的值
ElemType Comm_Ancestor(SqTree T,int i,int j)
{
	if(T[i]!='#'&&T[j]!='#')//保证两个结点的值都不为空 
	{
		while(i!=j)
		{
			if(i>j)
				i/=2;//向上找i的祖先 
			else
				j/=2;//向上找j的祖先 
		}//出while时 必然找到了公共祖先 i=j 
		
	}
	
	return T[i];
 } 

5_3

03、试编写后序遍历二叉树的非递归算法

#include <stdio.h>

#define MaxSize 50

//树的存储结构
typedef struct BiTNode{
	int data;//用字母表示数据域 如1 2 3 4等
	struct BiTNode *lchild,*rchild; 
}BiTNode,*BiTree; 

//栈的存储结构
typedef struct{
	BiTree data[MaxSize];//因为存储的是p 所以类型也应该为BiTree 
	int top;
}Bistack;

//初始化栈
void InitStack(Bistack &S)
{
	S.top=-1;
 } 
 
//栈是否为空
bool IsEmpty(Bistack S)
{
	if(S.top==-1)
	return true;
	else
	return false;
 } 

//进栈
bool Push(Bistack &S,BiTree p)
{
	if(S.top==MaxSize-1)
	{
		return false;
	}
	S.data[++S.top]=p;
	return true;
 } 
 
//出栈
bool Pop(Bistack &S,BiTree &p)
{
	if(S.top==-1)
	{
		return false;
	}
	p=S.data[S.top--];
	return true;
 } 
 
//取栈顶元素
bool GetTop(Bistack S,BiTree &p)
{
	if(S.top==-1)//栈空 
	{
		return false;
	}
	p=S.data[S.top];
	return true;
 } 
 
//二叉树后序非递归遍历

void PostTraverse_1(Bitree T)
{
	InitStack(S);
	BiTNode *p=T;
	BiTNode *r=NULL;//用r来表示右子树是否被访问过 
	while(p||!StackEmpty(S))
	{
		if(p)
		{
			Push(S,p);//保存在栈中 
			p=p->lchild;//处理左子树 
		}else
		{
			GetTop(S,p);//取出栈顶元素 检查是否有右子树
			if(p->rchild&&p->rchild!=r) //右子树存在且未被访问过 
			{
				p=p->rchild;//处理其右子树 
			}else
			{
				Pop(S,p);//出栈 输出元素 
				printf("%d ",p->data);
				r=p;//让r指向p 表示已被访问过 
				p=NULL;//每次访问过后将p置空 
			}
		}
	}
 }
 
 //测试
 void test()
 {
 	//Bistack S;
 	BiTNode a,b,c,d,e;
 	a.data=1;
 	a.lchild=&b;
 	a.rchild=&c;
 	b.data=2;
 	b.lchild=&d;
 	b.rchild=NULL;
 	c.data=3;
 	c.lchild=NULL;
 	c.rchild=NULL;
 	d.data=4;
 	d.lchild=NULL;
 	d.rchild=&e;
 	e.data=5;
 	e.lchild=NULL;
 	e.rchild=NULL;
 	
 	BiTree T=&a;
	PostOrder(T); 
	
	//输出应为5 4 2 3 1 
 	
  } 
 
 int main()
 {
 	test();
 	
 	getchar();
 	return 0;
 }

04、试给出二叉树的自下而上、从右到左的层次遍历算法

//倒序输出层次遍历
//思路:层序遍历 出队时 立即将结点压入栈中 最后让所有栈中元素出栈即可

void Inverse_LevelOrder(BiTree T)
{
	Stack S,Queue Q;
	
	if(T)//树不空 
	{
		InitQueue(Q);InitStack(S);//分别将对列Q和栈S初始化
		BiTNode *p=T;
		Enqueue(Q,p);
		while(!IsEmpty(Q))
		{
			Dequeue(Q,p);//对列保证先进先出 出队后立即压入栈中 
			Push(S,p);
			if(p->lchild)
				Enqueue(Q,p);//左子树不空 入队 
			if(p->rchild)
				Enqueue(Q,p);//右子树不空 入队 
		}
		while(!StackEmpty(S))//倒序输出 
		{
			Pop(S,p);
			printf("%d ",p->data);
		}
	} 
}

05、假设二叉树采用二叉链表存储结构,设计一个非递归算法求二叉树的高度

//非递归算法求二叉树高度
//思路:采用层序遍历 设置一个标志last使其指向每层的最右边结点 

int BTHeight(BiTree T)
{
	int level=0,last=0;
	int front=-1,rear=-1;//队列队头和队尾指针 初始为-1 指向空
	BiTree Q[MAXSIZE];
	if(!T)//树为空 
		return 0; 
	Q[++rear]=T;//将根结点入队 
	BiTNode *p;
	while(front<rear)
	{
		p=Q[++front];//出队 即正在访问 的结点 
		if(p->lchild)
			Q[++rear]=p->lchild;//左孩子入队 
		if(p->rchild)
			Q[++rear]=p->rchild;//右孩子入队 
		if(front==last)//fornt与last相等表示 该层结点输出完毕 
		{
			level++;//高度+1 
			last=rear;//让last指向下一层最右边结点 
		}	
	}
	return level;
 } 

//递归求二叉树高度
int Btdepth(BiTree T)
{
	int ldep,rdep;//分别代表左右子树高度
	if(!T)
		return 0;
	ldep=Bedepth(T->lchild);//左子树高度 
	rdep=Bedepth(T->rchild);//右子树高度 
	
	if(ldep>rdep)
		return ldep+1;//树的高度为子树最大高度+根结点 
	else
		return rdep+1; 
 }
 
 //求某层的结点个数
//非递归算法求二叉树高度
//思路:采用层序遍历 设置一个标志last使其指向每层的最右边结点 

int BTHeight(BiTree T)
{
	int s[MAXSIZE];//记录每层的结点个数 
	int cnt=0;
	int level=0,last=0;
	int front=-1,rear=-1;//队列队头和队尾指针 初始为-1 指向空
	BiTree Q[MAXSIZE];
	if(!T)//树为空 
		return 0; 
	Q[++rear]=T;//将根结点入队 
	BiTNode *p;
	while(front<rear)
	{
		p=Q[++front];cnt++;//出队 即正在访问 的结点 出队即个数+1 
		if(p->lchild)
			Q[++rear]=p->lchild;//左孩子入队 
		if(p->rchild)
			Q[++rear]=p->rchild;//右孩子入队 
		if(front==last)//fornt与last相等表示 该层结点输出完毕 
		{
			level++;//高度+1 
			s[level]=cnt;//记录完毕后 将cnt置0 方便重新计数 
			cnt=0;
			last=rear;//让last指向下一层最右边结点 
		}	
	}
	return level;
 }

06、设一颗二叉树中各结点的值互不相同,其先序遍历序列和中序遍历序列分别存于两个一维数组A[1...n]和B[1..n]中,试编写算法建立该二叉树的二叉链表

//已知先序序列和中序序列建立二叉链表
//思路:递归

BiTree Create(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2)
{//l1 h1分别代表先序序列的第一个和最后一个结点下标 l2 h2分别代表中序序列的第一个和最后一个结点下标 
 //初始调用时,l1=l2=1,h1=h2=n;
 	BiTNode *root=(BiTNode *)malloc(sizeof(BiTNode ));//建立根结点
	root->data=A[l1];
	for(i=l2;B[i]!=root->data;i++);//找到root结点在中序序列B[]中的位置i
	llen=i-l2;//左子树长度 
	rlen=h2-i; //右子树长度
	if(llen)//建立左子树 
	{
		root->lchild=Create(A,B,l1+1,l1+llen,l2,l2+llen-1);
	} 
	else
		root->rchild=NULL;//左子树长度为0 则置为空 
	if(rlen)//建立右子树 
	{
		root->rchild=Create(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
	}
	else
		root->rchild=NULL;//右子树长度为0 则置为空 
	 
	return root;//返回根结点指针 
 }

07、二叉树按二叉链表形式存储,写一个判别给定二叉树是否是完全二叉树的算法

//7、判断是否是完全二叉树
//思路:采用层次遍历 将所有结点加入队列(包括空节点)
//遇到空节点时 查看其后是否有非空结点 若有则不是完全二叉树

bool IsComplete(BiTree T)
{
	InitQueue(Q);
	BiTNode *p;
	if(!T)
		return true;//空树也是完全二叉树
	else
	{
		EnQueue(T);
		while(!IsEmpty(Q))
		{
			DeQueue(Q,p);
			if(p)//p不是空节点 
			{
				EnQueue(Q,p->lchild);//将左子树入队 
				EnQueue(Q,p->rchild);//右子树入队 
			}else//遇到空节点 看队列中是否有非空结点 
			{
				while(!IsEmpty(Q))
				{
					DeQueue(Q,p);
					if(p)//有非空节点 
						return false;//不是完全二叉树 
				}
			}
		}
	} 
 } 

08、假设二叉树采用二叉链表存储结构存储,试设计一个算法,计算一颗给定二叉树的所有双分支结点个数

 
 //计算双分支结点个数
 //思路1;
 //采用层次遍历 先将每个结点入队
 //若对不空则出队 出队时判断该结点的左右孩子是否为空 若都不为空则cnt++
 
 //思路2:
 //递归:
 //f(b)=0; 若b=NULL
 //f(b)=f(b->lchild)+f(b->rchild)+1;//*b是双分支结点 
 //f(b)=f(b->lchild)+f(b->rchild); //*b为单分支结点或叶子结点
 
 int DsonNodes(BiTree b)
 {
 	if(b==NULL)
 		return 0;//空节点则返回0 也是递归出口
	else if(b->lchild&&b->rchild)//左右孩子都存在
		return DsonNodes(b->lchild)+DsonNodes(b->rchild)+1;
	else
		return DsonNodes(b->lchild)+DsonNodes(b->rchild); 

} 

09、设树B是一颗采用链式结构存储的二叉树,编写一个把树B中的所有结点的左、右子树进行交换的函数

//交换所有结点的左右子树
//思路:递归 将遍历算法中的visit()改为交换即可 

void swap(BiTree T)
{
	if(T)
	{
		swap(T->lchild);//递归交换左子树 
		swap(T->rchild);//递归交换右子树 
		BiTNode* temp=T->lchild;//交换左右孩子结点 
		T->lchild=T->rchild;
		T->rchild=temp;
	}
} 

10、假设二叉树采用二叉链表存储结构存储,设计一个算法,求先序遍历序列中第k(1<=k<=二叉树中结点个数)个结点的值

//求先序遍历序列中第k个结点的值
//思路:
//设置一个全局变量num来表示先序遍历时当前访问的是第几个结点
//当num=k时 返回即可


int num=1;//注意num是全局变量 
int k_thPreNode(BiTree b,int k)
{
	if(b==NULL)
		return '#';
	if(num==k)
		return b->data;
	//不为空 也不是第k个结点 则num++ 访问下一个结点 
	num++;
	int ch=k_thPreNode(b->lchild,k);
	if(ch!='#')//ch不为'#' 才返回 
		return ch;
	//ch为'#' 则继续 
	ch=k_thPreNode(b->rchild,k);
} 

11、已知二叉树以二叉链表存储,编写算法完成:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间。

//对于每个元素值为x的结点 删去以它为根的子树并释放相应空间
//思路:
//选择后序遍历删除以该结点为根的 子树 选择层次遍历找到该结点 删除 并将左右孩子结点置空

void DeleteXTree(BiTree &bt)
{
	DeleteXTree(bt->lchild);
	DeleteXTree(bt->rchild);//删除bt的左右子树 
	free(bt);//释放被删除结点所占的存储空间 
} 

//查找以x为元素值的结点,并删除以其为根的子树
void Search(BiTree bt,ElemeType x) 
{
	BiTree Q[max];//存放二叉树结点指针的队列 容量足够大
	BiTree p;
	
	if(bt)
	{//bt不为空 
		if(bt->data==x)//根结点值为x 删除整棵树 
		{
			DeleteXTree(bt);
			exit(0);
		}
	}
	InitQueue(Q);
	EnQueue(Q,bt);
	
	while(!IsEmpty(Q))
	{
		DeQueue(Q,p);
		
		if(p->lchild)//左子树非空 
		{
			if(p->lchild->data==x)//左子树是待删除结点 
			{
				DeleteXTree(p->lchild);//删除 
				p->lchild=NULL;//左子树置空 
			}else//否则 入队 
				EnQueue(Q,p->lchild); 
		}
		
		if(p->rchild)//右子树非空 
		{
			if(p->rchild->data==x)//右子树是待删除结点 
			{
				DeleteXTree(p->rchild);//删除 
				p->rchild=NULL;//右子树置空 
			}else//否则 入队 
				EnQueue(Q,p->rchild);
		}
		
	}
}

12、在二叉树中查找值为x的结点,试编写算法(用C语言)打印值为x的结点的所有祖先,,假设值为x的结点不多于1个。

//打印值为x的结点的所有祖先
//思路:后序非递归算法 特性:访问到值为x的结点时,栈中所有元素均为该结点的祖先,依次出栈打印即可
const int max=999;
typedef struct stack{
	BiTree t;
	int tag;//tag=0表示左子女被访问 tag=1表示右子女被访问
}stack;

void printXAnces(BiTree bt,ElemType x)
{
	stack s[max];
	int top=0;
	while(bt!=NULL||top>0)
	{
		while(bt!=NULL&&bt->data!=x)
		{
			s[++top].t=bt;//入栈
			s[top].tag=0;
			bt=bt->lchild;//沿左分支向下 
		}
		
		if(bt!=NULL&&bt->data==x)
		{
			printf("所查节点的祖先结点的值为:\n");
			for(int i=1;i<=top;i++)//访问到x时 该结点还未入栈 故其祖先是此时栈中所有的结点 所以i<=top 
				printf("%d ",s[i].t->data);
			exit(0);
		}
		
		while(top!=0&&s[top].tag==1)//退栈 空遍历 
			top--;
			
		if(top!=0)
		{
			s[top].tag=1;
			bt=s[top].t->rchild;//沿右分支向下遍历 
		}
	}
} 

13、

//找到任意两个结点的最近公共祖先
//思路:利用后序非递归遍历 访问到p时 栈中元素必是p的祖先 此时将栈复制到另一辅助栈中
//继续遍历到q时 将栈中元素从栈顶开始逐个到辅助栈中去匹配 第一个匹配的元素就是p和q的最近公共祖先
const int N=999;
typedef struct stack{
	BiTree t;
	int tag;//tag=0表示左子女被访问 tag=1表示右子女被访问
}stack;
 
stack s[N],s1[N];//栈 容量足够大
BiTree Ancestor(BiTree ROOT,BiTNode *p,BiTNode *q)
{
	BiTree bt=ROOT;
	int top=0,top1=0;
	while(bt!=NULL||top>0)
	{
		while(bt!=NULL)
		{
			s[++top].t=bt;
			s[top].tag=0;
			bt=bt->lchild;//沿左分支向下 
		}
		
		while(top!=0&&s[top].tag==1)
		{
			if(s[top].t==p)//访问到p 将栈中结点复制到s1 
			{
				for(int i=1;i<=top;i++)
				{
					s1[i]=s[i];
					top1=top;
				}
			} 
			
			if(s[top].t==q)
			{//访问到q结点 将此时 栈中元素的树结点到s1中去匹配 
				for(int i=top;i>0;i--)//注意for循环的顺序 
					for(int j=top1;j>0;j--)
						if(s1[j].t==s[i].t)
							return s[i].t;
			}
			
			top--;//未访问到p q结点 出栈 
		}
		
		if(top!=0)
		{
			s[top].tag=1;
			bt=s[top].t->rchild;//沿右分支向下 
		}
	}
	return NULL;//p和q无公共祖先 
 } 

14、假设二叉树采用二叉链表存储结构,设计一个算法,求非空二叉树b的宽度(即具有结点树最多的那一层的结点个数)

//14、求非空二叉树的宽度
//思路:采用层次遍历的方法求出所有节点的层次,并将所有节点和层次放在一个队列中
//扫描队列求出各层的结点总数 找出最大的即可

typedef struct{
	BiTree data[MaxSize];
	int level[MaxSize];
	int front,rear;
}BiQueue;

int BTWidth(BiTree bt)
{
	BiQueue Q;
	Q.front=-1,Q.rear=-1;//队列指针初始化
	int k,n,max,i;//k代表层数 n用于记录每层的结点树 max表示最大层节点数 即宽度
	Q.rear++;
	Q.data[Q.rear]=bt;//根结点入队 
	Q.level[Q.rear]=1;//根结点层次为1
	while(Q.front<Q.rear)
	{
		Q.front++;
		BiTree p=Q.data[Q.front];//出队
		k=Q.level[Q.front];//出队结点的层次
		
		if(p->lchild!=NULL)
		{//左孩子存在 
			Q.data[++Q.rear]=p->lchild;//左孩子入队
			Q.level[Q.rear]=k+1;//层次+1 
		} 
		
		if(p->rchild!=NULL)
		{//右孩子存在 
			Q.data[++Q.rear]=p->rchild;//右孩子入队 
			Q.level[Q.rear]=k+1;//记录右孩子层次 
		}
		
	}
	//出while循环后 每层的节点数以及相应的层数 都已被记录
	
	i=0,max=0;//i表示从入队的第一个元素开始向后扫描 
	k=1;//从第一层结点计数
	while(i<=Q.rear)
	{
		n=0;
		while(i<=Q.rear&&Q.level[i]==k)
		{
			n++;
			i++;
		}
		//出while后 表示第k层结点已遍历完
		//更新k
		k=Q.level[i]; 
		
		if(n>max) max=n;//记录最大的n 
	} 
	
	return max;
	
} 

15、设有一颗满二叉树(所有节点值均不同),已知其先序序列为pre,设计一个算法求其后序序列post。

//15、将满树的先序序列转换为后序序列
//递归:
//先序序列的第一个结点一定是后序序列的最后一个结点
//由于是满树 取一半元素 先序除了根结点前一半一定是后序的前一半结点(左子树) 
//同理 先序的后一半是后序的后一半 (右子树)

void PreToPost(ElemType pre[],int l1,int h1,ElemType post[],int l2,int h2)
{
	int half;
	if(h1>=l1)
	{
		post[h2]=pre[l1];
		half=(h1-l1)/2;
		PreToPost(pre,l1+1,l1+half,post,l2,l2+half-1);//递归转换左子树 
		PreToPost(pre,l1+half+1,h1,post,l2+half,h2-1);//递归转换右子树 
	}
 } 

16、设计一个算法将二叉树的叶节点按从左到右的顺序连成一个单链表,表头指针为head,二叉树按二叉链表方式存储,链接时用叶节点的右指针域来存当放单链表指针。

//16、将二叉树的叶节点从左到右链成一个单链表 用叶节点的右指针存放单链表指针
//思路:选择一种遍历方式 将访问操作改成链接操作

BiTree head,pre=NULL;

LinkList InOrder(BiTree bt)
{
	if(bt)
	{
		InOrder(bt->lchild);
		if(bt->lchild==NULL&&bt->rchild==NULL)
		{
			if(pre==NULL)//第一个叶结点 
			{
				head=bt;
				pre=bt;
			}else
			{
				pre->rchild=head;
				pre=bt;
			}
		}
		InOrder(bt->rchild);
		pre->rchild=NULL;//设置链表尾 
	}
	return head;
}

17、试设计判断两棵二叉树是否相似的算法。所谓二叉树T1和T2相似,指的是T1和T2都是空的二叉树或都只有一个根结点;或T1的左子树和T2的左子是树相似的,且T1的右子树和T2的右子树是相似的。

//17、判断两颗二叉树相似
//递归

int resemble(BiTree T1,BiTree T2)
{
	if(T1==NULL&&T2==NULL)
		return 1;
	if(T1==NULL||T2==NULL)//T1和T2只有一树为空 不相似 
		return 0;
	int Left,Right;
	Left=resemble(T1->lchild,T2->lchild);//递归 判断左子树 
	Right=resemble(T1->rchild,T2->rchild);//递归判断右子树 
	
	return Left&&Right;	//当左右子树都相似时 才相似 
} 

18、写出在中序线索二叉树里查找指定结点在后序的前驱结点算法。

//18、中序线索二叉树中找指定结点在后序的前驱结点算法 
//思路:在后序序列中 若结点p有右子女 则右子女是其前驱 若无右子女而有左子女 则其左子女是前驱
//若左右子女皆不存在 设其中序左线索指向某祖先结点f(f是p右子树中按中序遍历的第一个节点)
//若f有左子女 则其左子女是结点p在后序下的前驱;若f无左子女 则顺其前驱找双亲的双亲
//一直找到双亲有左子女(这时左子女是p的前驱)
//若p是总序遍历的第一个结点 则结点p在中序和后序下均无前驱

//线索二叉树的存储结构 

typedef struct ThreadNode {
	ElemType data;
	struct ThreadNode* lchild, * rchild;
	int ltag, rtag;//左右线索 标志 
}ThreadNode, * ThreadTree;

ThreadNode* InPostPre(ThreadTree T,ThreadNode* p)
{
	ThreadNode* q;
	if(p->rtag==0)//右子树存在 
		q=p->rchild;
	else if(p->ltag==0)//右子树不存在 左子树存在 
		q=p->lchild;
	else if(p->lchild==NULL)//p是中序遍历下的第一个结点 
		q=NULL;//没有前驱 
	else
	{
		//顺着线索找到有左子树的双亲
		while(p->ltag==1&&p->lchild!=NULL)
			p=p->lchild;
		if(p->ltag==0)
			q=p->lchild;//左子树为后序前驱 
		else//否则 是单支树 没有后序前驱 
			q=NULL; 
	}
	
	return q;
}

19、

//19、计算二叉树的带权路径长度
//思路:用层次遍历二叉树 同时记录当前层次

typedef struct BiTree{
	BiTree lchild,rchild;//孩子指针 
	int weight;//权值 
}BiTree;

typedef struct BiQueue{
	BiTree data[Max];
	int rear,front;
	int level[MaxSize];
}BiQueue;

//计算wpl  
int WPL(BiTree bt)
{
	BiQueue Q;
	BiTree p;
	int k;//表示结点层次 
	Q.rear=Q.front=-1;//队列初始化
	Q.rear++;
	Q.data[Q.rear]=bt;
	Q.level[Q.rear]=1;//根结点是第一层
	 
	while(Q.front<Q.rear)
	{
		p=Q.data[++Q.front];//出队 
		k=Q.level[Q.front];//记录结点层数 
		
		if(p->lchild!=NULL)
		{
			Q.data[++Q.rear]=p->lchild;
			Q.level[Q.rear]=k+1;
		}
		
		if(p->rchild!=NULL)
		{
			Q.data[++Q.rear]=p->rchild;
			Q.level[Q.rear]=k+1;
		}
	}
	
	int Rec=Q.level[Q.rear];//记录二叉树总共的层数 
	
	//while循环结束时 则将所有的结点和相应层次都保存了
	int sum=0;
	int i=0;
	for(k=1;k<=Rec;k++)
	{
		while(i<=Q.rear&&Q.level[Q.rear]==k)
		{//算每一层的wpl 
			sum+=Q.data[Q.rear].weight*(k-1);//边的条数为层数-1 
			i++;
		}	
	}
		
	return sum; 
} 
//以上解法 是计算所有结点的带权路径长度

//计算叶节点的带权路径长度
//解法一:基于先序遍历的算法

int WPL(BiTree root)
{
	return wpl_PreOrder(root,0);
}

int wpl_PreOrder(BiTree root,int deep)
{
	static int wpl=0;//静态变量 在程序执行的整个期间一直存在
	
	if(root->lchild==NULL&&root->rchild==NULL)
		wpl+=deep*root->weight;//若为叶节点则累积wpl
		
	if(root->lchild!=NULL)//左子树存在 递归遍历左子树 
		wpl_PreOrder(root->lchild,deep+1);
		
	if(root->rchild!=NULL)//右子树存在 递归遍历右子树 
		wpl_PreOrder(root->rchild,deep+1);
	return wpl; 
}

//解法二:基于层次遍历的解法
int wpl_LevelOrder(BiTree root)
{
	BiTree q[MaxSize];
	BiTree lastNode,newlatNode;//lastNode表示当前层的最后一个节点 newlastNode表示下一层的最后一个结点
	lastNode=root,newlastNode=NULL;//lastNode初始化为根结点 newlastNode初始化为NULL
	int end1,end2;//end2为队尾 end1为队头
	end1=end2=0;
	int wpl=0,deep=0;//初始化wpl 和 深度
	q[end2++]=root;
	
	while(end1!=end2)
	{
		BiTree p=q[end1++];
		
		//当前结点是叶子结点 累积wpl 
		if(p->lchild==NULL&&p->rchild==NULL)
			wpl+=deep*p.weight;
			
		//存在左子树 入队 
		if(p->lchild!=NULL)
		{
			q[end2++]=p->lchild;
			newlastNode=p->lchild;//修改newlastNode 
		}
		
		//存在右子树 入队 
		if(p->rchild!=NULL)
		{
			q[end2++]=p->rchild;
			newlastNode=p->rchild;
		}
		
		if(p==lastNode)
		{//访问到当前层的最后一个结点
			lastNode=newlastNode;//修改当前层的最后一个结点指向下一层最后一个节点 
			deep++;//深度+1 
			
		}
	} 
	return wpl;
} 

20、 

//20、将给定二叉树转换为中缀表达式 用括号显示运算顺序
//修改中序遍历即可 注意:根结点和叶子结点不加括号
//而分支节点则要加括号

typedef struct node{
	char data[10];//存储操作数 或 操作符 
	struct node *left,*right;
}BTree; 

void BtreeToE(BTree *root)
{
	BtreeToExp(root,1);
}

void BtreeToExp(BTree *root,int deep)
{
	if(root==NULL)
		return;
	else if(root->left==NULL&&root->right==NULL)
		printf("%s",root->data);//有疑问 如果是数组的话 确实用%s 但root->data 是调值 感觉是字符 用%c 
	else
	{
		if(deep>1) printf("(");//有子表达式 即分支结点 加一层括号 
		BtreeToExp(root->left,deep+1);//往下遍历时 深度+1 
		printf("%s",root->data);
		BtreeToExp(root->right,deep+1);
		if(deep>1) printf(")"); 
	}
}

5_4

04、编程求以孩子兄弟表示法存储的森林的叶子结点数。

//求孩子-兄弟表示法的叶节点综述
//递归: 
typedef struct node{
	ElemType data;
	struct node *fch,*nsib;//孩子指针 和 兄弟指针 
}*Tree; 

int Leaves(Tree T)
{
	if(T==NULL)
		return 0;
	if(T->fch==NULL)//无孩子 则自身就是叶节点 
		return 1+Leaves(T->nsib);
	if(T->fch!=NULL);//有孩子 则叶节点为孩子树上和兄弟树上之和 
		return Leaves(T->fch)+Leaves(T->nsib); 
}

05、以孩子兄弟链表为存储结构,请设计递归算法求树的深度。

//求孩子兄弟链表表示的树高
//递归求树的高度都类似

//因为此时表示法的根结点没有右孩子 树高就是左子树树高+1
//由于第一个孩子的右子树和第一个孩子的高度是相同的 所以比较第一个孩子的左子树高度+1和右子树高度即可 
 
int height(CSTree bt)//Child-Sibling Tree
{
	int hc,hs;//孩子树高度 和 兄弟树高度 
	if(bt==NULL)
		return 0;
	else
	{//高度取子女高度+1和兄弟子树高度的大者 
		hc=height(bt->firstchild);//第一子女树 高 
		hs=height(bt->nextsibling);//兄弟树高 
		
		if(hc+1>hs)
			return hc+1;
		else
			return hs;
	}
 } 

06、已知一颗树的层次序列及每个结点的度,编写算法构造此树的孩子-兄弟链表。

 //设立一个辅助数组pointer[]存储新建树的各结点的地址
 //再根据层次序列与每个结点的度 逐个链接结点
 
 #define maxNodes 15
 
typedef struct CSNode{
 	CSNode *lchild,*rsibling;
 	ElemType data;
 }CSNode;
 
 void createCSTree_Degree(CSTree &T,DataType e[],int degree[],int n) 
 {//e[]存储层次遍历的序列 degree[]存储结点的度 n是结点个数 
 	CSNode* pointer=new CSNode[maxNodes];
 	int i,j,d,k=0;
 	
 	//将pointer[]初始化 
 	for(i=0;i<n;i++)
 	{
 		pointer[i]->data=e[i];
 		pointer[i]->lchild=pointer[i]->rsibling=NULL;
	}
	
	for(i=0;i<n;i++)
	{
		d=degree[i];
		if(d)
		{
			k++;//第一个"度"结点是左孩子 
			pointer[i]->lchild=pointer[k];
			for(j=2;j<=d;j++)
			{
				k++; 
				pointer[k-1]->rsibling=pointer[k];//剩余"度"结点是右兄弟 
			}
		}
	}
	
	T=pointer[0];//将第一个结点作为树根 
	delete [] pointer;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值