采用树表示一个家谱关系,采用链表(孩子表示法)作为存储结构,实现家谱关系的相关运算。每个节点信息包含有:姓名、性别、配偶姓名、身份证号、年龄、出生日期等。 功能要求: 1)输入家族信息(要求自己设计文件存储格式,存放当前所有家族信息)2)输出家族信息(要求界面输出格式直观明了) 3)查找某人的所有儿子 4)查找某人的双亲选做功能: 1)查找某人的所有祖先 2)查找某人的所有兄弟界面
时间: 2023-11-22 08:53:56 浏览: 118
树的二叉链表(孩子-兄弟)存储表示.doc
很好,这是一个家谱关系的小项目,需要用到树和链表数据结构,下面我将分步骤进行讲解。
1. 设计文件存储格式
我们可以使用文本文件作为存储格式,每个节点信息之间用逗号或制表符隔开,每个节点占一行。例如:
```txt
姓名,性别,配偶姓名,身份证号,年龄,出生日期
张三,男,李四,123456789,30,1990-01-01
李四,女,张三,987654321,28,1992-05-15
王五,男,,111111111,60,1960-08-20
```
其中,配偶姓名为空表示此人未婚。
2. 定义节点结构体
我们定义一个节点结构体,包含姓名、性别、配偶姓名、身份证号、年龄、出生日期等信息。同时,为了实现孩子表示法,我们需要定义一个指向孩子节点的指针和一个指向兄弟节点的指针。
```c++
struct Node {
string name;
string gender;
string spouseName;
string idNumber;
int age;
string birthDate;
Node* child;
Node* sibling;
};
```
3. 实现读取文件并构建家谱树
我们可以定义一个函数,读取存储家族信息的文本文件,并构建家谱树。读取文本文件可以使用 ifstream 类,构建家谱树可以使用递归方法。
```c++
Node* buildTreeFromFile(string fileName) {
ifstream fin(fileName);
if (!fin.is_open()) {
cout << "Failed to open file: " << fileName << endl;
return nullptr;
}
string line;
getline(fin, line); // 读取第一行,抛弃
Node* root = nullptr;
unordered_map<string, Node*> nodeMap; // 用哈希表存储已经创建的节点
while (getline(fin, line)) {
stringstream ss(line);
string name, gender, spouseName, idNumber, birthDate;
int age;
getline(ss, name, ',');
getline(ss, gender, ',');
getline(ss, spouseName, ',');
getline(ss, idNumber, ',');
ss >> age;
getline(ss, birthDate);
Node* node = new Node{name, gender, spouseName, idNumber, age, birthDate, nullptr, nullptr};
nodeMap[idNumber] = node; // 将节点存入哈希表
if (!root) {
root = node; // 如果根节点还没有创建,将第一个节点作为根节点
} else {
// 将节点插入到家谱树中
if (!spouseName.empty()) {
// 如果有配偶,将配偶插入到家谱树中
if (nodeMap.count(spouseName)) {
Node* spouse = nodeMap[spouseName];
node->sibling = spouse->child;
spouse->child = node;
} else {
Node* spouse = new Node{spouseName, gender == "男" ? "女" : "男", name, "", age, birthDate, nullptr, nullptr};
nodeMap[spouseName] = spouse;
node->sibling = spouse->child;
spouse->child = node;
}
} else {
// 如果没有配偶,将节点插入到兄弟节点中
Node* parent = nodeMap[idNumber.substr(0, 16) + "00000000"]; // 获得父亲节点
node->sibling = parent->child;
parent->child = node;
}
}
}
fin.close();
return root;
}
```
4. 实现输出家族信息
我们可以定义一个函数,遍历家谱树,并输出每个节点的信息。这里我们采用前序遍历算法。
```c++
void printFamilyTree(Node* root) {
if (!root) {
return;
}
cout << root->name << " " << root->gender << " 身份证号:" << root->idNumber << " 年龄:" << root->age << " 出生日期:" << root->birthDate << endl;
Node* child = root->child;
while (child) {
printFamilyTree(child);
child = child->sibling;
}
}
```
5. 实现查找某人的所有儿子
我们可以定义一个函数,输入某人的身份证号,查找该人的所有儿子。遍历该人的孩子链表,并筛选出所有性别为男的孩子。
```c++
vector<Node*> findSons(Node* root, string idNumber) {
vector<Node*> sons;
Node* node = findNode(root, idNumber);
if (node) {
Node* child = node->child;
while (child) {
if (child->gender == "男") {
sons.push_back(child);
}
child = child->sibling;
}
}
return sons;
}
```
其中,findNode 函数可以用递归的方法实现,查找身份证号为 idNumber 的节点。
6. 实现查找某人的双亲
我们可以定义一个函数,输入某人的身份证号,查找该人的双亲。由于一个节点可能有多个父亲(比如再婚的情况),我们可以将所有父亲节点放入一个 vector 中返回。
```c++
vector<Node*> findParents(Node* root, string idNumber) {
vector<Node*> parents;
Node* node = findNode(root, idNumber);
if (node) {
string fatherId = idNumber.substr(0, 16) + "00000000";
if (findNode(root, fatherId)) {
parents.push_back(findNode(root, fatherId));
}
string motherId = idNumber.substr(0, 16) + "11111111";
if (findNode(root, motherId)) {
parents.push_back(findNode(root, motherId));
}
}
return parents;
}
```
7. 实现查找某人的所有祖先
我们可以定义一个函数,输入某人的身份证号,查找该人的所有祖先。由于一个节点可能有多个父亲,我们可以递归查找所有父亲的父亲,直到根节点。
```c++
vector<Node*> findAncestors(Node* root, string idNumber) {
vector<Node*> ancestors;
Node* node = findNode(root, idNumber);
vector<Node*> parents = findParents(root, idNumber);
for (Node* parent : parents) {
ancestors.push_back(parent);
vector<Node*> grandParents = findAncestors(root, parent->idNumber);
ancestors.insert(ancestors.end(), grandParents.begin(), grandParents.end());
}
return ancestors;
}
```
8. 实现查找某人的所有兄弟
我们可以定义一个函数,输入某人的身份证号,查找该人的所有兄弟。由于一个节点可能有多个兄弟,我们可以遍历该节点的兄弟链表,并筛选出所有不是该节点本人的兄弟。
```c++
vector<Node*> findSiblings(Node* root, string idNumber) {
vector<Node*> siblings;
Node* node = findNode(root, idNumber);
if (node) {
Node* parent = findNode(root, idNumber.substr(0, 16) + "00000000"); // 获得父亲节点
Node* child = parent->child;
while (child) {
if (child != node) {
siblings.push_back(child);
}
child = child->sibling;
}
}
return siblings;
}
```
到这里,我们已经完成了家谱关系的相关运算,下面是完整的代码:
阅读全文