二叉树相关代码题【较全】C语言

文章目录

  • 一、树相关代码题
    • 1.编写后序遍历的非递归算法(栈实现)
    • 2.二叉链表存储,左右子树进行交换(后序)
    • 3.二叉链表存储,编写算法实现二叉树的层次遍历
    • 4.编写实现二叉树后序线索化的算法(中序 先序类似)
    • 5.二叉链表存储,求先序遍历序列中第k(1≤k≤二叉树中结点个数)个结点的值--计数器
    • 6.在先序线索树中找出X结点的后继结点
    • 7.在后序线索树中找出X结点的前驱结点
    • 8.给出二叉树的自下而上,从右到左的层次遍历算法--栈
    • 9二叉链表存储 求二叉树的高度(递归非递归)
      • 9.1二叉链表存储,非递归算法求二叉树的高度(层序)
      • 9.2二叉链表存储,递归算法求二叉树的高度(后序)
      • 9.3二叉链表存储,递归算法求二叉树的高度(前序)
    • 10.二叉链表存储,判定一棵二叉树是否是完全二叉树
    • 11.二叉链表存储,判断两棵二叉树是否相似
    • 12.对一棵以孩子兄弟链表表示的树统计其叶子结点的数目(左子树为空则为叶子结点)
    • 13.求以孩子兄弟表示法存储的树的高度(左子树高度加一 右子树高度不变进行递归)
    • 14.树root采用孩子—兄弟表示法存储, 编写算法输出该树中值为X 的结点的所有兄弟结点
    • 15.二叉链表存储,求二叉树的宽度(即具有结点数最多的那一层的结点个数)
    • 16 求从根结点到r结点之间的路径
      • 16.1二叉链表存储,求二叉树根结点到r结点之间的路径(后序遍历基于栈的递归消除)
      • 16.2在二叉树中查找值为x的结点,编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于一个。
    • 17.已知一棵二叉树按顺序放到hi存储在数组A[1……n]中。设计算法求出下标分别为i和j的两个结点的最近的公共祖先结点的值
    • 18.采用二叉链表存储,root指向根结点,p所指结点和q所指结点为二叉树中的两个结点,编写一个计算它们最近的共同祖先的函数(后序遍历 基于栈的递归消除)
    • 19.编写递归算法:对于二叉树中每一个值为x的结点,删去以它为根的子树,并释放相应的空间
    • 20.采用二叉链表存储,编写算法求取一棵二叉树的路径长度。(二叉树的路径长度是指从树根到树中所有结点的路径长度之和。二叉树中结点的路径长度为该结点所在的层次值-1,根结点在第一层,以此类推)
    • 22.一棵二叉树中各结点的值互不相同,其先序序列和中序序列分别存放在两个数组当中A[1……n]、 B[1……n]中,编写算法建立该二叉树的二叉链表(递归)


一、树相关代码题

1.编写后序遍历的非递归算法(栈实现)

//基于栈的递归消除(后序遍历)
void PostOrder2(BiTree root){
	BiTNode *p,*q;
	Stack S;
	InitStack(&S);
	p=root;
	while(p!=NULL||IsEmpty(S)){
		if(p!=NULL){
			Push(&S,p);
			p=p->LChild;
		}
		GetTop(&S,&p);
		if(p->Rchild==NULL||p->Rchild==q){
			visit(p->data);
			q=p;
			Pop(&S,&p);
			p=NULL;
		}else	
		p=p->Rchild;
	}
}

2.二叉链表存储,左右子树进行交换(后序)

//交换二叉树的左右子树(后序)
void swap(BiTree *root){
	if(bt!=NULL){
		swap(root->LChild);
		swap(root->Rchild);
		temp=root->LChild;
		root->LChild=root->Rchild;
		root->Rchild=temp;
	}
} 

3.二叉链表存储,编写算法实现二叉树的层次遍历

