孩子兄弟表示法家谱

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

运行效果如下:

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值