树的孩子兄弟表示法及遍历操作

转载 2018年04月16日 22:00:17
/*
  @孩子兄弟表示法建立的一般树
*/
#include<iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define OK 1
#define ERROR 0
#define FALSE 0
#define TRUE 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) //插入元素e为Q的新队尾元素
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if(!p)
		exit(OVERFLOW);
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;
	Q.rear = p;
	return OK;
}

Status DeQueue(LinkQueue &Q,QElemType &e) //若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;
{
	if(Q.front == Q.rear)
	{
		return ERROR; //队空
	}
	QueuePtr p = Q.front->next;
	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];  //用于存放孩子们的缓存
	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];
		T->nextsbling = NULL;  //根结点无兄弟
		EnQueue(Q,T);  //根结点入队
		while(!QueueEmpty(Q))
		{
			QElemType e;
			DeQueue(Q,e); //结点出队
			//CSTree p = 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 = 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)//树空
	{
		return 0;
	}
	if(!T->firstChild)//无长子
	{
		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)
				return e;
			if(e->firstChild) //当前结点有长子,则该长子入队
			{
				EnQueue(Q,e->firstChild);
			}
			if(e->nextsbling)//当前结点有兄弟,则该兄弟入队
			{
				EnQueue(Q,e->nextsbling);
			}
		}
	}
	return NULL;
}

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)//该结点有孩子
			{
				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;
}

ElemType LeftChild(CSTree &T, ElemType cur_e)
{
	//初始条件:树T存在,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存在,cur_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;
			while(p)
			{
				printf("%c ",p->data);
				EnQueue(Q,p);
				p = p->nextsbling;
			}
		}
		return OK;
	}
	return ERROR;
}

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;
}


树的孩子兄弟表示法 及遍历实现

以二叉链表为例, #include #include // -------- 树的 孩子-兄弟 存储表示法 ------ struct Node{ char data; N...
  • tiantangrenjian
  • tiantangrenjian
  • 2012-01-04 22:00:41
  • 10253

孩子兄弟表示法实现树

因本人能力有限,参考了另一位大牛的代码,在此向他表示感谢! vs2008运行正确,如有误,请各位大牛指正! // CSTree.cpp : 定义控制台应用程序的入口点。 //孩子兄弟表示法实现树 ...
  • htyurencaotang
  • htyurencaotang
  • 2012-07-24 19:37:27
  • 10577

数据结构之通用树(孩子兄弟表示法)

孩子兄弟表示法模型,每个结点都有一个指向其第一个孩子的指针,每个结点都有一个指向其第一个右兄弟的指针 。...
  • m0_38001783
  • m0_38001783
  • 2017-08-01 22:30:21
  • 1839

树的孩子表示法,树的兄弟表示法,树的存储结构详解,数据结构-树的学习(2)

树的存储结构: 孩子表示法:把每个结点的孩子结点排列起来,以单链表作存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数...
  • YEDITABA
  • YEDITABA
  • 2017-06-04 20:02:35
  • 2489

构建树(孩子兄弟表示法)

构建树(孩子兄弟表示法) ...
  • caomm1982
  • caomm1982
  • 2006-05-17 09:22:00
  • 2181

java实现兄弟孩子树代码

树的表示方法很多,双亲儿子,双亲,儿子,儿子兄弟表示法。 但是用来表示树的最多的方式是儿子兄弟表示法。 第一,可以用来表示孩子节点不相同的树。 第二,不浪费存储空间。 一下贴出代码: ===...
  • andan14
  • andan14
  • 2014-06-09 21:39:23
  • 599

树的左孩子 右兄弟表示法的建立过程 (后序遍历)

#include #include using namespace std; struct Node { int data; Node * leftchild; Node * ...
  • zhou2214
  • zhou2214
  • 2013-06-30 14:24:03
  • 4417

使用C++ 和 孩子兄弟表示法实现树

VS2008可以运行通过。程序参考了许多大牛的总结,因能力有限,如有问题,请各位大牛指正。 程序采用孩子兄弟表示法存储树,实现了树的构造、遍历、深度、宽度、结点个数、叶子个数 以及 结点的层次、祖先、...
  • insistGoGo
  • insistGoGo
  • 2011-10-15 21:34:42
  • 8066

C语言数据结构——孩子兄弟表示法

任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我们设置两个指针,分别指向该节点的第一个孩子和此结点的右兄弟。 其中data是数据域,firstchild为指针...
  • sunshine_rebrith
  • sunshine_rebrith
  • 2017-06-03 11:36:00
  • 833

数据结构:树--孩子兄弟表示法

/*************************************************** 程序:树--孩子兄弟表示法 完成者:小单 完成时间:2013年5...
  • s634772208
  • s634772208
  • 2015-05-08 14:57:22
  • 4910
收藏助手
不良信息举报
您举报文章:树的孩子兄弟表示法及遍历操作
举报原因:
原因补充:

(最多只允许输入30个字)