大数据结构课程设计家族关系查询系统要点Word格式文档下载.docx
《大数据结构课程设计家族关系查询系统要点Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《大数据结构课程设计家族关系查询系统要点Word格式文档下载.docx(30页珍藏版)》请在冰豆网上搜索。
malloc.h>
#include<
limits.h>
stdio.h>
stdlib.h>
io.h>
math.h>
process.h>
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR-1
#defineINFEASIBLE-1
typedefcharDataType;
#defineMAXNUM20
typedefstructTriTNode/*树的三叉链表存储结构*/
{
DataTypedata[MAXNUM];
structTriTNode*parent;
/*双亲*/
structTriTNode*lchild;
/*左孩子*/
structTriTNode*rchild;
/*右孩子*/
}TriTree;
typedefstructNode/*队列的结点结构*/
{
TriTree*info;
structNode*next;
}Node;
typedefstruct/*链接队列类型定义*/
{
structNode*front;
/*头指针*/
structNode*rear;
/*尾指针*/
}LinkQueue;
DataTypefname[MAXNUM],family[50][MAXNUM];
/*全局变量*/
2.1.2链队的基本操作
LinkQueue*LQueueCreateEmpty()/*建立一个空队列*/
LinkQueue*plqu=(LinkQueue*)malloc(sizeof(LinkQueue));
if(plqu!
=NULL)
plqu->
front=plqu->
rear=NULL;
else
{
printf("
内存不足!
\n"
);
returnNULL;
}
returnplqu;
}
intLQueueIsEmpty(LinkQueue*plqu)/*判断链接表示队列是否为空队列*/
{
return(plqu->
front==NULL);
voidLQueueEnQueue(LinkQueue*plqu,TriTree*x)/*进队列*/
Node*p=(Node*)malloc(sizeof(Node));
if(p==NULL)
printf("
内存分配失败!
{
p->
info=x;
next=NULL;
if(plqu->
front==NULL)/*原来为空队*/
front=p;
rear->
next=p;
rear=p;
}
intLQueueDeQueue(LinkQueue*plqu,TriTree*x)/*出队列*/
Node*p;
front==NULL)
队列空!
returnERROR;
p=plqu->
front;
x=p->
info;
front->
next;
free(p);
returnOK;
TriTree*LQueueGetFront(LinkQueue*plqu)/*在非空队列中求队头元素*/
return(plqu->
info);
2.2建立家族关系
2.2.1建立家族关系并存入文件
基本思想:
首先输入家族关系的名称,以此名称为文件名,建立文本文件接下来按层次输入结点信息,输入一个在文件中写入一行同时将输入的信息保存
到二位字符数组family中。
字符数组family是全局变量,存储临时信息.注意,输入时每个结点信息占一行,一个结点有多个兄弟,以“@”作为兄弟结束标志,结点若无孩子,直接以“@”代替。
依次输入各节点信息,以“#”作为结束标志。
最后使用函数CreateTriTree建立家族关系树.
lixian
liguoyuliguojunliguoqiang
liyongzhiliyongruiliyongming
liwendeliwenjia
TriTree*Create(DataTypefamilyname[MAXNUM])/*建立家族关系并存入文件*/
inti=0;
/*i控制family数组下标*/
DataTypech,str[MAXNUM];
/*ch存储输入的y或n,str存储输入的字符串*/
TriTree*t;
FILE*fp;
strcpy(fname,familyname);
/*以家族名为文本文件名存储*/
strcat(fname,"
.txt"
fp=fopen(fname,"
r"
/*以读取方式打开文件*/
if(fp)/*文件已存在*/
fclose(fp);
%s的家族关系已存在!
重新建立请按“Y”,直接打开请按“N”\n"
familyname);
ch=getchar();
getchar();
/*接收回车*/
if(ch=='
N'
||ch=='
n'
)
{
t=Open(familyname);
/*直接打开*/
returnt;
}
if(!
fp||ch=='
Y'
y'
)/*重新建立,执行以下操作*/
fp=fopen(fname,"
w"
/*以写入方式打开文件,不存在则新建*/
请按层次输入结点,每个结点信息占一行\n"
兄弟输入结束以“@”为标志,结束标志为“#”\n."
gets(str);
fputs(str,fp);
fputc('
\n'
fp);
strcpy(family[i],str);
/*将成员信息存储到字符数组中*/
i++;
/*family数组下标后移*/
while(str[0]!
='
#'
)
printf("
."
/*以点提示符提示继续输入*/
gets(str);
fputs(str,fp);
/*写到文件中,每个信息占一行*/
fputc('
strcpy(family[i],str);
/*将成员信息存储到字符数组中*/
i++;
/*关闭文件*/
t=TriTreeCreate();
/*根据family数组信息创建三叉树*/
家族关系已成功建立!
returnt;
/*返回树*/
2.2.2建立家族关系树
采用指针数组作为指针,保存输入的结点地址。
队列的尾指针指向当前结点。
头指针指向当前结点的双亲结点。
输入的结点信息已存储在字符数组family中。
将信息复制到字符串数组“ch”中,如果"
ch"
不是“@”,则建立一个新结点。
若新结点是第一个结点,则它是根结点,将其入队,指针tree指向这个根节点;
如果不是根结点,则将当前结点链接到双亲结点上,即当前结点的双亲指针就是队头元素,然后将当前结点入队列。
接着判断flag的值,如果flag=0,表示当前结点没有左孩子,那么当前结点就是双亲的左孩子。
否则,当前结点就是双亲的右孩子。
用指针root指向刚刚入队的结点。
继续复制数组family的下个元素。
如果“ch”是@。
则flag=0(因为“@”后面的第一个孩子为左孩子),同时判断“@”是否是第一次出现,如果是第一次,则令标志star=1;
如果不是第一次出现。
则出队列,root指向队头元素(实际上root总是指向双亲结点)。
继续复制family的下一个元素。
知道遇到“#”结束。
函数返回指针tree。
/*建立家族关系树*/
TriTree*TriTreeCreate()
TriTree*t,*x=NULL,*tree,*root=NULL;
LinkQueue*q=LQueueCreateEmpty();
/*建立一个空的队列,存储指向树的指针*/
inti=0,flag=0,start=0;
DataTypestr[MAXNUM];
/*存放family数组中信息*/
strcpy(str,family[i]);
/*复制*/
i++;
while(str[0]!
)/*没遇到结束标志继续循环*/
@'
)/*没遇到兄弟输入结束标志继续*/
if(root==NULL)/*空树*/
{
root=(TriTree*)malloc(sizeof(TriTree));
/*申请空间*/
strcpy(root->
data,str);
root->
parent=NULL;
lchild=NULL;
rchild=NULL;
LQueueEnQueue(q,root);
/*将root存入队列*/
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(str,family[i]);
if(start!
=0)/*标记不是第一次出现“@”*/
{
LQueueDeQueue(q,x);
/*出队*/
if(q->
front!
root=LQueueGetFront(q);
/*root为队头元素*/
start=1;
/*标记已出现过“@”*/
flag=0;
/*“@”后面的结点一定为左孩子*/
strcpy(str,family[i]);
returntree;
2.3打开一个家族关系
首先输入家族关系名,以家族名为文件名打开文件,如果家族关系不存在,返回空;
如果存在,文件打开,读取文件。
将文件的每行信息依次存储在数组family【】中。
/*打开一个家族关系*/
TriTree*Open(DataTypefamilyname[MAXNUM])
inti=0,j=0;
DataTypech;
if(fp==NULL)/*文件不存在*/
%s的家族关系不存在!
ch=fgetc(fp);
/*按字符读取文件*/
while(ch!
=EOF)/*读到文件尾结束*/
if(ch!
)/*ch不为一个结点信息的结尾*/
family[i][j]=ch;
/*将文件信息存储到family数组中*/
j++;
else
family[i][j]='
\0'
;
/*字符串结束标志*/
i++;
/*family数组行下标后移*/
j=0;
/*family数组列下标归零*/
ch=fgetc(fp);
/*继续读取文件信息*/
}
t=TriTreeCreate(family);
/*调用函数建立三叉链表*/
家族关系已成功打开!
2.4在家族关系中查找一个成员是否存在
用递归算法实现。
如果树空,返回NULL。
如果根节点就是要查找的成员,返回根节点;
否则,递归查找它的左右子树。
/*查找一个成员是否存在*/
TriTree*Search(TriTree*t,DataTypestr[])
TriTree*temp;
if(t==NULL)/*如果树空则返回NULL*/
elseif(strcmp(t->
data,str)==0)/*如果找到返回该成员指针*/
else/*如果没找到遍历左右子树进行查找*/
temp=Search(t->
lchild,str);
/*递归查找*/
if(temp)/*结点不空则查找*/
return(Search(t->
lchild,str));
else
rchild,str));
2.5向家族中添加一个新成员
添加的新成员要根据其双亲确定其在家族中的位置。
首先判断该双亲是否在此家族关系中,若存在则查找其双亲,将新结点插入其双亲的最后一个孩子之后;
若没有孩子,则直接作为左孩子插入。
以写入的方式打开文件,如果成功打开,则更新family数组中的信息,并查找新成员的双亲所在位置和其对应的“@”个数,如果“@”个数小于双亲位置,则添加“@”实质相等,新成员不插入到最后“@”之前。
最后将family数组中信息写入文件保存,关闭文件。
/*添加一个新成员*/
voidAppend(TriTree*t)
inti=0,j,parpos=1,curpos,num,end=0,count=-1;
DataTypechi[MAXNUM],par[MAXNUM];
/*存储输入的孩子和其双亲结点*/
TriTree*tpar,*temp;
请输入要添加的成员和其父亲,以回车分隔!
\n."
gets(chi);
gets(par);
tpar=Search(t,par);
/*查找双亲结点是否存在*/
tpar)
%s该成员不存在!
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/*没有孩子则直接添加*/
lchild=temp;
/*以写入方式打开文件*/
if(fp)
while(strcmp(par,family[i])!
=0&
&
family[i][0]!
if(family[i][0]!
)/*查找双亲在数组中位置*/
parpos++;
/*parpos计数*/
i=0;
/*family数组行下标归*/
while(family[i][0]!
if(family[i][0]=='
)/*查找“@”的个数,第一个不计*/
count++;
/*count累加个数*/
if(count==parpos)/*说明此“@”与其前一个“@”之前为par的孩子*/
curpos=i;
/*curpos计当前位置*/
if(count<
parpos)/*“@”数小于parpos数*/
num=parpos-count;
/*添加“@”个数为num*/
for(j=i;
j<
=i+num;
j++)/*从数组末尾添加“@”*/
strcpy(family[j],"
@\0"
strcpy(family[i+num+1],"
#\0"
/*“#”移到数组末尾*/
strcpy(family[i+num-1],chi);
/*在最后一个“@”前添加新成员*/
end=1;
/*end为时标记已添加*/
j>
=curpos;
j--)/*当前位置到数组最后的全部信息后移一行*/
strcpy(family[j+1],family[j]);
strcpy(family[curpos],chi);
/*将新结点存储到“@”的前一行*/
if(end==1)/*若end为,则数组末尾下标后移num位*/
i=i+num;
for(j=0;
=i+1;
j++)/*将数组所有信息写入文件*/
fputs(family[j],fp);
fputc('
/*一个信息存一行*/
fclose(fp);
添加新成员成功!
添加新成员失败!
2.6家族成员关系的相关查询
2.6.1查找一个家族的鼻祖
判断输入的姓名是否在该家族中存在,如果存在,则返回该家族的根节点信息。
/*查找一个家族的祖先*/
voidAncesstor(TriTree*t)/*返回树的根结点信息*/
该家族的祖先为%s\n"
t->
data);
2.6.2查找一个成员的所有祖先路径
查找一个成员的所有祖先路径,需要从它的双亲一直向上查找到根结点。
对与结点t,先判断它是否是根结点(根节点的双亲是NULL),如果是根结点,直接输出它本身;
如果不是,查找它的双亲指针指向的结点,将双亲信息输出。
继续查找,直到找到根结点。
/*查找一个成员的所有祖先*/
voidAncesstorPath(TriTree*t)
if(t->
parent==NULL)/*若该成员为祖先,则直接输出*/
%s无祖先!
else/*否则继续查找祖先*/
%s所有祖先路径:
%s"
data,t->