<数据结构>孩子兄弟表示法家谱
2013-06-04 21:22
405 查看
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> const int MAXSIZE = 5000; const int NAME_LENGTH = 500; using namespace std; struct TreeNode { char name[NAME_LENGTH];//定义一个字符数组,存放姓名 int level;//辈分 struct TreeNode *child;//第一个孩子 struct TreeNode *brother;//兄弟 }; //加入队列,把每个人的信息存进去 struct QueueNode { char name[NAME_LENGTH]; int level;//辈分 struct QueueNode *next; }; QueueNode *q = NULL, *qt, *newq;//定义一个队列的全局变量 //载入文件 void Load(char str[]) { FILE *fp; if ((fp = fopen("jiapu_by_pt.txt", "r")) == NULL) { cout << "Can't open file!\n"; exit (0); } fgets(str, MAXSIZE, fp);//从文件中读取一行字符串到str中 fclose(fp);//关闭文件 } //创建树,根据嵌套括号表示法的字符串*str生成树 TreeNode *CreateTree(TreeNode *b, char *str) { TreeNode *stack[MAXSIZE];//声明一个栈指针 TreeNode *p;//临时指针 int iName, stName; //记录名字的长度,记录名字起始的下标 int k;//判断是孩子还是兄弟的变量 int j = 0;//str的下标 int i, m; int top = -1;//栈顶变量 int tLevel = 1;//存放零时辈分 char ch;//存放字符的零时变量 char tName[NAME_LENGTH];//用来取出名字用 b = NULL; ch = str[j]; //循环遍历整个字符串 while (ch != '\0') { switch (ch) { case '(': top++; stack[top] = p; k=1; tLevel++; break; // 为孩子,辈分加1 case ')': top--; break;//辈分减1 case ',': k=2 ; tLevel--; break;//为兄弟,辈分不变 default: p = new TreeNode;//动态为其分配内存空间,把名字起始下标给stName变量 stName = j; iName = 0;//将名字的长度置位0 //循环计算名字的长度 while (ch!='\0' && ch!='(' && ch!=',' && ch!=')') { iName++; j++; ch = str[j]; } j--;//由于最后j要自加,所以就跳过了以上循环不满足的四种情况,此时要让k自减 m = 0; //取出名字的字符串 for (i=stName; i<stName+iName; i++) { tName[m++] = str[i]; } tName[m] = '\0'; //printf("%s\n", tName); strcpy(p->name, tName);//赋值姓名 p->level = tLevel;//赋值辈分 p->child = p->brother = NULL;//让p的孩子节点,兄弟节点为空 if (b == NULL) b = p;//根节点 else { switch (k) { case 1: stack[top]->child = p; break;//k为1代表了孩子节点 case 2: stack[top]->brother = p; break;//k为2代表了兄弟节点 } } } j++; ch = str[j]; } return b; } //输出指定家庭的所有成员 TreeNode *Find(TreeNode *b, char inName[]) { TreeNode *p;//定义一个接受查找的指针变量 if (b == NULL)//树空 return NULL; else if (!strcmp(b->name, inName))//查找的为根节点 return b; else { p = Find(b->child, inName);//递归查找孩子 if (p!=NULL)//如果查找到了 return p; else return Find(b->brother, inName);//递归查找兄弟 } } //输出指定成员的辈数 int GetLevel(TreeNode *b, char inName[]) { TreeNode *p; p = Find(b, inName);//调用查找姓名为inName的孩子 if (p == NULL) return 0; else return p->level;//直接返回它的辈份变量即可 } //把家庭的存储结构写入文件中 char s[2]="(",p[2]=",",t[2]=")"; void Save(TreeNode *b,FILE *fp) { //如果b不为空树 if(b!=NULL) { fputs(b->name, fp);//将名字写入文件 //如果孩子或者兄弟不为空 if(b->child!=NULL || b->brother!=NULL) { //printf("("); fputs(s,fp);//将左括号写入文件 Save(b->child, fp);//递归孩子节点写入文件,一直到空 if (b->brother!=NULL) { // printf(","); fputs(p,fp);//将逗号写入文件 } Save(b->brother,fp);//递归兄弟节点写入文件,一直到空 //printf(")"); fputs(t,fp);//将又括号写入文件 } } } //在家庭中添加新成员 void Add(TreeNode *b,char par[],char chi[]) { FILE *fp;//定义一个文件指针 TreeNode *p,*q;//树节点p,q p = Find(b, par);//找到双亲节点的指针 if (p==NULL) { cout << "\n你要添加孩子的双亲不存在,添加失败!!!!\n\n"; return ; } q = new TreeNode;//为q分配内存空间 strcpy(q->name, chi);//复制孩子的姓名到新节点的姓名 q->level = p->level+1;//孩子的辈份在双亲的基础上加1 q->child=q->brother=NULL; if(p->child == NULL)//如果孩子的节点为空 { p->child = q;//直接把q当成他的孩子 } else { p=p->child;//找到他的孩子 while(p->brother!=NULL)//循环到孩子的最后一个兄弟 { p=p->brother ; } p->brother=q;//把q当成他的兄弟 } cout << "向文件中写入新家谱......\n"; if((fp = fopen("jiapu_by_pt.txt","w"))==NULL) { cout << "\n can't open the file.\n"; exit(0); } else Save(b,fp);//保存问年 fclose (fp);//关闭文件 } //初始化队列 void QueueInit(TreeNode *b) { if (b!=NULL) { if (q==NULL) { q = new QueueNode;//为第一个队列节点分配内存 strcpy(q->name, b->name);//将名字复制到第一个队列节点 q->level = b->level;//复制辈份 q->next = NULL; qt = q;//让qt临时指针变量指向第一个队列节点 } else { newq = new QueueNode;//为非第一个队列节点分配内存 newq->next = NULL; strcpy(newq->name, b->name);//将名字复制到非第一个队列节点 newq->level = b->level;//复制辈份 qt->next = newq;//将其连接起来 qt = newq;//让qt临时指针变量指向新创建的队列节点(即最后一个队列节点) } QueueInit(b->child); QueueInit(b->brother); } } //使用嵌套括号表示法输出 void PrintTree(TreeNode *b) { if (b!=NULL)//如果树不为空 { cout << b->name;//打印根节点的姓名 if (b->child!=NULL || b->brother!=NULL)//孩子或者兄弟不为空 { cout << "("; PrintTree(b->child);//递归打印孩子 if (b->brother!=NULL)//如果兄弟不为空 cout << ","; PrintTree(b->brother);//递归打印兄弟 cout << ")"; } } } //以凹入表表示法输出 void DispTree(TreeNode *b) { TreeNode *stack[MAXSIZE];//定义一个栈指针 TreeNode *p; //level[m][0]代表的是打印stack[m]这个节点信息,打印多少个空格 //level[m][1]代表的是打印stack[m]这个节点信息,标示是孩子还是兄弟 //0表示孩子,1表示兄弟,2表示根 int level[MAXSIZE][2], top, n, i, width = 4; char type;//用来显示的时候标识是孩子还是兄弟 if (b!=NULL)//树不为空时 { top = 1; stack[top] = b; // 根节点入栈 level[top][0] = width;//让根节点前面打印width个空格 level[top][1] = 2;//2表示根 //栈不为空 while (top > 0) { p = stack[top]; // 退栈并凹入显示该节点值 n = level[top][0];//把打印多少个空格的值赋值给n //分支语句判断是孩子节点还是根节点 switch (level[top][1]) { case 0: type = 'h'; break;//孩子节点 case 1: type = 'x'; break;//兄弟节点 case 2: type = 'g'; break;//根节点 } //循环打印n歌空格 for (i=1; i<=n; i++) cout << " "; cout << p->name << "(" << type << ")\n";//输出名字和标示符 top--;//出栈 //如果兄弟节点不为空 if (p->brother!=NULL) { //将兄弟节点入栈 top++; stack[top] = p->brother; level[top][0] = n;//在n的基础上空格数+width个 level[top][1] = 1;//兄弟标示为1 } //如果孩子节点不为空 if (p->child!=NULL) { //将孩子节点入栈 top++; stack[top] = p->child; level[top][0] = n+width;//在n的基础上空格数+width个 level[top][1] = 0;//孩子标示为0 } } } } //输出选择 void PrintSel(TreeNode *b) { int sel; cout << "~~~~~~~~~~~~~~~~~~~~~~~\n"; cout << "1.凹入表表示法输出 \n"; cout << "2.嵌套括号表示法输出 \n"; cout << "~~~~~~~~~~~~~~~~~~~~~~~\n"; while (1) { cout << "请输入你的选择:"; cin >> sel;//输入打印选择 if (sel == 1) { cout << "凹入表表示法输出如下:\n\n"; DispTree(b); break; } else if (sel == 2) { cout << "嵌套括号表示法输出如下:\n\n"; PrintTree(b); break; } else { cout << "你输入的选项不存在,请从新输入:"; } } } //输出指定辈的成员 void PrintLevel(int n) { QueueNode *p; int flag = 0; //循环遍历队列 cout << "\n"; for (p=q; p!=NULL; p = p->next) if (p->level == n)//如果辈份对应 { cout << "-" << p->name << "-";//打印相应的名字 flag = 1; } if (flag == 0)//如果标示为0,即不存在这个人 { cout << "\n该家谱中不存在辈份为" << n << "的人!!!\n\n"; return ; } } int Menu() { int select; cout << "|**************欢迎进入蒲氏家谱系统**********|\n"; cout << "| 1.在家谱中添加新成员并追加到文件中 |\n"; cout << "| 2.输出指定家庭的所有成员 |\n"; cout << "| 3.打印出指定成员在家族中的辈份 |\n"; cout << "| 4.输出指定辈的所有成员 |\n"; cout << "| 5.输出整个家谱 |\n"; cout << "| 6.退出 |\n"; cout << "|********************************************|\n"; cout << "|参考文献:1.<<程序设计题典>>--清华大学出版社 |\n"; cout << "| 2.<<c程序设计>>--清华大学出版社 |\n"; cout << "|********************************************|\n"; cout << "|ps:计划生育说:少生优生 幸福一生 !!!!!!!!!|\n"; cout << "|********************************************|\n"; cout << "|作者:蒲通 *()* 日期:13.5.28|\n"; cout << "|********************************************|\n"; do { cout << "请输入你的选项:"; cin >> select; }while (select<1 || select>6); return select; } int main() { //char str[] = "蒲爷爷(蒲爸爸(蒲通(蒲通的大儿子,蒲通的二儿子),蒲弟弟),蒲姑父(蒲表哥))"; char str[MAXSIZE]; char par[NAME_LENGTH], chi[NAME_LENGTH]; Load(str);//载入文件,将字符串读入str数组中 TreeNode *b, *p; b = CreateTree(b, str); int sel, level; char inName[NAME_LENGTH]; while (1) { sel = Menu(); switch (sel) { case 1: getchar();//吃掉选择菜单回车符 cout << "输入你要添加孩子的双亲姓名:"; gets(par);//输入添加孩子的双亲姓名 cout << "输入你要添加孩子的姓名:"; gets(chi);//输入添加孩子的姓名 Add(b, par, chi); //b = CreateTree(b, str); break; case 2: cout << "请输入你要查找指定成员家庭的姓名:"; getchar();//吃掉选择菜单回车符 gets(inName); p = Find(b, inName); if (p == NULL) { cout << "\n你要查找指定成员家庭的姓名不存在!!!\n\n"; break; } cout << "\n" << inName << "(c)\n"; DispTree(p->child);//直接以凹入表表示法显示 cout << "\n\n"; break; case 3: cout << "请输入你要查找指定成员辈份的姓名:"; getchar();//吃掉选择菜单回车符 gets(inName);//输入查找指定成员辈份的姓名 level = GetLevel(b, inName); if (level == 0) { cout << "\n你要查找指定成员辈份的姓名不存在,查找辈份失败!!!\n\n"; break; } cout << "\n" << inName << "是第" << level << "辈\n\n"; break; case 4: q = NULL; QueueInit(b); cout << "请输入要显示的辈份:"; cin >> level; PrintLevel(level); cout << "\n\n"; break; case 5: PrintSel(b); cout << "\n\n"; break; case 6: cout << "\n谢谢使用^()^\n\n"; exit(0); break; } } return 0; }
运行效果如下:
相关文章推荐
- 数据结构:树--孩子兄弟表示法
- 树的孩子表示法,树的兄弟表示法,树的存储结构详解,数据结构-树的学习(2)
- C语言数据结构——孩子兄弟表示法
- 数据结构之通用树(孩子兄弟表示法)
- 6-7-树的二叉链表(孩子-兄弟)存储表示-树和二叉树-第6章-《数据结构》课本源码-严蔚敏吴伟民版
- <<农民的孩子>> 第二回 父母的小帮手
- <数据结构>二叉树的实现
- 树的孩子兄弟表示法-因特网域名的查找
- <数据结构>线性表.顺序存储结构
- <a href="javascript:;" id="button_qg_close"></a>表示什么意思?
- 树的孩子兄弟表示法
- 数据结构之通用树(使用链表实现树的存储结构,双亲孩子表示法)
- 树的孩子兄弟表示法
- 任意有根树的左孩子右兄弟表示法存储
- <!doctype html>表示浏览器可以用H5解析页面
- 左孩子右兄弟表示多叉树查找返回下一个节点
- 将邻接表表示的图转换为孩子兄弟法表示的二叉树
- java <T> T <E> List<E> <K,V> Map<K,V> 表示的意思
- <>这个符号表示泛型的意思
- UVa11732 "strcmp()" Anyone?(Trie树+孩子兄弟表示法)