//层序遍历二叉树
void LevelOrder(BiTree root){
	LinkQueue Q;
	InitQueue(Q);
	BiTNode *p;
	EnQueue(&Q,root);
	while(IsEmpty(Q)){
		DeQueue(&Q,&p);
		visit(p->data);
		if(p->LChild!=NULL)
			EnQueue(&Q,p->LChild);
		if(p->RChild!=NULL)
			EnQueue(&Q,p->RChild);		
	}	
} 

4.编写实现二叉树后序线索化的算法(中序 先序类似)

//后序遍历二叉树,一边遍历一边线索化
void PostThread(ThreadTree root){
	if(root!=NULL){
		PostThread(T->lchild);
		PostThread(T->rchild);
		visit(T);
	}
}
void visit(ThreadNode *q){
	if(q->LChild==NULL){//左子树为空,建立前驱线索
		q->LChild=pre;
		q->Ltag=1; 
	}
	if(pre!=NULL&&pre->RChild==NULL){
		pre->RChild=q;
		pre->Rtag=1;
	}
	pre=q;
}
//后序线索化二叉树 
void CreatePostThread(Thread T){
	if(T!=NULL){
		PostThread(T);
		if(pre->rchild == NULL) //处理最后一个结点 
			pre->rtag=1;
	}
}
ThreadNode *pre = NULL;     //全局变量pre,指向当前访问结点的前驱 

5.二叉链表存储,求先序遍历序列中第k(1≤k≤二叉树中结点个数)个结点的值–计数器

void PreOrder(BiTree root,int k,char *e){
	int i = 0;
	if(root!=NULL){
		Visit(root->data);
		i++;
		if(i==k){
			*e = root->data;
		}
		PreOrder(root->LChild);
		PreOrder(root->Rchild);
	}
} 

6.在先序线索树中找出X结点的后继结点

//先序线索二叉树中找先序后继
ThreadNode * PrePost(ThreadNode *p){
	BiTNode *next,*q;
	if(p->LChild!=NULL){
		next=p->LChild;
	}else{
		next=p->Rchild;
	}
	return next;
} 

7.在后序线索树中找出X结点的前驱结点

//后序线索二叉树中找后序前驱 
ThreadNode * PostPre(ThreadNode *p){
	BiTNode *pre,*q;
	if(p->RChild!=NULL){
		pre=p->RChild;
	}else{
		pre=p->Lchild;
	}
	return pre;
} 

8.给出二叉树的自下而上,从右到左的层次遍历算法–栈

//二叉树的自下而上,从右到左的层次遍历算法
void LevelOrder(BiTree root){
	SeqStack S;
	InitStack(&S);
	LinkQueue Q;
	InitQueue(&Q);
	BiTNode *p;
	EnQueue(&Q,root);
	Push(&S,root);
	while(QueueIsEmpty(Q)){
		DeQueue(&Q,&p);
		visit(p->data);
		if(p->LChild!=NULL){
			EnQueue(&Q,p->LChild);
			Push(&S,p->LChild);
		}
		if(p->RChild!=NULL){
			EnQueue(&Q,p->RChild);
			Push(&S,p->RChild);	
		}	
	}//退出while循环 元素以全部放入栈中
	//出栈 
	while(StackIsEmpty(S)==0){  //将栈中结点弹出
        	BiTNode *temp;
			temp = Pop(&S);
			printf("%c",temp->data);
	}	
} 

9二叉链表存储 求二叉树的高度(递归非递归)

9.1二叉链表存储,非递归算法求二叉树的高度(层序)

算法的执行步骤:
1、如果树为空,则直接返回错。
2、如果树不为空:层次遍历二叉树 ;
区别不同于单纯的层序遍历

  • 在进行当前结点的左右孩子入队时,记录左右孩子的个数child
  • 每次结点进行出队操作时,都要比较此时队列中元素个数 与 之前记录的左右孩子个数是否相等
  • 如果不相等则说明当前层还没遍历完
  • 如果相等则说明开始遍历下一层结点了 需要h+1 并且需要将child重置为0
