数据结构基础(5) 树与森林

CONTENT

  • 树的存储结构:
    1.双亲表示
    2.孩子链表表示
    3.树的二叉链表(重点)
  • 树,森林与二叉树的转换(firstchild,nextsibling)
  • 遍历
    在这里插入图片描述
  • 如何建树:转为二叉树利用二叉树序列来建树;直接对输入的父亲孩子对进行建树
#include "stdio.h"
#include "stdlib.h"
#define N 30

typedef struct node
{
	char data;
	struct node *fir,*sib,*pa;//左第一个孩子(子树森林),兄弟节点(其余子树构成的森林),父节点 
}TR;

TR *createtree(char *pre,int *k);//建树 
int height(TR *T);//求树的高度(递归:max(子树的高度加1与其余树组成森林中树高度的最大值)) 
void preorder(TR *T);//先序遍历 (相当于二叉树的先序遍历) \*/ 
void postorder(TR *T);//后序遍历 (相当于二叉树的中序遍历)\*/
void layer(TR *T);//层次遍历 (队列,非递归) 
TR *deltree(TR *T);//删除树 
void showtree(TR *T);//括号形式显示树 
void getpa(TR *T);//为节点的父节点赋值 
void showpa(TR *T);//输出各点的父节点 
TR *findpa(TR *T,TR **pa,char data);//返回值为data的节点指针,同时靠二重指针带出其父节点的指针 
void allpath(TR *T,char *route,int top); //输出所有根到叶子的路径 



main()
{
	char pre[]="ABE F  C DGH I J     ";
	TR *T=NULL,*p,*pa;
	char data;
	int k=0;
	T=createtree(pre,&k);
	printf("\n树:\n");
	if(!T)
		printf("树为空\n");
	else
	    showtree(T);	
	printf("\n\n");
	printf("\n先序遍历:\n");
	preorder(T);
	printf("\n后序遍历:\n");
	postorder(T);
	printf("\n层次遍历:\n");
	layer(T);
	printf("\n树的高度=%d\n",height(T));
	printf("\n\n请输入带查找的节点数据:");
	scanf("%c",&data);
	while(data!='#')
	{
		getchar();
		pa=p=NULL;
		p=findpa(T,&pa,data);
		if(!p)
			printf("%c不存在\n",data);
		else
		{
			if(!pa)
				printf("%c是根节点,没有父节点\n",data);
			else
				printf("%c的父节点是%c\n",data,pa->data);
		}
		printf("\n请输入带查找的节点数据:");
	    scanf("%c",&data);
	}
	printf("\n");
	getpa(T);
	showpa(T);
	char route[N];
	printf("输出所有到叶子节点的路径:\n");
	allpath(T,route,-1);
	T=deltree(T);	
}


TR *createtree(char *pre,int *k)
{
	TR *T;
	if(pre[*k]==' ')
		return NULL;
	else
	{
		T=(TR *)malloc(sizeof(TR));
		T->data=pre[*k];
		(*k)++;		
		T->fir=createtree(pre,k);
		(*k)++;
		T->sib=createtree(pre,k);
		return T;

	}

}
int height(TR *T)
{	
	int h1,h2;
	if(T)
	{	//一棵树的高度是这棵树的子树高度加1与兄弟节点树高度中的最大值 
		h1=1+height(T->fir);
		h2=height(T->sib);
		return h1>h2?h1:h2;
	}
	else return 0;
}



void preorder(TR *T)
{
	if(T)
	{
		printf("%c ",T->data);
		preorder(T->fir);
		preorder(T->sib);
	}
	
	
}

void postorder(TR *T)//树的后序遍历就是对应二叉树的中序遍历 
{
	TR *t[N],*p=T;
	int top=-1;
	while(top>=0||p)
	{
		while(p)
		{
			top++;
			t[top]=p;
			p=p->fir;
		}
		p=t[top];
		top--;
		printf("%c ",p->data);
		p=p->sib;
	}
	/*if(T)
	{
		postorder(T->fir);
		printf("%c ",T->data);
		postorder(T->sib);
	}*/
	
	
}
void layer(TR *T)//队列 
{
	TR *p=T;
	int front=-1,rear=-1;
	TR *t[N];
	t[++rear]=T;
	printf("%c ",p->data);
	while(rear!=front)
	{	
		p=t[front+1]->fir;
		while(p)
		{	
			t[++rear]=p;
			printf("%c ",p->data);
			p=p->sib;
		}
		front++;
		
	}
	printf("\n");
}

TR *deltree(TR *T)//销毁树
{
	TR *p=T,*p2;
	if(!T)
		return NULL;
	else
	{
		p=T->fir;
		while(p)
		{
			p2=p->sib;
			free(p);
			p=p2;
		}
		free(T);
		return NULL;
	}
	
}
void showtree(TR *T)
{	
	TR *p;
	if(T)
	{
		printf("%c",T->data);
		p=T->fir;
		if(p)
		{	
			printf("(");
			showtree(p);
			p=p->sib;
			while(p)
			{	
				printf(",");
				showtree(p);
				p=p->sib;
			}
			printf(")");
		} 
	} 
}


TR *findpa(TR *T,TR **pa,char x)
{
	TR *target=NULL,*p;
	if(T)
	{
		if(T->data==x)
		{	*pa=NULL;
			return T;
		}
		else
		{
			p=T->fir;
			while(p)
			{	if(p->data==x)
				{
					*pa=T;
					return p; 
				}
				target=findpa(p,pa,x);
				if(target) return target;
				p=p->sib;
			}
		}
	 } 
}


void getpa(TR *T)
{	
	TR *p;
	if(T)
	{
		p=T->fir;
		while(p)
		{	
			getpa(p);
			//与p->pa顺序不能呼唤,不然先赋值正确的pa被后来的NULL覆盖了 
			p->pa=T;
			p=p->sib;
		}
		T->pa=NULL;	
	}
	
}
void showpa(TR *T)
{
	if(T)
	{
		if(!(T->pa))
			printf("%c---NULL\n",T->data);
		else
			printf("%c---%c\n",T->data,T->pa->data);
		showpa(T->fir);
		showpa(T->sib);
	}	
}
void allpath(TR *T,char *route,int top)
{	TR *p;
	if(T)
	{	route[++top]=T->data;
		if(!T->fir)
		{
			int i;
			for(i=0;i<=top;i++)
			printf("%c ",route[i]);
			printf("\n");
		}
		else
		{	
			p=T->fir;
			while(p)
			{
				allpath(p,route,top);
				p=p->sib; 
			}	
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值