树的兄弟表示法

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 1
#define OVERFLOW -2
using namespace std;
typedef int Status;
typedef char ElemType;//设置结点的值为字符
typedef struct CSNode{
	ElemType data;
	struct CSNode *firstChild;//第一个孩子
	struct CSNode * nextsbling;//该孩子的第一个兄弟
}CSNode,*CSTree;
typedef CSTree QElemType;//结构体指针 ,指向该结构类型
typedef struct QNode{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
Status InitQueue(LinkQueue &Q)//构造一个控队列
{
//这是在创建线性表,用于存放结点
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));//队头结点
if(!Q.front)
	exit(OVERFLOW);
Q.front->next=NULL;
return OK;
}
//判断存放结点的队列是否为空
Status QueueEmpty(const LinkQueue &Q)//若队列为空,则返回true,否则返回false
{
if(Q.rear==Q.front)
 	return TRUE;
 return FALSE;
}
//增加队列 是在队尾增加,把兄弟类型结构体作为一个结点加到顺序队列的队尾
Status EnQueue(LinkQueue &Q,QElemType e)//在Q的队尾插入元素e
{
 	QueuePtr p=(QueuePtr)malloc(sizeof(QNode));//为队尾的结点开辟空间
if(!p)
	exit(OVERFLOW);
p->data=e;
p->next=NULL;//此时已经是尾部,没有下一个结点了 所以结点位NULL
Q.rear->next=p;//原先队列的队尾的下一个结点指向P
Q.rear=p;//自然而然的p就成了队列的队尾,也即是最后一个元素
return OK;
}
//删除队列中的元素 ,从队头开始删
Status DeQueue(LinkQueue &Q,QElemType &e)//若队列不为空 则删除Q的队头元素.用e返回其值 并返回ok
{
//如果是空队列,那么就会报错
	if(Q.front==Q.rear){
	return ERROR;//此时队列为空
}
	QueuePtr p=Q.front->next;//创建一个指针p,用于接收删除的指针头
	e=p->data;
	Q.front->next=p->next;//将新元素赋值给队头的下一个元素
	if(Q.rear==p)
		Q.rear=Q.front;//如果删完之后 队列中没有元素了 ,那么队列就是空队列了
	free(p);
	return OK;
}
Status CreateTree(CSTree &T)//创建一颗树
{
LinkQueue Q;
InitQueue(Q);//创建一个空队列
char buffChild[20];//用于存放孩子的缓存,最多存放20个孩子
memset(buffChild,0,20);//初始化缓存数组 置为NULL
printf("请输入树的根节点(字符,以#代表空):\n");
//如果输入'#',代表开辟的是根结点
scanf("%c",&buffChild[0]);
if(buffChild[0]!='#')
{
	T=(CSTree)malloc(sizeof(CSNode));//为根结点开辟一个空间
	if(!T)
		exit(OVERFLOW);//开辟失败  终止程序
	T->data=buffChild[0];//跟结点的数据部分就是buffChild[0]存放的数据
	T->nextsbling=NULL;//根结点没有兄弟结点
	EnQueue(Q,T);//将根结点放到队列中
	while(!QueueEmpty(Q)){//先判断队列是否为空
	QElemType e;
	DeQueue(Q,e);//结点出队
	printf("请按照长幼顺序输入结点%c的孩子(输入的字符串以#结束):\n",e->data);
	scanf("%s",buffChild);
	if(buffChild[0]!='#')//有孩子  
{
	CSTree q;
	q=(CSTree)malloc(sizeof(CSNode));//开辟孩子结点空间
	if(!q)
		exit(OVERFLOW);
	q->data=buffChild[0];
	e->firstChild=q;//指向第一个孩子
	EnQueue(Q,q);//第一个孩子入队
	CSTree p=q;//指向刚入队的孩子
	for(size_t i=1;i<strlen(buffChild)-1;++i)//孩子存在兄弟
{
	q=(CSTree)malloc(sizeof(CSNode));//开辟孩子结点空间
	if(!q)
		exit(OVERFLOW);
		q->data=buffChild[i];
		p->nextsbling=q;
		EnQueue(Q,q);
		p=q;//指向刚入队的孩子
//把它的兄弟均加入到队列中
}
		p->nextsbling=NULL;
}	
else{//没有孩子
	e->firstChild=NULL;
}
}
}
else{
	T=NULL;//空树
}
return OK;
}
void DestroyTree(CSTree &T){
 if(T){//如果树不为空
	if(T->firstChild)//左子树存在,即销毁以长子为结点的子树
		DestroyTree(T->firstChild);
	if(T->nextsbling)//右子数存在 即销毁以兄弟为结点的子树
		DestroyTree(T->nextsbling);
	free(T);//释放T所指向的空间
	T=NULL;
}
}
void ClearTree(CSTree &T){
	DestroyTree(T);//树T存在,将树T清为空树

}
//判断树是否是空树
Status TreeEmpty(const CSTree &T){
if(T)//树T存在 空树返回TRUE,否则返回FALSE
	return TRUE;
else
	return FALSE;
}
int TreeDepth(const CSTree &T){
//树T存在,返回树的深度
if(!T){//如果这是一颗空树,那么自然而然的这棵树的度位0
return 0;
}
if(!T->firstChild)//无长子 如果这棵树不是空树,但是这棵树没有长子,那么度为1
{
return 1;
}
CSTree p;
int depth,max=0;
for(p=T->firstChild;p;){
//对左右子树调用同样的函数,一个一个遍历 一边求得最终的深度
	depth=TreeDepth(p);
	if(depth>max)
	max=depth;
	p=p->nextsbling;
}
return max+1;//当前的下一层
}
ElemType Root(const CSTree &T){
//树T存在  返回树的根
if(T)
	return T->data;
return 0;
}
CSNode *FindNode(const CSTree &T,ElemType cur_e){
//树T存在,返回值位cur_e结点的指针
LinkQueue Q;
InitQueue(Q);//构造一个空队列
if(T){
	EnQueue(Q,T);//树根入队
	while(!QueueEmpty(Q)){
	QElemType e;
	DeQueue(Q,e);
	if(e->data==cur_e)//先找到cur_e这个结点的的指针
		return e ;
	if(e->firstChild)//当前结点有长子 则长子入队
	{
	EnQueue(Q,e->firstChild);
}
	if(e->nextsbling)//当前结点有兄弟,则该兄弟入队
{
	EnQueue(Q,e->nextsbling);
}
}
}
//把这个结点的左右兄弟放到结点中
return NULL;
}
ElemType LeftChild(CSTree &T,ElemType cur_e){
//初始条件 树存在 cur_e是T中某个结点
//操作结果 若cur_e是T的非叶子结点
CSNode *node;
node=FindNode(T,cur_e);//通过上面的函数  找到这个
if(node){
	if(node->firstChild)//有孩子 就是指它不是叶子结点
{
	return node->firstChild->data;
}
}
return NULL;
}
ElemType RightSibling(CSTree &T,ElemType cur_e){
//初始条件:树T存在 cure_e是T中的某个结点
//操作结果 若cur_e有右兄弟 则返回它的右兄弟 否则返回空
CSNode *node;
node=FindNode(T,cur_e);
if(node){
if(node->nextsbling)//有右兄弟
{
	return node->nextsbling->data;
}
}
return NULL;
}
Status LevelOrderTraverse(const CSTree &T){
//层序遍历树
LinkQueue Q;
InitQueue(Q);
if(T){
printf("%c",T->data);//访问结点
EnQueue(Q,T);//根结点排队
while(!QueueEmpty(Q)){
	QElemType e,p;
	DeQueue(Q,e);//这一步是为了删除队头的元素
	p=e->firstChild;//p指针为该结点的长子
	while(p){
	printf("%c",p->data);
	EnQueue(Q,p);
	p=p->nextsbling;//遍历它的兄弟结点
}
}
return OK;
}
return ERROR;
}
CSNode *Parent(CSTree &T,ElemType cur_e)
{
	//初始条件:树T存在,cur_e是T中某个结点
	//操作结果:若cur_e是T的非根结点,则返回它的双亲,否则返回空
	LinkQueue Q;
	InitQueue(Q);
	if(T)
	{
	//如果输入的是根结点  那么根结点没有双亲
		if(T->data == cur_e)
			return NULL;//根结点无双亲,结束,返回NULL
		EnQueue(Q,T);//根结点入队
		while(!QueueEmpty(Q))
		{
			QElemType e;
			DeQueue(Q,e);//删除队头元素 
			QElemType p = e;//提示刚出队的元素;
			if(e->firstChild)//该结点有孩子
			{//恰好这个孩子结点等于cur_e
				if(e->firstChild->data == cur_e)//或该孩子是所求的结点,则返回双亲
				{
					return p;
				}
				EnQueue(Q,e->firstChild);//将左孩子加入到队列中
				QElemType brotherPtr = e->firstChild->nextsbling;//指向孩子的兄弟结点
				while(brotherPtr) //该孩子有兄弟
				{
					if(brotherPtr->data == cur_e)//兄弟是所求的结点,则返回双亲
					{
						return p;
					}
					EnQueue(Q,brotherPtr);//兄弟结点入队
					brotherPtr = brotherPtr->nextsbling;
				}
			}
		}
	}
	return NULL;
}
int main()
{
	CSTree T;
	CreateTree(T);
 
	printf("按层序遍历该树:");
	LevelOrderTraverse(T);
	printf("\n");
 
	printf("树的根为:  %c\n",Root(T));
	printf("输入要查询的节点:\n");
	ElemType e ;
	cin>>e;
	CSNode *node = FindNode(T,e);
        if(node){
           printf("存在结点:  %c\n",node->data);
        }
		   printf("树的深度为: %d\n",TreeDepth(T));
        node = Parent(T,e);
        if(node)
          {
               printf("结点%c的双亲是:  %c\n",e,node->data);
          }
        else{
               printf("查询的节点不存在,或节点为根节点\n");
          }
             DestroyTree(T);
	return 0;
}



参考了这个代码 然后自己运行了一遍.https://blog.csdn.net/lfb637/article/details/78507509

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值