//非递归算法求二叉树的高度
int findTreeHight(BiTree root){
	Queue Q;	//创建队列 
	InitQueue(*Q);
	BiTree t;
	t = root;
	EnterQueue(&Q,t);
	int h = 0;	//记录高度 初始从1开始
	int child = 0;
	while(!IsEmptyQueue(Q)){
		if(t->LChild){
			EnterQueue(&Q,t->LChild);  //左孩子入队 
			child++;
		}
		if(t->RChild){
			EnterQueue(&Q,t->RChild);	//右孩子入队 
			child++;
		}		
		DeleteQueue(&Q,&t);	//队头出队 
		if(child == Q.len){	//len为队列中元素个数 
			h++;
			child = 0;
		}
	}
	return h;
}

9.2二叉链表存储,递归算法求二叉树的高度(后序)

//求二叉树的高度(后序)
int PostTreeDepth(BiTree bt){
	int hl,hr,max;
	if(bt!=NULL){
		hl=PostTreeDepth(bt->LChild);  //求左子树的深度 
		hr=PostTreeDepth(bt->Rchild);  //求右子树的深度 
		max=hl>hr?hl+1:hr+1;
		return max;
	}
	else return 0;
} 

9.3二叉链表存储,递归算法求二叉树的高度(前序)

//求二叉树的高度(前序)
int PreTreeDepth(BiTree bt,int h){  //h为bt指向结点的所在层次 初值为1 
	//可以通过遍历计算二叉树中每个结点的层次
	//最大值为二叉树的高度
	if(bt!=NULL){
		if(h>depth)
			depth=h;  //depth是全局变量 初始为0 
		PreTreeDepth(bt->LChild,h+1);
		PreTreeDepth(bt->RChild,h+1);
	} 
	return depth; 
} 

10.二叉链表存储,判定一棵二叉树是否是完全二叉树

算法的执行步骤:
1、如果树为空,则直接返回错。
2、如果树不为空:层次遍历二叉树 ;
2.1、如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树;
2.2、如果一个结点左右孩子都不为空,则pop该节点,将其左右孩子入队列;
2.3、如果遇到一个结点,左孩子不为空,右孩子为空;或者左右孩子都为空;则该节点之后的队列中的结点都为叶子节点; 该树才是完全二叉树,否则就不是完全二叉树。

//判断二叉树是否为完全二叉树 
int Judge_Complete(BiTree boot)
{
	BiTree t;
	LinkQueue Q;//创建一个空队列
	InitQueue(Q);
	EnQueue(Q,root); //将T的头结点入队
	t = root;//给t赋初值T根节点
	if(root==NULL)
		return 0;
	while(IsEmpty(Q))
	{
		if(t->lchild==NULL && t->rchild!=NULL)//如果左孩子为空右孩子不为空,说明一定不是完全二叉树
			return false;
		if(t->lchild!=NULL && t->rchild!=NULL)//左右孩子都不为空
		{	
			DeQueue(Q,t);//删除该双亲节点
			EnQueue(Q,t->lchild); //将左孩子入队
			EnQueue(Q,t->rchild); //将右孩子入队
		}
	//如果左孩子不为空右孩子为空,或者左右孩子都为空(该节点为叶子结点)
	//则该节点之后的所有节点都应该是叶子结点
		if((t->lchild!=NULL && t->rchild==NULL) || (t->lchild==NULL && t->rchild==NULL))
		{
			DeQueue(Q,t); //从刚才判断的节点的下一个节点一次判断剩下队列中的节点是否左右子树都为空
			while(IsEmpty(Q))
			{
				if(t->lchild==NULL && t->rchild==NULL)
					DeQueue(Q,t);
				else
					return false;
			}	
			return true;
		}			
	}
	return true;
}

