#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