家谱图-二叉树

// FamilyMap_BTree.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"


#define fileName "familyMap.dat"


//定义节点最大个数
#define MaxNode 20


//节点数据类型
typedef char ElemType;


//二叉树节点类型(节点类型)
typedef struct btnode{
	ElemType data;				//家谱图中人员编号
	btnode * lchild;			//成员的配偶指针
	btnode * rchild;			//成员的子女及子女的兄弟指针
}BtNode;


typedef BtNode *BTree;			//定义BtNode *类型为BTree


//二叉树栈
typedef struct{
	BtNode * stack[MaxNode];	//栈区
	int top;					//栈顶指针
}BTreeStack;

typedef struct{
	BtNode * pNode;
	int height;
}BtNodewithHeight;

//二叉树队列
typedef struct{
	BtNodewithHeight queue[MaxNode];	//队列数据区
	int front;							//队列头指针
	int rear;							//队列尾指针
}BTreeQueue;




//从文件中读取系谱图(以括号表示法储存)
bool ReadfromFile(char *&s){
	FILE *fp = NULL;
	fopen_s(&fp,fileName,"rb");
	int size=0;
	if (fp == NULL)
		return false;
	fseek(fp, 0L, SEEK_END);
	size = ftell(fp);


	s = (char *)malloc(sizeof(size+1));		//在这里分配了内存空间,在外面使用,最后释放


	*(s + size) = '\0';
	fread(s,size,1,fp);
	fclose(fp);
	return true;
}


//从括号表述法创建二叉树(使用栈进行实现)
bool CreateBTreefromBracketNotation(BTree &r, char * btStr){
	BTreeStack bts;
	bts.top = -1;						//初始化栈


	int i = 0, k = 0;					//i用于保存串的偏移量,k用于标记处理栈顶的左指针还是右指针
	char ch;						//ch用于保存括号表示法串的字符
	BtNode * temp = NULL;				//temp用于保存待处理的节点
	while ((ch = *(btStr + i)) != '\0')	//循环扫描串,并将字符存到ch
	{
		switch (ch){
		case '(':					//将子树根节点进栈,准备处理根节点左指针
			bts.stack[++bts.top] = temp;
			k = 1;
			break;
		case ')':					//子树根节点出栈
			bts.top--;
			break;
		case ',':					//准备处理子树根节点右指针
			k = 2;
			break;
		default:					//处理数据节点
			temp = (BtNode *)malloc(sizeof(BtNode));
			temp->data = ch;
			temp->lchild = temp->rchild = NULL;
			switch (k){
			case 0:
				r = temp;
				break;
			case 1:
				bts.stack[bts.top]->lchild = temp;
				break;
			case 2:
				bts.stack[bts.top]->rchild = temp;
				break;
			}
			break;
		}
		i++;
	}
	return true;
}


//寻找某人的所有孩子函数(递归实现)
//@BTree r表示子树的根节点
//@char e表示要寻找的节点编号
//@bool src储存得到该节点的路径(左还是右) true代表左 false代表右 第一次调用时(即根节点时)src为true
bool FindAllSon(BTree r, char e ,bool src){
	if (r == NULL)											//递归出口
		return false;							
	if (r->data == e){										//找到该人
		BtNode * temp=NULL;
		if(src==true){										//表示该节点为家族外来人,孩子直接挂在他的右子树上
			temp=r->rchild;
			if(temp==NULL)
				printf("%c没有孩子\n",e);
			else{
				printf("%c的孩子有:\t",e);
				while(temp!=NULL){
					printf("%c\t",temp->data);
					temp=temp->rchild;
					}
				printf("\n");
				}
		}else{												//表示该节点为家族内部人,孩子挂在他的配偶身上(即左子树的右子树上)
			if(r->lchild==NULL)
				printf("哥们,%c配偶都没有,哪来的孩子啊...\n",e);
			else{
				temp=r->lchild->rchild;
				if(temp==NULL)
					printf("%c还没有孩子\n",e);
				else{
					printf("%c的孩子有:\t",e);
					while(temp!=NULL){
					printf("%c\t",temp->data);
					temp=temp->rchild;
					}
				}
			}
		}
		return true;
	}
	else{
		if (!FindAllSon(r->lchild, e, true))						//寻找左子树
			return FindAllSon(r->rchild,e,false);					//左子树未找到时寻找右子树
		else
			return true;
	}
}