11.二叉链表存储,判断两棵二叉树是否相似

所谓二叉树t1与t2相似,指的是t1与t2都是空二叉树;或者 t1的左子树与t2的左子树相似,同时t1的右子树与t2的右子树相似。
算法的执行步骤:

  • f(t1,t2)=TRUE,若t1=t2=NULL
  • f(t1,t2)=FALSE,若t1与t2其中一个为NULL,另一个不为NULL
  • f(t1,t2)=f(t1->left,t2->left)&&f(t1->right,t2->right);若t1与t2均不为NULL
//二叉树相似性判断
int like(BiTree t1,BiTree t2){
	int like1,like2;
	if(t1==NULL && t2==NULL){   //t1和t2均为空树 相似,返回1 
		return 1;
	}
	else if(t1==NULL || t2==NULL){ //t1和t2其中之一为空树,不相似 ,返回0 
		return 0;
	}
	else{
		like1 = like(t1->LChild,t2->LChild); //判断t1和t2的左子树是否相似 
		like2 = like(t1->Rchild,t2->Rchild); //判断t1和t2的右子树是否相似  
		return (like1&&like2);
	}
} 

12.对一棵以孩子兄弟链表表示的树统计其叶子结点的数目(左子树为空则为叶子结点)

int leafnum; //全局变量 统计叶子结点数目 
//对一棵以孩子兄弟链表表示的树统计其叶子结点的数目(左子树为空则为叶子结点)
int getLeafNum(CSTree tree){
	if(tree!=NULL){
		if(tree->FirstChild!=NULL){
			leafnum++;   //全局变量 统计叶子结点数目 
		}
		getLeafNum(tree->FirstChild);
		getLeafNum(tree->Nextsibling); 	
	}
}

13.求以孩子兄弟表示法存储的树的高度(左子树高度加一 右子树高度不变进行递归)

int max=0; //全局变量 
//以孩子兄弟表示法存储的树的高度
int getHeight(CSTree tree,int layer){
	if(tree!=NULL){
		if(layer>max){
			max=layer;
		}
		getHeight(tree->FirstChild,layer+1);
		getHeight(tree->Nextsibling,layer);
	}
	return max;
} 

14.树root采用孩子—兄弟表示法存储, 编写算法输出该树中值为X 的结点的所有兄弟结点

算法的执行步骤:
1、如果树为空,则直接返回错。
2、如果树不为空:遍历二叉树找到值为X的结点
2.1、while循环输出该结点的右结点,直到右结点为NULL

CSNode * PreOrder(CSTree root,char x){
	CSNode *temp;
	if(root!=NULL){
		if(root->data==x){
			temp=root;
		}
		PreOrder(root->LChild);
		PreOrder(root->Rchild);
	}
	return temp;
} 
//采用孩子—兄弟表示法存储, 编写算法输出该树中值为X的结点的所有兄弟结点
void BroNodeX(CSTree root,char x,CSNode[] *bro){
	int i=0;
	CSNode *p;
	p=PreOrder(root,x);
	p=p->Nextsibling;
	while(p!=NULL){
		bro[i++]=p;
		p=p->Nextsibling;
	}
} 

15.二叉链表存储,求二叉树的宽度(即具有结点数最多的那一层的结点个数)

算法的执行步骤:
1、如果树为空,则直接返回错。
2、如果树不为空:层次遍历二叉树 ;

  • 区别不同于单纯的层序遍历- 在进行当前结点的左右孩子入队时,记录左右孩子的个数num
  • 每次结点进行出队操作时,都要比较此时队列中元素个数 与 之前记录的左右孩子个数是否相等
  • 如果不相等则说明当前层还没遍历完
  • 如果相等则说明开始遍历下一层结点了 需要h+1 并且需要将num重置为0
  • 还需要初始化一个max初始为0,将max与num比较 max中保存的就是某层最多的结点树
