图形化之家谱遗传系统
1:废话不多说先看成果。
QQ录屏20230418163603
QQ录屏20230418163732
2:解析:
1:不知道会有多少个孩子,所以我们用二叉树的孩子兄弟结构
typedef struct treeNode {char name[100];//名字int generation;//辈分char gender;//性别char birth[11];//生日char death[11];//死亡struct treeNode* firstChild;//第一个孩子struct treeNode* nextSibling;//兄弟
} TreeNode, * Tree;
2:创立新节点
Tree createNode(char* name, int generation, char gender, char* birth, char* death) {// 创建一个新节点Tree node = (Tree)malloc(sizeof(TreeNode));strcpy(node->name, name);node->generation = generation;node->gender = gender;strcpy(node->birth, birth);strcpy(node->death, death);node->firstChild = NULL;node->nextSibling = NULL;return node;
}
3:因为我没加父亲指针,所以这里又加了一个确立父子关系的函数
void insertChild(Tree parent, Tree child) {//确定父子关系if (parent == NULL || child == NULL) {return;}if (parent->firstChild == NULL) { // 如果该节点没有子节点,则直接将新节点作为子节点parent->firstChild = child;}else { // 否则在子节点链表尾部添加新节点Tree sibling = parent->firstChild;while (sibling->nextSibling != NULL) {sibling = sibling->nextSibling;}sibling->nextSibling = child;}
}
4:先序遍历显示整个家谱
void traverseTree(Tree root) {//全部输出char a[100];if (root == NULL) {return;}if (root->generation == 1){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(130, i, a); i += 100;}else if (root->generation == 2){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(260, j, a); j += 100;}else if (root->generation == 3){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(390, o, a); o += 100;}else if (root->generation == 4){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(510, u, a); u += 100;}else if (root->generation == 5){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(640, y, a); y += 100;}else if (root->generation == 6){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(770, t, a); t += 100;}else if (root->generation == 7){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(900, r, a); r += 100;}traverseTree(root->firstChild);traverseTree(root->nextSibling);
}
5:因为没加父亲指针,又要想想怎么找父亲的节点
Tree findParent(Tree root, Tree p) {//找父亲节点if (root == NULL || p == NULL) {return NULL;}if (root == p) { // 如果要查找的是根节点,则其没有父亲节点return NULL;}Tree q = root->firstChild;while (q != NULL) {Tree parent = findParent(q, p); // 递归查找节点p的父亲节点if (parent != NULL) {return parent;}q = q->nextSibling; // 遍历root的下一个兄弟节点}// 如果root的孩子节点中没有包含节点p,则判断root是否为p的父亲节点if (root->firstChild == p) {return root;}else {Tree sibling = root->firstChild;while (sibling != NULL && sibling != p) {sibling = sibling->nextSibling;}if (sibling != NULL) {return root;}}return NULL; // 没有找到节点p,返回NULL
}
6:有了父亲节点就可以进行删除了
void deleteMember(Tree root) {//删除成员char name[100];InputBox(name, 100, "请输入要删除的成员姓名:");Tree node = searchNode(root, name);if (node == NULL) {settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(690, 200, "没找到");return;}// 删除该节点及其所有子节点if (node == root) { // 如果要删除的是根节点,则直接释放整个家谱free(root);settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(690, 200, "家谱已经清空");return;}Tree parent = findParent(root, node);Tree child = parent->firstChild;while (child != NULL) { // 在父节点的子节点链表中删除该节点if (child == node) { // 找到要删除的节点if (child == parent->firstChild) { // 如果要删除的节点是第一个子节点,则直接将其后面的节点作为父节点的第一个子节点parent->firstChild = child->nextSibling;}else { // 否则在子节点链表中删除该节点Tree sibling = parent->firstChild;while (sibling->nextSibling != child) {sibling = sibling->nextSibling;}sibling->nextSibling = child->nextSibling;}free(node); // 释放要删除的节点settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(690, 200, "删除成功");return;}child = child->nextSibling;}
}
7:修改和添加的话,就先找到它的节点,加和改。我们直接看完整代码。这里我图形化用的有点乱,抱歉。
3:完整代码
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include<fstream>
#include<easyx.h>
#include<conio.h>
#include<graphics.h>
using namespace std;
const int i1 = 50;
int i = i1, j = i1, o = i1, u = i1, y = i1, t = i1, r = i1, k = i1;
typedef struct treeNode {char name[100];//名字int generation;//辈分char gender;//性别char birth[11];//生日char death[11];//死亡struct treeNode* firstChild;//第一个孩子struct treeNode* nextSibling;//兄弟
} TreeNode, * Tree;
void huanyuan()//图形化输出家谱的时候用还原y的坐标
{i = i1; j = i1; o = i1; u = i1; y = i1; t = i1; r = i1; k = i1;
}
Tree createNode(char* name, int generation, char gender, char* birth, char* death) {// 创建一个新节点Tree node = (Tree)malloc(sizeof(TreeNode));strcpy(node->name, name);node->generation = generation;node->gender = gender;strcpy(node->birth, birth);strcpy(node->death, death);node->firstChild = NULL;node->nextSibling = NULL;return node;
}
void insertChild(Tree parent, Tree child) {//确定父子关系if (parent == NULL || child == NULL) {return;}if (parent->firstChild == NULL) { // 如果该节点没有子节点,则直接将新节点作为子节点parent->firstChild = child;}else { // 否则在子节点链表尾部添加新节点Tree sibling = parent->firstChild;while (sibling->nextSibling != NULL) {sibling = sibling->nextSibling;}sibling->nextSibling = child;}
}
void beifen(Tree root, int a)//辈分输出
{char nm[100];if (root == NULL){return;}if (root->generation == a){strcpy(nm,root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(500, k, nm); k += 50;}beifen(root->firstChild, a);beifen(root->nextSibling, a);
}
void traverseTree(Tree root) {//全部输出char a[100];if (root == NULL) {return;}if (root->generation == 1){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(130, i, a); i += 100;}else if (root->generation == 2){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(260, j, a); j += 100;}else if (root->generation == 3){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(390, o, a); o += 100;}else if (root->generation == 4){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(510, u, a); u += 100;}else if (root->generation == 5){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(640, y, a); y += 100;}else if (root->generation == 6){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(770, t, a); t += 100;}else if (root->generation == 7){strcpy(a, root->name);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(900, r, a); r += 100;}traverseTree(root->firstChild);traverseTree(root->nextSibling);
}
Tree searchNode(Tree root, char* name) {//查找姓名的节点if (root == NULL) {return NULL;}if (strcmp(root->name, name) == 0) {return root; // 如果找到了,则返回该节点}// 否则递归查找该节点的子节点Tree child = root->firstChild;while (child != NULL) {Tree node = searchNode(child, name);if (node != NULL) {return node;}child = child->nextSibling;}return NULL;
}
void chazhao(Tree root, char* name)//查姓名
{int a;Tree node=searchNode(root, name);if (node == NULL){settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(690, 200, "没查到");return;}a = node->generation;char str[10];sprintf(str, "%d", a);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(690, 200, node->name);outtextxy(690, 250, str);outtextxy(690, 400, node->gender);outtextxy(690, 300, node->birth);outtextxy(690, 350, node->death);
}
Tree findParent(Tree root, Tree p) {//找父亲节点if (root == NULL || p == NULL) {return NULL;}if (root == p) { // 如果要查找的是根节点,则其没有父亲节点return NULL;}Tree q = root->firstChild;while (q != NULL) {Tree parent = findParent(q, p); // 递归查找节点p的父亲节点if (parent != NULL) {return parent;}q = q->nextSibling; // 遍历root的下一个兄弟节点}// 如果root的孩子节点中没有包含节点p,则判断root是否为p的父亲节点if (root->firstChild == p) {return root;}else {Tree sibling = root->firstChild;while (sibling != NULL && sibling != p) {sibling = sibling->nextSibling;}if (sibling != NULL) {return root;}}return NULL; // 没有找到节点p,返回NULL
}
void addMember(Tree root) {//添加成员char name[100], generation,b[10], gender, birth[11], death[11];InputBox(name, 100, "请输入成员姓名:");InputBox(b, 100, "请输入性别(M/F):");gender = b[0];InputBox(birth, 100, "请输入出生日期(格式:yyyy-mm-dd):");InputBox(death, 100, "请输入死亡日期(格式:yyyy-mm-dd,如在世请输入“-”):");Tree node = createNode(name, 1, gender, birth, death);InputBox(name, 100, "请选择该成员的父亲或母亲姓名:");Tree parent = searchNode(root, name);if (parent == NULL) {settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(690, 200, "未找到他的父母,请确认后重试"); return;}insertChild(parent, node);node->generation = parent->generation + 1;settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(690, 200, "添加成功");
}
void modifyMember(Tree root) {// 修改成员信息char name[100], birth[100], death[100];InputBox(name, 100, "请输入要修改信息的成员姓名:");Tree node = searchNode(root, name);if (node == NULL) {settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(690, 200, "没查到");return;}InputBox(birth, 100, "请输入新的出生日期(格式:2002-12-28):");strcpy(node->birth, birth);InputBox(name, 100, "请输入新的死亡日期(格式:2002-12-28,如在世请输入“-”):");strcpy(node->death, death);settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(690, 200, "修改成功");
}
void deleteMember(Tree root) {//删除成员char name[100];InputBox(name, 100, "请输入要删除的成员姓名:");Tree node = searchNode(root, name);if (node == NULL) {settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(690, 200, "没找到");return;}// 删除该节点及其所有子节点if (node == root) { // 如果要删除的是根节点,则直接释放整个家谱free(root);settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(690, 200, "家谱已经清空");return;}Tree parent = findParent(root, node);Tree child = parent->firstChild;while (child != NULL) { // 在父节点的子节点链表中删除该节点if (child == node) { // 找到要删除的节点if (child == parent->firstChild) { // 如果要删除的节点是第一个子节点,则直接将其后面的节点作为父节点的第一个子节点parent->firstChild = child->nextSibling;}else { // 否则在子节点链表中删除该节点Tree sibling = parent->firstChild;while (sibling->nextSibling != child) {sibling = sibling->nextSibling;}sibling->nextSibling = child->nextSibling;}free(node); // 释放要删除的节点settextcolor(YELLOW);settextstyle(25, 0, _T("楷体"));outtextxy(690, 200, "删除成功");return;}child = child->nextSibling;}
}
void anjian()
{settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(20, 50, _T("显示家谱"));settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(20, 150, _T("查找成员"));settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(20, 250, _T("添加成员"));settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(20, 350, _T("修改成员"));settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(20, 450, _T("删除成员"));settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(20, 550, _T("退出"));
}
void fanhui()
{settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(900, 600, _T("返回"));
}
void tuichu()
{settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(380, 1, _T("真的要退出吗?"));settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(170, 100, _T("嗯,下次再见"));settextcolor(YELLOW);settextstyle(50, 0, _T("楷体"));outtextxy(610, 100, _T("算了,再待一会"));
}
void chazhaoanjian()
{settextcolor(RED);settextstyle(25, 0, _T("楷体"));outtextxy(130, 1, _T("按姓名查"));outtextxy(430, 1, _T("按辈分查"));outtextxy(726, 1, _T("查父母"));outtextxy(128, 352, _T("查子女"));outtextxy(428, 351, _T("查兄弟"));
}
int main()
{char name[100];int n;char a[100], b, c[100], d[100], e[100];int generation;fstream file;file.open("D:\\\\算法\\\\家谱系统\\\\jiapu.txt", ios::in);file >> a >> generation >> b >> c >> d >> e;Tree node1 = createNode(a, generation, b, c, d);while (!file.eof()){file >> a >> generation >> b >> c >> d >> e;Tree node2 = createNode(a, generation, b, c, d);Tree node3 = searchNode(node1, e);insertChild(node3, node2);}initgraph(1000, 700);IMAGE backgroung;loadimage(&backgroung, _T("D:\\\\SteamLibrary\\\\steamapps\\\\workshop\\\\content\\\\431960\\\\2931161999\\\\preview.jpg"), 1000, 700);putimage(0, 0, &backgroung);anjian();//按键fanhui();//返回按键while (1){BeginBatchDraw();putimage(0, 0, &backgroung);anjian();MOUSEMSG msg = GetMouseMsg();if (msg.x > 20 && msg.x < 220 && msg.y>50 && msg.y < 100 && msg.uMsg == WM_LBUTTONDOWN)//显示家谱{IMAGE bg;loadimage(&bg, _T("D:\\\\SteamLibrary\\\\steamapps\\\\workshop\\\\content\\\\431960\\\\2953870227\\\\preview.jpg"), 1000, 700);putimage(0, 0, &bg);settextcolor(RED);settextstyle(25, 0, _T("楷体"));outtextxy(130, 1, _T("第一代"));outtextxy(260, 1, _T("第二代"));outtextxy(390, 1, _T("第三代"));outtextxy(510, 1, _T("第四代"));outtextxy(640, 1, _T("第五代"));outtextxy(770, 1, _T("第六代"));outtextxy(900, 1, _T("第七代"));traverseTree(node1);huanyuan();fanhui();while (1){BeginBatchDraw();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if (msg.x > 20 && msg.x < 220 && msg.y>150 && msg.y < 200 && msg.uMsg == WM_LBUTTONDOWN)//查找成员{IMAGE bg;loadimage(&bg, _T("D:\\\\SteamLibrary\\\\steamapps\\\\workshop\\\\content\\\\431960\\\\2809204709\\\\preview.jpg"), 1000, 700);putimage(0, 0, &bg);fanhui();chazhaoanjian();while (1){BeginBatchDraw();putimage(0, 0, &bg);chazhaoanjian();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 130 && m1.x < 230 && m1.y>1 && m1.y < 26 && m1.uMsg == WM_LBUTTONDOWN)//查姓名{IMAGE b1;loadimage(&b1, _T("C:\\\\Users\\\\86178\\\\Pictures\\\\Saved Pictures\\\\085237m64ya4rfleumyxe4.jpg"), 1000, 700);putimage(0, 0, &b1);char s[100];InputBox(s, 100, "请输入姓名");chazhao(node1, s);fanhui();while (1){BeginBatchDraw();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if (m1.x > 430 && m1.x < 530 && m1.y>1 && m1.y < 26 && m1.uMsg == WM_LBUTTONDOWN)//查辈分{IMAGE b2;loadimage(&b2, _T("C:\\\\Users\\\\86178\\\\Pictures\\\\Saved Pictures\\\\e40a20ca39dbb6fd24061bf14c24ab18952b37de.jpg"), 1000, 700);putimage(0, 0, &b2);char str[100];InputBox(str, 100, "请输入要查找的辈分");n = atoi(str);beifen(node1,n);fanhui();while (1){BeginBatchDraw();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if (m1.x > 726 && m1.x < 826 && m1.y>1 && m1.y < 26 && m1.uMsg == WM_LBUTTONDOWN)//查父母{IMAGE b3;loadimage(&b3, _T("D:\\\\SteamLibrary\\\\steamapps\\\\workshop\\\\content\\\\431960\\\\2954397085\\\\preview.jpg"), 1000, 700);putimage(0, 0, &b3);char str[100];InputBox(str, 100, "请输入要查找谁的父母");Tree node = searchNode(node1, str);Tree node2 = findParent(node1, node);settextcolor(RED);settextstyle(25, 0, _T("楷体"));outtextxy(500, 50, "他的家长是:");outtextxy(500, 100, node2->name);fanhui();while (1){BeginBatchDraw();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if(m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if (msg.x > 20 && msg.x < 220 && msg.y>250 && msg.y < 300 && msg.uMsg == WM_LBUTTONDOWN)//添加成员{IMAGE bg;loadimage(&bg, _T("D:\\\\SteamLibrary\\\\steamapps\\\\workshop\\\\content\\\\431960\\\\2954915142\\\\preview.jpg"), 1000, 700);putimage(0, 0, &bg);fanhui();addMember(node1);while (1){BeginBatchDraw();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if (msg.x > 20 && msg.x < 220 && msg.y>350 && msg.y < 400 && msg.uMsg == WM_LBUTTONDOWN)//修改成员{IMAGE bg;loadimage(&bg, _T("D:\\\\SteamLibrary\\\\steamapps\\\\workshop\\\\content\\\\431960\\\\2771613746\\\\preview.jpg"), 1000, 700);putimage(0, 0, &bg);fanhui();modifyMember(node1);while (1){BeginBatchDraw();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if (msg.x > 20 && msg.x < 220 && msg.y>450 && msg.y < 500 && msg.uMsg == WM_LBUTTONDOWN)//删除成员{IMAGE bg;loadimage(&bg, _T("C:\\\\Users\\\\86178\\\\Pictures\\\\Saved Pictures\\\\20220726235757_54919.jpeg"), 1000, 700);putimage(0, 0, &bg);fanhui();deleteMember(node1);while (1){BeginBatchDraw();fanhui();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 900 && m1.x < 1000 && m1.y>600 && m1.y < 650 && m1.uMsg == WM_LBUTTONDOWN){break;}FlushBatchDraw();}}else if (msg.x > 20 && msg.x < 120 && msg.y>550 && msg.y < 600 && msg.uMsg == WM_LBUTTONDOWN)// 退出{tuichu();IMAGE backgroung;loadimage(&backgroung, _T("D:\\\\SteamLibrary\\\\steamapps\\\\workshop\\\\content\\\\431960\\\\2934572611\\\\preview.jpg"), 1100, 800);putimage(0, 0, &backgroung);while (1){BeginBatchDraw();tuichu();MOUSEMSG m1 = GetMouseMsg();if (m1.x > 170 && m1.x < 470 && m1.y>100 && m1.y < 150 && m1.uMsg == WM_LBUTTONDOWN){break;}else if (m1.x > 610 && m1.x < 960 && m1.y>100 && m1.y < 150 && m1.uMsg == WM_LBUTTONDOWN){goto GG;}FlushBatchDraw();}closegraph();GG:continue;}FlushBatchDraw();}system("pause");
}
4:文件内容在这里
唐晨 1 M 1000 1222 无
唐昊 2 M 1022 1225 唐晨
唐三 3 M 1122 1322 唐昊
唐舞桐 4 F 1206 1348 唐三
唐雨浩 5 M 1265 1451 唐舞桐
唐小桐 5 M 1268 1436 唐舞桐
唐二桐 6 F 1309 1559 唐小桐
唐皮蛋 7 M 1333 1540 唐二桐
唐三桐 7 F 1315 1594 唐小桐
唐建国 8 M 1343 1585 唐三桐
唐舞麟 4 F 1224 1374 唐三
唐轩宇 5 M 1266 1486 唐舞麟
唐小轩 6 M 1300 1560 唐轩宇
唐二轩 7 F 1330 1532 唐小轩
图片的话你可以找你喜欢的。
对了,查找中查兄弟,查子女我还没写,后续再写,所以你点了那里没反应正常。
都看到这里了,点个赞再走吧!