//寻找祖先元素(递归实现)
//@BTree r代表根节点
//@char e代表待寻找的元素编号
//@BTreeStack *bt代表记录节点路径信息的栈
bool FindAllAncestor(BTree r, char e, BTreeStack * bt){
	if (r == NULL)
		return false;												//递归出口,未找到该节点
	int temp = ++bt->top;											//temp储存根节点进栈后的栈顶指针
	bt->stack[temp] = r;											//将根节点进栈
	if (r->data == e){												//递归出口,找到该节点,根据路径判断该节点的祖先元素
		if(bt->top==0)
			printf("%c为该家谱图中的根节点,祖先元素无法找出\n",e);
		else{
			if(bt->stack[bt->top-1]->lchild==bt->stack[bt->top])
				printf("%c是外来人口,根据该家谱图如法得出其祖先元素\n",e);
			else{
				int k=0;											//k记录输出祖先元素的对数
				printf("%c的祖先元素有:\t",e);
				for(int i=0;i<bt->top;i+=2){
					if(bt->stack[i]->lchild==bt->stack[i+1]){
						k++;
						printf("(%c,%c)\t",bt->stack[i]->data,bt->stack[i+1]->data);
					}
				}
				if(k==0)
					printf("null\n");
				else
					printf("\n");
			}
		}
		return true;
	}
	else{
		if (!FindAllAncestor(r->lchild, e, bt)){						//在左子树中找改节点
			bt->top = temp;												//左子树中未找到则退栈
			return FindAllAncestor(r->rchild, e, bt);					//在右子树中寻找该节点
		}
		else
			return true;
	}
}

//以括号表示输出二叉树(递归实现)
void DispbyBracketNotation(BTree r)
{
	if(r!=NULL){
		printf("%c",r->data);
		if(r->lchild!=NULL || r->rchild!=NULL){
			printf("(");
			DispbyBracketNotation(r->lchild);
			if(r->rchild!=NULL)
				printf(",");
			DispbyBracketNotation(r->rchild);
			printf(")");
		}
	}
}

//求二叉树的高度
int HeightofBTree(BTree r,int h)
{
	int lh=h,rh=h;
	if(r->lchild!=NULL)
		lh=HeightofBTree(r->lchild,h+1);
	if(r->rchild!=NULL)
		rh=HeightofBTree(r->rchild,h+1);
	return lh>=rh?lh:rh;
}

//输出星号函数
void printStar(int n)
{
	for(int i=0;i<n;i++)
		printf(" * ");
	printf("\n");
}

//以凹入表示法输出二叉树
void DispbyIndentation(BTree r,BTreeQueue * q)
{
	int h=HeightofBTree(r,1);		//获得树的总高度

	BtNodewithHeight *p=NULL;
	
	q->queue[++q->rear].pNode=r;	//根节点进队
	q->queue[q->rear].height=h;
	
	while(q->front!=q->rear){
		q->front=(q->front+1)%MaxNode;
		p=&(q->queue[q->front]);
		if(p->pNode!=NULL){
			printf("%c:\t",p->pNode->data);
			printStar(p->height);
			q->queue[++q->rear].pNode=p->pNode->lchild;
			q->queue[q->rear].height=p->height-1;
			q->queue[++q->rear].pNode=p->pNode->rchild;
			q->queue[q->rear].height=p->height-1;
		}
		
	}

}

bool FamilyMemberAdd(){
	return false;
}




int _tmain(int argc, _TCHAR* argv[])
{
	char * familyMapStr = "A(B(,D(G(,I(,J)),H)),C(E,F))";	//树的括号表示法字符串

	BTree bt = NULL;										//树的根节点指针

	BTreeStack bs;											//创建二叉树的栈
	bs.top = -1;											//初始化二叉树栈

	BTreeQueue bq;											//创建二叉树队列
	bq.front=bq.rear=-1;										//初始化二叉树队列
	
	char a='F',b='B';

	CreateBTreefromBracketNotation(bt, familyMapStr);		//创建家谱二叉树


	FindAllSon(bt,a,true);									//寻找a变量元素的孩子
	printf("\n");

	if (!FindAllAncestor(bt,b, &bs))						//寻找b变量元素的祖先
		printf("%c的祖先在家谱图中没有得到体现",b);
	printf("\n");

	
	printf("二叉树的括号表示法如下:\n");
	DispbyBracketNotation(bt);
	printf("\n\n");

	printf("二叉树的凹入表示法如下:\n");
	DispbyIndentation(bt,&bq);
	printf("\n");
	//printf("%d\n",HeightofBTree(bt,1));

	system("PAUSE");
	return 0;
}


/***************************
*说明:
*本例要求给出家谱结构图和家谱性别图
*与本家族节点的配偶必须位于左节点,两人结婚所生小孩须挂于外来人的右子树
*新增节点必须给出性别
*根节点如有配偶则配偶必须出现在家谱图中
*祖先元素输出会包括男与女双方,如果显示祖先元素为空,也表示该图中不存在他的祖先元素
***************************/

二叉树实现家谱图---未完成
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值