//二叉链表存储,求二叉树的宽度
int findTreeWidtht(BiTree root){
	Queue Q;	//创建队列 
	InitQueue(*Q);
	BiTree t;
	t = root;
	EnterQueue(&Q,t);
	int h = 1;	//记录高度 初始高度为1
	int num = 0;
	int max = 0;
	while(!IsEmptyQueue(Q)){
		if(t->LChild){
			EnterQueue(&Q,t->LChild);  //左孩子入队 
			num++;
		}
		if(t->RChild){
			EnterQueue(&Q,t->RChild);	//右孩子入队 
			num++;
		}		
		DeleteQueue(&Q,&t);	//队头出队 
		if(num == Q.len){	//len为队列中元素个数 
			if(max<num){
				max=num;
			}
			h++;
			num = 0;
		}
	}
	return max;
}

16 求从根结点到r结点之间的路径

16.1二叉链表存储,求二叉树根结点到r结点之间的路径(后序遍历基于栈的递归消除)

16.2在二叉树中查找值为x的结点,编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于一个。

先复习一遍后序遍历时栈的操作:
二叉树相关代码题【较全】C语言_第1张图片

二叉树相关代码题【较全】C语言_第2张图片

//二叉链表存储,求二叉树根结点到r结点之间的路径
void path(BiTree root,BiTNode *r){
	BiTNode *p,*q;
	int i,top=0;
	BiTree s[Stack_Size];
	q=NULL;
	p=root;
	while(p!=NULL||top!=0){
		while(p!=NULL){
			top++;
			if(top>=Stack_Size)
				overFlow(); //栈溢出
			s[top]=p;
			p=p->LChild;  //遍历左子树 
		}
		if(top>0){
			p=s[top];
			if(p->Rchild==NULL||p->Rchild=q){
				if(p==r){           //找到r所指结点,显示从根结点到r结点之间的路径
					for(i=1;i<=top;i++)
						printf("%d",s[i]->data);
					return;
				}
				else{
					q=p;  //用q保留刚遍历过的结点 
					top--;
					p=NULL; //跳过前面左遍历,继续退栈 
				}
			}
			else p=p->Rchild; //遍历右子树 
		}
	}
}

17.已知一棵二叉树按顺序放到hi存储在数组A[1……n]中。设计算法求出下标分别为i和j的两个结点的最近的公共祖先结点的值

二叉树相关代码题【较全】C语言_第3张图片

int find_public(BiTNode T[],int i,int j)//注意这里不是BiTNode* &T
{
    if(T[i].data!='#'&&T[j].data!='#')//还要判断结点是否存在
    {
        while(i!=j)
        {
            if(i>j)
                i=i/2;
            else
                j=j/2;
        }
        return i;
    }
    else
        return 0;
}

18.采用二叉链表存储,root指向根结点,p所指结点和q所指结点为二叉树中的两个结点,编写一个计算它们最近的共同祖先的函数(后序遍历 基于栈的递归消除)

算法步骤:
参考16题,相当于利用两个栈 保存从根结点分别到结点p,q路径上的所有结点。之后比较两个栈中元素,最先相等的就i是最近的共同祖先

//二叉链表存储,求二叉树结点p q的最近公共祖先 
BiTNode * PostOrder2(BiTree root,BiTNode *p,BiTNode *q){
	BiTNode *bt,*pre;
	int i,j,top1,top=-1;
	BiTree S[Stack_Size],S1[Stack_Size];
	pre=NULL;
	bt=root;
	while(bt!=NULL||top!=0){
		while(bt!=NULL){
			top++;
			if(top>=Stack_Size)
				overFlow(); //栈溢出
			S[top]=bt;
			p=p->LChild;  //遍历左子树 
		}
		if(top>-1){
			bt=S[top];
			if(bt->Rchild==NULL||bt->Rchild=pre){
				if(bt==p){
					for(i=0;i<top;i++){
						S1[i]=S[i];
						top1=top;						
					}	
				}	
				if(bt==q){
					for(i=top;i>-1;i--)
						for(j=top1;j>-1;j--){
							if(S[i]==S1[j])
								return S[i];
						}
				}
				pre=bt;  //用pre保留刚遍历过的结点 
				top--;
				bt=NULL; //跳过前面左遍历,继续退栈 
			}
			else bt=bt->Rchild; //遍历右子树 
		}
	}
	return NULL;
}

