1、malloc.h#includestdio.hstdlib.hio.hmath.hprocess.h#define TRUE 1#define FALSE 0#define OK 1#define ERROR -1#define INFEASIBLE -1typedef char DataType;#define MAXNUM 20typedef struct TriTNode/* 树的三叉链表存储结构*/ DataType dataMAXNUM; struct TriTNode *parent;/* 双亲*/ struct TriTNode *lchild;/* 左孩子*/ struct T
2、riTNode *rchild;/* 右孩子*/TriTree;typedef struct Node/* 队列的结点结构*/ TriTree *info; struct Node *next;Node;typedef struct/* 链接队列类型定义*/ struct Node *front; /* 头指针*/ struct Node *rear; /* 尾指针*/LinkQueue;DataType fnameMAXNUM,family50MAXNUM;/* 全局变量*/2.1.2 链队的基本操作LinkQueue *LQueueCreateEmpty( )/* 建立一个空队列*/ Li
3、nkQueue *plqu=(LinkQueue *)malloc(sizeof(LinkQueue); if (plqu!=NULL) plqu-front=plqu-rear=NULL; else printf(内存不足!n); return NULL; return plqu;int LQueueIsEmpty(LinkQueue *plqu)/* 判断链接表示队列是否为空队列*/ return(plqu-front=NULL);void LQueueEnQueue(LinkQueue *plqu,TriTree *x)/* 进队列*/ Node *p=(Node *)malloc(si
4、zeof(Node); if(p=NULL) printf(内存分配失败! p-info=x;next=NULL; if(plqu-front=NULL)/* 原来为空队*/front=p;rear-next=p;rear=p; int LQueueDeQueue(LinkQueue *plqu,TriTree *x)/* 出队列*/ Node *p;front=NULL)队列空! return ERROR; p=plqu-front; x=p-info;front-next; free(p); return OK;TriTree *LQueueGetFront(LinkQueue *plqu
5、)/* 在非空队列中求队头元素*/return(plqu-info);2.2建立家族关系2.2.1 建立家族关系并存入文件 基本思想:首先输入家族关系的名称,以此名称为文件名,建立文本文件接下来按层次输入结点信息,输入一个在文件中写入一行同时将输入的信息保存 到二位字符数组family中。字符数组family是全局变量,存储临时信息 . 注意,输入时每个结点信息占一行,一个结点有多个兄弟,以“”作为兄弟结束标志,结点若无孩子,直接以“”代替。依次输入各节点信息,以“#” 作为结束标志。最后使用函数CreateTriTree建立家族关系树.lixianliguoyu liguojun liguo
6、qiangliyongzhi liyongrui liyongmingliwende liwenjia TriTree *Create(DataType familynameMAXNUM)/* 建立家族关系并存入文件*/ int i=0; /* i控制family数组下标*/ DataType ch,strMAXNUM; /* ch存储输入的y或n,str存储输入的字符串*/ TriTree *t; FILE *fp; strcpy(fname,familyname); /* 以家族名为文本文件名存储*/ strcat(fname,.txt fp=fopen(fname,r /* 以读取方式打
7、开文件*/ if(fp) /* 文件已存在*/ fclose(fp);%s 的家族关系已存在!重新建立请按“Y”,直接打开请按“N”n,familyname); ch=getchar(); getchar(); /* 接收回车*/ if(ch=N|ch=n) t=Open(familyname);/* 直接打开*/ return t; if(!fp|ch=Yy) /* 重新建立,执行以下操作*/ fp=fopen(fname,w /* 以写入方式打开文件,不存在则新建*/请按层次输入结点,每个结点信息占一行n兄弟输入结束以“”为标志,结束标志为“#”n. gets(str); fputs(st
8、r,fp); fputc(n,fp); strcpy(familyi,str); /* 将成员信息存储到字符数组中*/ i+; /* family数组下标后移*/ while(str0!=#) printf(. /* 以点提示符提示继续输入*/ gets(str); fputs(str,fp); /* 写到文件中,每个信息占一行*/ fputc( strcpy(familyi,str);/* 将成员信息存储到字符数组中*/ i+; /* 关闭文件*/ t=TriTreeCreate(); /* 根据family数组信息创建三叉树*/家族关系已成功建立! return t; /* 返回树*/2.
9、2.2建立家族关系树采用指针数组作为指针,保存输入的结点地址。队列的尾指针指向当前结点。头指针指向当前结点的双亲结点。输入的结点信息已存储在字符数组family中。将信息复制到字符串数组“ch”中 ,如果ch不是“”,则建立一个新结点。若新结点是第一个结点,则它是根结点,将其入队,指针tree指向这个根节点;如果不是根结点,则将当前结点链接到双亲结点上,即当前结点的双亲指针就是队头元素,然后将当前结点入队列。接着判断flag的值,如果flag=0,表示当前结点没有左孩子,那么当前结点就是双亲的左孩子。否则,当前结点就是双亲的右孩子。用指针root指向刚刚入队的结点。继续复制数组family的下
10、个元素。如果“ch” 是。则flag=0(因为“”后面的第一个孩子为左孩子),同时判断“”是否是第一次出现,如果是第一次,则令标志star=1;如果不是第一次出现。则出队列,root指向队头元素(实际上root总是指向双亲结点)。继续复制family的下一个元素。知道遇到“#”结束。函数返回指针tree。 /* 建立家族关系树*/TriTree *TriTreeCreate() TriTree *t,*x=NULL,*tree,*root=NULL; LinkQueue *q=LQueueCreateEmpty();/* 建立一个空的队列,存储指向树的指针*/ int i=0,flag=0,s
11、tart=0; DataType strMAXNUM; /* 存放family数组中信息*/ strcpy(str,familyi); /* 复制*/ i+; while(str0!) /* 没遇到结束标志继续循环*/) /* 没遇到兄弟输入结束标志继续*/ if(root=NULL) /* 空树*/ root=(TriTree *)malloc(sizeof(TriTree);/* 申请空间*/ strcpy(root-data,str); root-parent=NULL;lchild=NULL;rchild=NULL; LQueueEnQueue(q,root); /* 将root存入队
12、列*/ tree=root; else /* 不为空树*/ t=(TriTree *)malloc(sizeof(TriTree); /* 申请空间*/ strcpy(t- t-parent=LQueueGetFront(q); /* 当前结点的双亲为队头元素*/ LQueueEnQueue(q,t); /* 入队*/ if(!flag) /* flag为,当前结点没有左孩子*/ root-lchild=t; else /* flag为,当前结点已有左孩子*/rchild=t; root=t; /* root指向新的结点t */ flag=1; /* 标记当前结点已有左孩子*/ strcpy(
13、str,familyi); if(start!=0) /* 标记不是第一次出现“”*/ LQueueDeQueue(q,x); /* 出队*/ if(q-front! root=LQueueGetFront(q);/* root为队头元素*/ start=1; /* 标记已出现过“”*/ flag=0; /* “”后面的结点一定为左孩子*/ strcpy(str,familyi); return tree;2.3打开一个家族关系 首先输入家族关系名,以家族名为文件名打开文件,如果家族关系不存在,返回空;如果存在,文件打开,读取文件。将文件的每行信息依次存储在数组family【】中。/* 打开一
14、个家族关系*/TriTree *Open(DataType familynameMAXNUM) int i=0,j=0; DataType ch; if(fp=NULL) /* 文件不存在*/%s 的家族关系不存在! ch=fgetc(fp); /* 按字符读取文件*/ while(ch!=EOF) /* 读到文件尾结束*/ if(ch!) /* ch不为一个结点信息的结尾*/ familyij=ch; /* 将文件信息存储到family数组中*/ j+; else familyij=0; /* 字符串结束标志*/ i+; /* family数组行下标后移*/ j=0; /* family数组
15、列下标归零*/ ch=fgetc(fp); /* 继续读取文件信息*/ t=TriTreeCreate(family); /* 调用函数建立三叉链表*/家族关系已成功打开!2.4在家族关系中查找一个成员是否存在用递归算法实现。如果树空,返回NULL。如果根节点就是要查找的成员,返回根节点;否则,递归查找它的左右子树。/* 查找一个成员是否存在*/TriTree *Search(TriTree *t,DataType str) TriTree *temp; if(t=NULL) /* 如果树空则返回NULL */ else if(strcmp(t-data,str)=0) /* 如果找到返回该成
16、员指针*/ else /* 如果没找到遍历左右子树进行查找*/ temp=Search(t-lchild,str); /* 递归查找*/ if(temp) /* 结点不空则查找*/ return(Search(t-lchild,str); elserchild,str);2.5 向家族中添加一个新成员添加的新成员要根据其双亲确定其在家族中的位置。首先判断该双亲是否在此家族关系中,若存在则查找其双亲,将新结点插入其双亲的最后一个孩子之后;若没有孩子,则直接作为左孩子插入。以写入的方式打开文件,如果成功打开,则更新family数组中的信息,并查找新成员的双亲所在位置和其对应的“”个数,如果“”个数
17、小于双亲位置,则添加“”实质相等,新成员不插入到最后“”之前。最后将family数组中信息写入文件保存,关闭文件。/* 添加一个新成员*/void Append(TriTree *t) int i=0,j,parpos=1,curpos,num,end=0,count=-1; DataType chiMAXNUM,parMAXNUM;/* 存储输入的孩子和其双亲结点*/ TriTree *tpar,*temp;请输入要添加的成员和其父亲,以回车分隔!n. gets(chi); gets(par); tpar=Search(t,par); /* 查找双亲结点是否存在*/tpar)%s 该成员不存
18、在! else /* 存在则添加其孩子*/ temp=(TriTree *)malloc(sizeof(TriTree); temp-parent=tpar; strcpy(temp-data,chi); /* 新结点左右孩子置空*/ if(tpar-lchild) /* 成员存在左孩子*/ tpar=tpar-lchild; /* 遍历当前成员左孩子的右子树*/ while(tpar-rchild) /* 当前结点右孩子存在*/ tpar=tpar-rchild; /* 继续遍历右孩子*/ tpar-rchild=temp; /* 将新结点添加到所有孩子之后*/ else /* 没有孩子则直
19、接添加*/lchild=temp; /* 以写入方式打开文件*/ if(fp) while(strcmp(par,familyi)!=0&familyi0! if(familyi0!) /* 查找双亲在数组中位置*/ parpos+; /* parpos计数*/ i=0; /* family数组行下标归*/ while(familyi0! if(familyi0=) /* 查找“”的个数,第一个不计*/ count+; /* count累加个数*/ if(count=parpos) /* 说明此“”与其前一个“”之前为par的孩子*/ curpos=i; /* curpos计当前位置*/ if
20、(countparpos) /* “”数小于parpos数*/ num=parpos-count; /* 添加“”个数为num */ for(j=i;j=curpos;j-) /* 当前位置到数组最后的全部信息后移一行*/ strcpy(familyj+1,familyj); strcpy(familycurpos,chi); /* 将新结点存储到“”的前一行*/ if(end=1) /* 若end为,则数组末尾下标后移num位*/ i=i+num; for(j=0;=i+1;j+) /* 将数组所有信息写入文件*/ fputs(familyj,fp); fputc( /* 一个信息存一行*/
21、 fclose(fp);添加新成员成功!添加新成员失败!2.6 家族成员关系的相关查询2.6.1 查找一个家族的鼻祖判断输入的姓名是否在该家族中存在,如果存在,则返回该家族的根节点信息。/* 查找一个家族的祖先*/void Ancesstor(TriTree *t) /* 返回树的根结点信息*/该家族的祖先为%sn,t-data);2.6.2 查找一个成员的所有祖先路径查找一个成员的所有祖先路径,需要从它的双亲一直向上查找到根结点。对与结点t,先判断它是否是根结点(根节点的双亲是NULL),如果是根结点,直接输出它本身;如果不是,查找它的双亲指针指向的结点,将双亲信息输出。继续查找,直到找到根结点。/* 查找一个成员的所有祖先*/void AncesstorPath(TriTree *t) if(t-parent=NULL) /* 若该成员为祖先,则直接输出*/%s 无祖先! else /* 否则继续查找祖先*/%s 所有祖先路径:%sdata,t-
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1