《家谱管理系统》
一个家谱关系由若干家谱记录构成,每个家谱记录由父亲、母亲和子女姓名构成,其中姓名是关 键字。设计并实现一个简单的家谱管理系统。定义一个主菜单,界面友好,演示程序以用户和计算机的对话方式进行,可以反复操作,方便用户实现下述操作。
2. 功能和原始数据
2.1 主要功能
主要功能包括:
- 创建家族关系树:从键盘输入家谱记录,按照祖先到子孙的顺序建立家族关系树,并将其存储到外部文件。
- 添加家族成员:通过输入父亲、母亲和子女的姓名,将新的家族成员添加到家族关系树中,并保存到外部文件。
- 删除家族成员:根据输入的家族成员姓名,从家族关系树中删除对应的家谱记录,并保存到外部文件。
- 查询家族成员信息:根据输入的家族成员姓名,在家族关系树中查询对应的家谱记录,并输出相关信息。
- 输出家谱信息:遍历家族关系树并打印家谱信息。
- 打印家谱树的先序、中序和后序遍历:分别以先序、中序和后序方式打印家族关系树。
2.2 原始数据
原始数据包括家庭成员的姓名和关系,用于构建和管理家族关系树的层级结构。下面图片是调试所用到的例子:
图2-2 原始数据图
3. 程序总体设计
3.1 数据结构设计
程序中使用的数据结构包括:
(1)结构体 FamilyRecord:用于表示家谱记录,包括父亲姓名、母亲姓名、子女姓名列表,以及指向左右子节点的指针。
(2)类 FamilyTree:家谱管理系统类,包括私有成员变量 root(家谱记录的根节点)和 printedMembers(记录已经打印过的成员的集合)。
3.2 程序总体框架
FamilyTree 类框架图描述
类名: FamilyTree
(1)公有成员函数:
FamilyTree(): 构造函数
createFamilyTree(): 从键盘输入家谱记录,建立家族关系树
saveFamilyTreeToFile(): 保存家谱关系到外部文件
addFamilyMember(): 添加家族成员
removeFamilyMember(): 删除家族成员
queryFamilyMember(): 查询家族成员信息
printFamilyTree(): 输出家谱信息
printFamilyTreePreOrder(): 打印家谱树的先序遍历
printFamilyTreeInOrder(): 打印家谱树的中序遍历
printFamilyTreePostOrder(): 打印家谱树的后序遍历
(2)私有成员函数:
insertFamilyRecord(FamilyRecord&, FamilyRecord*&): 插入家谱记录到家族关系树
removeFamilyRecord(const string&, FamilyRecord*&): 从家族关系树中删除家谱记录
deleteFamilyRecord(FamilyRecord*&): 删除家族记录
queryFamilyRecord(const string&, FamilyRecord*, bool&): 查询家族记录
isChild(const string&, const vector<string>&): 判断是否为子女
printChildren(const vector<string>&): 打印子女姓名
printFamilyRecord(FamilyRecord*): 遍历并打印家族记录
printFamilyTreeToFile(FamilyRecord*, ofstream&): 递归打印家谱树并保存到文件
printFamilyTreePreOrder(FamilyRecord*, string): 输出家谱树的先序遍历
printFamilyTreeInOrder(FamilyRecord*, string): 输出家谱树的中序遍历
printFamilyTreePostOrder(FamilyRecord*, string): 输出家谱树的后序遍历
(3)关系:
公有成员函数可以直接调用私有成员函数。
createFamilyTree() 可能会调用 insertFamilyRecord() 来建立家族关系树。
saveFamilyTreeToFile() 可能会调用 printFamilyTreeToFile() 来保存家谱树。
addFamilyMember() 可能会调用 insertFamilyRecord()。
removeFamilyMember() 可能会调用 removeFamilyRecord() 和 deleteFamilyRecord()。
queryFamilyMember() 可能会调用 queryFamilyRecord()。
printFamilyTreePreOrder(), printFamilyTreeInOrder(), 和 printFamilyTreePostOrder() 分别对应不同的树遍历方式,并可能会调用相应的私有成员函数 printFamilyTreePreOrder(FamilyRecord*, string), printFamilyTreeInOrder(FamilyRecord*, string), 和 printFamilyTreePostOrder(FamilyRecord*, string)。
图3-2 FamilyTree函数框架图
图3-2 FamilyTree函数调用关系图
3.3 函数原型清单
class FamilyTree {
public:
FamilyTree();
void createFamilyTree();
void saveFamilyTreeToFile();
void addFamilyMember();
void removeFamilyMember();
void queryFamilyMember();
void printFamilyTree();
void printFamilyTreePreOrder();
void printFamilyTreeInOrder();
void printFamilyTreePostOrder();
private:
void insertFamilyRecord(FamilyRecord&, FamilyRecord*&);
void removeFamilyRecord(const string&, FamilyRecord*&);
void deleteFamilyRecord(FamilyRecord*&);
void queryFamilyRecord(const string&, FamilyRecord*, bool&);
bool isChild(const string&, const vector<string>&);
void printChildren(const vector<string>&);
void printFamilyRecord(FamilyRecord*);
void printFamilyTreeToFile(FamilyRecord*, ofstream&);
void printFamilyTreePreOrder(FamilyRecord*, string);
void printFamilyTreeInOrder(FamilyRecord*, string);
void printFamilyTreePostOrder(FamilyRecord*, string);
};
3.4 程序组织
图3-4 程序组织框架图
4. 功能算法设计和调试
4.1 主要功能算法设计
1.文字描述算法设计思想,并用伪代码描述算法。
设计思想:
(1)创建家谱树:用户依次输入父亲、母亲和子女的信息,通过递归方式将新节点插入到二叉树中。
伪代码:
创建家族记录
如果根节点为空
创建新根节点
否则
递归插入到左子树
递归插入到右子树
(1)添加家族成员:获取新成员信息,按照二叉树的插入规则插入到树中。
伪代码:
创建家族记录
如果根节点为空
创建新根节点
否则
递归插入到左子树
递归插入到右子树
(2)删除家族成员:根据输入的成员姓名,在树中查找并删除。
伪代码:
如果根节点为空
返回
如果根节点的父亲或母亲姓名与输入匹配
删除根节点
返回
遍历子女列表,如果有匹配
删除对应的子女
递归删除左子树中的匹配成员
递归删除右子树中的匹配成员
(4)查询家族成员:在树中递归查找匹配的成员,并输出其信息。
伪代码:
如果根节点为空
返回
如果根节点的父亲、母亲或子女中有匹配
输出信息
返回
递归查询左子树
递归查询右子树
(5)遍历家谱树(先序、中序、后序):按照相应的遍历规则递归输出节点信息。
伪代码(以先序为例):
输出根节点信息
先序遍历左子树
先序遍历右子树
2.给出算法实现的程序流程图。
图4-1 程序流程图
4.2 调试
- 运行程序后出现家谱系统界面
图4-2 调试图1
2.选择操作“1“按照指令输入数据可以保存家谱到文件myFamily073.txt
图4-2 调试图2
3.选择操作“4”查询家族成员信息,输入要查询成员的姓名即可
图4-2 调试图3
4.选择操作“5”,等待家谱信息输出
图4-2 调试图4
5.选择操作“6”,“7”,“8”,会按照先序,中序,后序的顺序树形输出家谱信息
图4-2 调试图5
图4-2 调试图6
图4-2 调试图7
6.选择操作“2”,添加家族成员信息
图4-2 调试图8
7.选择操作“3”,输入要删除家族成员的姓名即可
图4-2 调试图9
8.选择操作“0”,退出家谱系统,界面显示“谢谢使用,再见!”,调试结束
图4-2 调试图10