19.编写递归算法:对于二叉树中每一个值为x的结点,删去以它为根的子树,并释放相应的空间

算法分析:删除以元素值为x根的子树,只要能删除其左、右子树,就可以释放值为x的根结点,因此采用后序遍历算法。
算法步骤:
1、遍历二叉树找到值为x的结点
2、调用删除函数,进行删除并释放空间
:因为题中要求删除树中每个元素值为x的结点的子树,因此要遍历完整整棵二叉树

//对于二叉树中每一个值为x的结点,删去以它为根的子树,并释放相应的空间
void DeleteXTree(BiTree *bt){  //删除以bt为根的子树 
	DeleteXTree(bt->LChild);
	DeleteXTree(bt->Rchild);
	free(bt);
}
//在二叉树上查找所有以x为元素值的结点,并删除
void SearchX(BiTree bt,char x){
	LinkQueue Q;
	InitQueue(Q);
	BiTNode *p;
	EnQueue(&Q,bt);
	while(IsEmpty(Q)){
		DeQueue(&Q,&p);
		if(p->LChild!=NULL){
			if(p->LChild->data==x)
				DeleteXTree(&(p->LChild));
				p->LChild=NULL;
			else
				EnQueue(&Q,p->LChild);			
		}
		
		if(p->RChild!=NULL){
			if(p->RChild->data==x)
				DeleteXTree(&(p->RChild));
				p->RChild=NULL;
			else
				EnQueue(&Q,p->RChild);	
		}
	}	
} 

20.采用二叉链表存储,编写算法求取一棵二叉树的路径长度。(二叉树的路径长度是指从树根到树中所有结点的路径长度之和。二叉树中结点的路径长度为该结点所在的层次值-1,根结点在第一层,以此类推)

算法思路:
同15题、9题,求出第几层 以及每层结点个数累加即可。

//求取一棵二叉树的路径长度
int findTreeWidtht(BiTree root){
	Queue Q;	//创建队列 
	InitQueue(*Q);
	BiTree t;
	t = root;
	EnterQueue(&Q,t);
	int h = 0;	//记录高度
	int num = 0;
	int wpl = 0;
	while(!IsEmptyQueue(Q)){
		if(t->LChild){
			EnterQueue(&Q,t->LChild);  //左孩子入队 
			num++;
		}
		if(t->RChild){
			EnterQueue(&Q,t->RChild);	//右孩子入队 
			num++;
		}		
		DeleteQueue(&Q,&t);	//队头出队 
		if(num == Q.len){	//len为队列中元素个数 
			h++;
			wpl+=h*num;
			num = 0;
		}
	}
	return wpl;
}

22.一棵二叉树中各结点的值互不相同,其先序序列和中序序列分别存放在两个数组当中A[1……n]、 B[1……n]中,编写算法建立该二叉树的二叉链表(递归)

//已知先序 中序遍历序列 建立二叉链表 
int pos=0;//全局变量 
tree build(char pre[],char in[],int begin,int end)
{
    if(s<=e)
    {
        BiTNode *root=(BiTNode *)malloc(sizeof(BiTNode));
        root->data=pre[pos];
        int i;
        for(i=begin;i<=end;i++) 
			if(in[i]==root->data) 
				break;
        pos++;
        root->lchild=build(pre,in,begin,i-1);
        root->rchild=build(pre,in,i+1,end);
        return root;
    }
    return NULL;
}

你可能感兴趣的:(c语言,链表,数据结构)