婚姻管理系统-使用bbst数据结构
使用到希尔排序和归并排序,文件存储
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>//名字的最大长度
#define NameMax 30//全局的文件指针变量
FILE* file, * file_admin, * file_divorce;//结婚人数
int nums = 0;//定义普通用户的结构体
typedef struct user {
char name[NameMax];
char ID[20]; //身份证位18位
int age; //年龄
char sex; //性别,F位女,M为男
char partner[NameMax]; //配偶的名字
char partner_ID[20]; //配偶的身份证
struct user* next;
} User;//定义管理员的结构体
typedef struct admin {
char name[NameMax]; //管理员的名字
char password[20]; //密码
}Admin;//定义树结点信息
typedef struct node {
int height;
int balance;
User* info;
struct node* left;
struct node* right;
}Node;//离婚人数链表,用来存储离婚人的信息
User* divorce;//判断是否操作确认,确认是返回1,不确认返回0
int GetConfirm()
{
char yes_no[5];
memset(yes_no, 0, sizeof(yes_no));
printf("\n\t\t=======================================\n");
printf(" \n\t\t\t是否执行该操作 ? 此操作不可逆! \n");
printf("\n\t\t=======================================\n");
printf("\n\t\t\t确认? [Y/N]:");
scanf("%s", yes_no);
if (strcmp(yes_no, "y") == 0 || strcmp(yes_no, "Y") == 0)
return 1;
else
return 0;
}//获得树的高度
int getHeight(Node* node) {
if (node == NULL) {
return 0;
}
int leftHeight = getHeight(node->left);
int rightHeight = getHeight(node->right);
return max(leftHeight, rightHeight) + 1;
}//获得当前结点的平衡因子
int getBalanceFactor(Node* tree) {
//如果不为空,当前结点平衡因子为左子树高度-右子树高度
if (tree) {
return getHeight(tree->left) - getHeight(tree->right);
}
return 0;
}//左转
Node* RR(Node* parent) {
//左旋
Node* son = parent->left;
parent->left = son->right;
son->right = parent;
//更新结点的高度
son->height = max(getHeight(son->left), getHeight(son->right)) + 1;
parent->height = max(getHeight(parent->left), getHeight(parent->right)) + 1;
//返回当前在最顶上的结点
return son;
}//左旋
Node* LL(Node* parent) {
//左旋变换
Node* son = parent->right;
parent->right = son->left;
son->left = parent;
//更新结点高度
son->height = max(getHeight(son->left), getHeight(son->right)) + 1;
parent->height = max(getHeight(parent->left), getHeight(parent->right)) + 1;
//返回当前在最顶上的结点
return son;
}
//更新树的平衡
Node* balance(Node* node) {//获取当前节点的平衡因子
int bf = getBalanceFactor(node);//不需要平衡
if (bf == 0)
return node;if (bf > 1) {
//左子树比右子树高
if (getBalanceFactor(node->left) < 0) {
//LR型,先对左节点进行LL旋转再对当前结点进行RR旋转
node->left = LL(node->left);
}
node = RR(node);
}
else if (bf < -1) {
//右子树比左子树高
if (getBalanceFactor(node->right) > 0) {
//RL型,先对右节点进行RR旋转再对当前结点进行LL旋转
node->right = RR(node->right);
}
node = LL(node);
}// 更新节点高度
node->height = max(getHeight(node->left), getHeight(node->right)) + 1;return node;
}//返回一个正确的身份证号
char* correct_ID() {
char* str = (char*)malloc(sizeof(char) * 19);
memset(str, 0, sizeof(str));
scanf("%s", str);
while (strlen(str) != 18) {
printf("\t\t身份证出错,请输入身份证:");
scanf("%s", str);
putchar('\n');
}
return str;
}//插入一个节点数据
Node* insert(Node* tree, User* info) {
// 判断插入节点是否为空
if (info == NULL) {
return tree;
}// 创建插入节点并赋值
if (tree == NULL) {
//判断是否离婚
User* p, * temp;
temp = p = divorce;
while (temp) {
if (!strcmp(temp->ID, info->ID)) {
printf("\n\t 此人已离婚!!!是否继续?\n");
if (GetConfirm()) {
p->next = temp->next;
}
else
return tree;
}
p = temp;
temp = temp->next;
}nums++;
tree = (Node*)malloc(sizeof(Node));
tree->info = (User*)malloc(sizeof(User));
*(tree->info) = *info;
tree->info->next = NULL;
tree->height = 0;
tree->left = tree->right = NULL;
return tree;
}// 存在相同身份证号的情况
if (strcmp(info->ID, tree->info->ID) == 0) {
printf("\t 身份证重复或已存在该人的信息,添加失败!\n");
return NULL;
}
else if (strcmp(info->ID, tree->info->ID) < 0) {
tree->left = insert(tree->left, info);
}
else {
tree->right = insert(tree->right, info);
}// 更新节点高度并进行平衡操作
tree->height = max(getHeight(tree->left), getHeight(tree->right)) + 1;
tree = balance(tree);return tree;
}//按身份证来查找某个结点
User* searchByID(Node* tree, char* ID) {
if (ID == NULL) {
printf("身份证出错");
return NULL;
}if (!tree) {
User* p = divorce->next;
int flag = 0;
while (p) {
if (!(strcmp(p->ID, ID))) {
printf("\t 姓名:%s,\t\t年龄:%d,\t身份证:%s,\t性别:%c,\t前配偶:%s\n",
p->name, p->age, p->ID, p->sex, p->partner);
flag = 1;
}
p = p->next;
}
if (flag == 0)
printf("\n\t 未找到该人的信息!\n");
return NULL;
}
else if (strcmp(ID, tree->info->ID) < 0) {
return searchByID(tree->left, ID);
}
else if (strcmp(ID, tree->info->ID) > 0) {
return searchByID(tree->right, ID);
}
else {
//找到了,输出信息
printf("\t 姓名:%s,\t\t年龄:%d,\t身份证:%s,\t性别:%c,\t配偶:%s\n",
tree->info->name, tree->info->age, tree->info->ID, tree->info->sex, tree->info->partner);
return tree->info;
}
}//通过姓名来查找,通过前序遍历一遍树
int searchByName(Node* tree, char* name, int type) {
//结婚的中选取
if (type == 1) {
if (name == NULL) {
printf("名称输入有误");
return 0;
}if (tree) {
if (!strcmp(tree->info->name, name)) {
//找到了,输出信息
printf("\t 姓名:%s,\t\t年龄:%d,\t身份证:%s,\t性别:%c,\t配偶:%s\n",
tree->info->name, tree->info->age, tree->info->ID, tree->info->sex, tree->info->partner);
return 1;
}
return searchByName(tree->left, name, type) + searchByName(tree->right, name, type);
}
}
else {
//离婚的中查询
if (divorce == NULL)
return 0;User* q = divorce->next;
int times = 0;
while (q) {
if (!strcmp(q->name, name))
{
//找到了相同名字的人
times++;
printf("\t 姓名:%s,\t\t年龄:%d,\t身份证:%s,\t性别:%c,\t配偶:%s\n",
q->name, q->age, q->ID, q->sex, q->partner);
}
q = q->next;
}
if (times > 0)
return 1;
}
return 0;
}//查找替换节点
Node* findrepalceNode(Node* node) {
//找到右子树上最小节点或左子树上的最大节点
if (node->left != NULL) {
//左子树的最大节点
Node* max = node->left;
while (max->right != NULL) {
max = max->right;
}
return max;
}
else if (node->right != NULL) {
//右子树的最小节点
Node* min = node->right;
while (min->left != NULL) {
min = min->left;
}
return min;
}
else {
//两种都不是
return NULL;
}}
//是否确认输入
int yes_no_divorce() {
char yes_no[5];
memset(yes_no, 0, sizeof(yes_no));
printf("\n\t\t=======================================\n");
printf(" \n\t\t\t是否为离婚? \n");
printf("\n\t\t=======================================\n");
printf("\n\t\t\t y 是离婚 n 是删除 [Y/N]:");
scanf("%s", yes_no);
//清空缓存区
fflush(stdin);
if (strcmp(yes_no, "y") == 0 || strcmp(yes_no, "Y") == 0)
return 1;
else
return 0;
}//删除一个结点
Node* del(Node* tree, User* info) {
// 判断传入的 info 是否为空
if (info == NULL || tree == NULL || ((tree->right == NULL) && (tree->left == NULL) && strcmp(tree->info->ID, info->ID)==0)) {
return NULL;
}if (strcmp(info->ID, tree->info->ID) > 0) {
// 递归删除右子树中的节点
tree->right = del(tree->right, info);
}
else if (strcmp(info->ID, tree->info->ID) < 0) {
// 递归删除左子树中的节点
tree->left = del(tree->left, info);
}
else {
// 找到了要删除的节点
nums--;if (tree->left == NULL || tree->right == NULL) {
// 被删除的节点有一个子节点或者没有子节点// 用子节点来代替当前节点
Node* child;
if (tree->left == NULL) {
child = tree->right;
}
else {
child = tree->left;
}
free(tree->info);
free(tree);
return child;
}
else {
// 被删除的节点有两个子节点
Node* replacenode = findrepalceNode(tree);
tree->info = replacenode->info;
tree->right = del(tree->right, replacenode->info);
}
}// 更新节点高度并进行平衡操作
tree->height = max(getHeight(tree->left), getHeight(tree->right)) + 1;
tree = balance(tree);
return tree;
}//显示已结婚所有数据,通过前序遍历实现
void display_tree(Node* tree) {
if (tree) {
printf("\t 姓名:%s,\t\t年龄:%d,\t身份证:%s,\t性别:%c,\t配偶:%s\n",
tree->info->name, tree->info->age, tree->info->ID, tree->info->sex, tree->info->partner);
display_tree(tree->left);
display_tree(tree->right);
}
}//添加一个双方的婚姻信息(添加婚姻信息)
Node* add_both(Node* tree) {
//定义好变量
char name[NameMax];
char partner_name[NameMax];
char* ID;
char* partner_ID;
int age;
int partner_age;
char sex;
int partner_sex;//输入一方的结婚信息
printf("\t\t 请输入姓名:");
scanf("%s", name);
printf("\t\t 请输入身份证:");
ID = correct_ID();
printf("\t\t 请输入年龄:");
getchar();
scanf("%d", &age);
printf("\t\t 请输入性别(M/F):");
getchar();
scanf(" %c", &sex);
printf("\t\t 请输入配偶姓名:");
scanf("%s", partner_name);
printf("\t\t 请输入配偶身份证:");
partner_ID = correct_ID();
printf("\t\t 请输入配偶年龄:");
getchar();
scanf("%d", &partner_age);
printf("\t\t 请输入配偶性别(M/F):");
getchar();
scanf(" %c", &partner_sex);
getchar();User* info = (User*)malloc(sizeof(User));
(info->next) = NULL;
User* info2 = (User*)malloc(sizeof(User));
(info2->next) = NULL;if (GetConfirm()) {
info->age = age;
info->sex = sex;
strcpy(info->name, name);
strcpy(info->ID, ID);
strcpy(info->partner, partner_name);
strcpy(info->partner_ID, partner_ID);
//先插入本人的身份信息到树中
printf("\t 姓名:%s,年龄:%d,身份证:%s,性别:%c,配偶:%s\n",
info->name, info->age, info->ID, info->sex, info->partner);
tree = insert(tree, info);//复制配偶的信息
info2->age = partner_age;
info2->sex = partner_sex;
strcpy(info2->name, partner_name);
strcpy(info2->ID, partner_ID);
strcpy(info2->partner, name);
strcpy(info2->partner_ID, ID);
printf("\t 姓名:%s,年龄:%d,身份证:%s,性别:%c,配偶:%s\n",
info2->name, info2->age, info2->ID, info2->sex, info2->partner);
//先插入配偶的身份信息到树中
tree = insert(tree, info2);}
return tree;
}//删除一个双方婚姻信息
Node* del_node(Node* tree) {
if (nums <= 2) {
printf("\t 节点必须多于两个\n");
return tree;
}
char* del_ID;
char del_partnerID[20];
//输入信息
printf("\t\t 请输入要删除人的身份证:");
del_ID = correct_ID();
//查找节点
User* user1, * user2;
user1 = searchByID(tree, del_ID);
if (user1 == NULL)
return tree;
strcpy(del_partnerID, user1->partner_ID);
user2 = searchByID(tree, del_partnerID);if (GetConfirm()) {
if (yes_no_divorce()) {
//返回值为1,代表离婚
User* p, * q;
p = q = divorce;
if (divorce->next != NULL) {
//遍历到链表的最后一个节点
while (q) {
p = q;
q = q->next;
}
}
//插入离婚两人的信息在链表中
q = (User*)malloc(sizeof(User));
q->next = NULL;
(*q) = (*user1);
(p->next) = q;
p = (p->next);
q = (User*)malloc(sizeof(User));
q->next = NULL;
(*q) = (*user2);
p->next = q;
q->next = NULL;
}
//删除节点
tree = del(tree, user1);
tree = del(tree, user2);}
return tree;}
//登入
Admin* login(Admin* admin) {
if (admin == NULL)
{
printf("admin.txt文件出错");
exit(0);
}char admin_name[NameMax];
char admin_password[20];
int times = 0;
while (1) {
//输入管理信息
printf("\t 请输入管理员账号:");
scanf("%s", admin_name);
printf("\n");
printf("\t 请输入管理员密码:");
scanf("%s", admin_password);//判断管理员信息是否相等
if (!strcmp(admin->name, admin_name)) {
if (!strcmp(admin->password, admin_password))
break;
else
{
printf("\t 密码错误,请重新输入:\n\n");
}
}
else
{
printf("\t 管理员账号错误,请重新输入:\n\n");
}times++;
//如果密码多次出错
if (times > 4) {
printf("\t\t是否需要修改密码:\n");
if (GetConfirm()) {
printf("请输入修改的用户名:\n");
scanf("%s", admin->name);
printf("请输入修改的密码:\n");
scanf("%s", admin->password);
}
}
}
return admin;
}
//调用文件初始化一颗二叉树
Node* readFile(FILE* f) {
Node* tree = (Node*)malloc(sizeof(Node));
tree->info = (User*)malloc(sizeof(User));
tree->info = NULL;
tree = NULL;
User* temp = (User*)malloc(sizeof(User));
temp->next = NULL;
//判断文件是否为空
fseek(f, 0, SEEK_END);
long position = ftell(f);
if (position == 0) {
//printf("文件为空\n");
return NULL;
}
//文件移到开头
fseek(f, 0, SEEK_SET);
while (fscanf(f, "%s %s %d %c %s %s\n", temp->name, temp->ID, &temp->age, &temp->sex, temp->partner, temp->partner_ID) != EOF) {
tree = insert(tree, temp);//注意指针一次只能指向一个地址,新建一棵树的时候要不断的来创建一个地址空间
temp = (User*)malloc(sizeof(User));
temp->next = NULL;
}
return tree;
}//磁盘上读取一个admin文件出来
Admin* readAdmin(FILE* f) {
Admin* temp = (Admin*)malloc(sizeof(Admin));
fseek(f, 0, SEEK_SET);
fscanf(f, "%s\n%s", temp->name, temp->password);
return temp;
}//磁盘上读取一个divorve文件出来
User* readDivorce(FILE* f) {
User* p, * q, * divorce;
p = q = divorce = (User*)malloc(sizeof(User));
p->next = NULL;
q = (User*)malloc(sizeof(User));
q->next = NULL;
//判断文件是否为空
fseek(f, 0, SEEK_END);
long position = ftell(f);
if (position == 0) {
//printf("文件为空\n");
User* temp = (User*)malloc(sizeof(User));
(temp->next) = NULL;
return temp;
}
//文件移到开头
fseek(f, 0, SEEK_SET);
while ((fscanf(f, "%s %s %d %c %s %s\n", q->name, q->ID, &q->age, &q->sex, q->partner, q->partner_ID)) != EOF)
{
p->next = q;
p = p->next;
q = (User*)malloc(sizeof(User));
}
free(q);
p->next = NULL;
return divorce;
}
//前序遍历存储树到文件中
void travel_creatfile(Node* root) {
if (root == NULL || file == NULL) {
return;
}fprintf(file, "%s %s %d %c %s %s\n",
root->info->name, root->info->ID, root->info->age, root->info->sex,
root->info->partner, root->info->partner_ID);
//遍历树
travel_creatfile(root->left);
travel_creatfile(root->right);
}
User* h, * p;//树转换成链表
void User_to_list(Node* root) {
if (root == NULL)
return;
p->next = root->info;
p = p->next;
p->next = NULL;
User_to_list(root->left);
User_to_list(root->right);
}//保存文件
void saveTreeToFile(Node* temp) {
fclose(file);
if ((file = fopen("marriage.txt", "w+")) != NULL) {
//打开成功
;
}
else {
//打开失败
printf("文件打开出错:\n");
exit(0);
}
travel_creatfile(temp);
}//保存离婚信息文件
void saveDivorceToFile(User* divorce_temp) {
fclose(file_divorce);
if ((file_divorce = fopen("divorce.txt", "w+")) != NULL) {
//打开成功
;
}
else {
//打开失败
printf("文件打开出错:\n");
exit(0);
}
if (divorce_temp == NULL)
return;
User* divorce = divorce_temp->next;
//循环遍历链表,将链表数据存储到文件中
while (divorce) {
fprintf(file_divorce, "%s %s %d %c %s %s\n",
divorce->name, divorce->ID, divorce->age, divorce->sex, divorce->partner, divorce->partner_ID);
divorce = divorce->next;
}
}//保存管理员信息文件
void saveAdminToFile(Admin* admin) {fclose(file_admin);
if ((file_admin = fopen("admin.txt", "w+")) != NULL) {
//打开成功
;
}
else {
//打开失败
printf("\t 管理员信息文件打开出错:\n");
exit(0);
}
if (fprintf(file_admin, "%s\n%s", admin->name, admin->password) == EOF) {
printf("\t 管理员信息文件保存出错:\n");
}
}//统计结婚信息
void Statistical(User a[]) {
//定义并初始化数组
int aa[11] = { 0 };for (int i = 0; i < nums; i++) {
aa[a[i].age / 10]++;
}
printf("\n\t\t不同年龄阶段登记结婚统计:\n");
for (int i = 1; i < nums; i++)
printf("\n\t\t%d岁到%d岁之间有:%d人", i * 10, (i + 1) * 10 - 1, aa[i]);
putchar('\n');
}//希尔排序,升序排序
void shell_sort(User arr[], int type) {
// 初始步长
int gap = nums / 2;
while (gap > 0) {
for (int i = gap; i < nums; i++) {
User temp = arr[i];
int j = i - gap;
//进行比较
if (type == 0) {
//升序
while (j >= 0 && arr[j].age > temp.age) {
arr[j + gap] = arr[j];
j -= gap;
}
}
else {
while (j >= 0 && arr[j].age < temp.age) {
arr[j + gap] = arr[j];
j -= gap;
}
}
//交换
arr[j + gap] = temp;
}
gap /= 2; // 缩短步长
}
}//年龄排序
void sort_age(Node* tree) {
if (tree == NULL) {
printf("\t\t无数据\n");
return;
}
p = h = (User*)malloc(sizeof(User));
h->next = NULL;
User_to_list(tree);
p->next = NULL;User* pp, * head = h->next;
if (head == NULL)
{
printf("\t\t无信息\n");
return;
}
User* a = (User*)malloc(sizeof(User) * nums);
int i = 0;
while (head) {
pp = head;
*(a + i) = *head;
i++;
head = head->next;
pp->next = NULL;
}
//进行排序
printf("\t\t升序排序请输入0,降序则输入其他\n");
int type;
printf("\t\t请输入你要输入的:");
scanf("%d", &type);
shell_sort(a, type);
putchar('\n');
for (i = 0; i < nums; i++) {
printf("\t 姓名:%s,\t\t年龄:%d,\t身份证:%s,\t性别:%c,\t配偶:%s\n",
a[i].name, a[i].age, a[i].ID, a[i].sex, a[i].partner);
}
getchar();
Statistical(a);free(a);
}//查看离婚人数列表
void display_divorce() {
int divorce_num = 0;
if (divorce == NULL)
{
printf("\t 无\n");
return;
}
User* p = divorce->next;
while (p) {
printf("\t 姓名:%s,年龄:%d,身份证:%s,性别:%c,前配偶:%s\n",
p->name, p->age, p->ID, p->sex, p->partner);
divorce_num++;
p = p->next;
}
printf("\t\t\t离婚人数有: %d", divorce_num);
}//显示所有信息
void display_all(Node* tree) {
printf("\t\t已结婚:\n");
display_tree(tree);
printf("\t\t已离婚:\n");
display_divorce();
}//查找并改写该结婚信息
Node* searchcorrect_mar(Node** tree, char* ID) {
if (((*tree) == NULL) || ID == NULL)
return *tree;
if (strcmp(ID, (*tree)->info->ID) > 0) {
//在右子树中
searchcorrect_mar(&((*tree)->right), ID);
}
else if (strcmp(ID, (*tree)->info->ID) < 0) {
searchcorrect_mar(&((*tree)->left), ID);
}
else {
//找到节点了
printf("\t\t 请输入要更改的姓名:");
char name[NameMax];
scanf("%s", name);
putchar('\n');
strcpy((*tree)->info->name, name);
printf("\t\t 请输入要更改的性别:");
char sex;
//抵消多余的回车
getchar();
scanf(" %c", &sex);
putchar('\n');
printf("\t\t 请输入要更改的年龄:");getchar();
int age;
scanf("%d", &age);
(*tree)->info->sex = sex;
(*tree)->info->age = age;
return (*tree);
}
}void searchcorrect_mar2(Node** tree, User* info) {
if (((*tree) == NULL) || info->ID == NULL)
return;
if (strcmp(info->ID, (*tree)->info->ID) > 0) {
//在右子树中
searchcorrect_mar2(&((*tree)->right), info);
}
else if (strcmp(info->ID, (*tree)->info->ID) < 0) {
searchcorrect_mar(&((*tree)->left), info);
}
else {
//找到节点了
strcpy((*tree)->info->partner, info->name);
}
}//更改婚姻信息
Node* correct_marriage(Node* tree) {
User* newnode = (User*)malloc(sizeof(User));
char* ID;
printf("\t\t输入你要更改人的身份证: ");
ID = correct_ID();
if (ID == NULL) {
printf("输入出错");
exit(0);
}
Node* temp = searchcorrect_mar(&tree, ID);
if (temp != temp)
searchcorrect_mar2(&tree, temp->info); //在结婚信息中找到节点了
else {
User* p = divorce->next;
printf("\t\t 请输入要更改的姓名:");
char name[NameMax];
scanf("%s", name);
putchar('\n');
printf("\t\t 请输入要更改的性别:");
char sex;
//抵消多余的回车
getchar();
scanf(" %c", &sex);
putchar('\n');
printf("\t\t 请输入要更改的年龄:");
getchar();
int age;
scanf("%d", &age);
while (p) {
if (!strcmp(p->ID, ID)) {
//在离婚信息中找到节点了
strcpy(p->name, name);
p->sex = sex;
p->age = age;
}
p = p->next;
}
}
return tree;
}//更改管理员信息
Admin* correct_admin() {
if (file_admin == NULL) {
printf("Admin信息文件出错");
exit(0);
}
else
fclose(file_admin);Admin* new = (Admin*)malloc(sizeof(Admin));
printf("\t\t输入你要更改人的管理员账号: ");
scanf("%s", new->name);
printf("\t\t输入你要更改人的管理员密码: ");
scanf("%s", new->password);
//判断存储管理员信息的文件是否存在,是否能打开
if ((file_admin = fopen("admin.txt", "w+")) != NULL) {
//打开成功
;
}
else {
//打开失败
printf("\t 管理员信息文件打开出错:\n");
exit(0);
}
if (fprintf(file_admin, "%s\n%s", new->name, new->password) == EOF) {
printf("\t 管理员信息文件保存出错:\n");
}
fclose(file_admin);
return new;
}//打印菜单
void memu() {printf("\n\t\t***************************************\n");
printf("\t\t* 请选择要进行的操作: *\n");
printf("\t\t* 1. 添加婚姻信息 *\n");
printf("\t\t* 2. 删除婚姻信息 *\n");
printf("\t\t* 3. 按身份证查询 *\n");
printf("\t\t* 4. 显示信息 *\n");
printf("\t\t* 5. 修改婚姻信息 *\n");
printf("\t\t* 6. 按姓名查询 *\n");
printf("\t\t* 7. 按年龄进行排序 *\n");
printf("\t\t* 8. 清屏 *\n");
printf("\t\t* 9. 显示菜单 *\n");
printf("\t\t* a. 修改管理员信息 *\n");
printf("\t\t* b. 保存并退出 *\n");
printf("\t\t* c. 保存文件 *\n");
printf("\t\t***************************************\n\n");
}//打开所有的文本文件
void open_allfile() {
//open_file(file, file_admin);
//判断存储婚姻信息的文件是否存在,是否能打开
if ((file = fopen("marriage.txt", "r+")) != NULL) {
//打开成功
;
}
else {
//打开失败
printf("\t\t 婚姻信息文件打开出错:\n");
exit(0);
}//判断存储管理员信息的文件是否存在,是否能打开
if ((file_admin = fopen("admin.txt", "r+")) != NULL) {
//打开成功
;
}
else {
//打开失败
printf("\t 管理员信息文件打开出错:\n");
exit(0);
}//判断存储离婚信息的文件是否存在,是否能打开
if ((file_divorce = fopen("divorce.txt", "r+")) != NULL) {
//打开成功
;
}
else {
//打开失败
printf("\t 离婚信息文件打开出错:\n");
exit(0);
}
}//后序释放空间
void free_tree(Node** root) {
if (*root == NULL)
return;
free_tree(&((*root)->left));
free_tree(&((*root)->right));
free((*root)->info);
free(*root);
}void free_other(User** h, Admin** admin) {
free(*admin);User* p = (*h)->next;
while (p) {
free(*h);
*h = p;
p = p->next;
}
}//运行程序操作
void running() {
//打开所有文件
open_allfile();Admin* admin = readAdmin(file_admin);
Node* tree = readFile(file);
divorce = readDivorce(file_divorce);admin = login(admin);
char option[10];
memu();
while (1) {
printf("\n\t\t请输入您的选项:");
scanf("%s", option);
printf("\n");
switch (option[0]) {
//添加
case '1':
tree = add_both(tree);
break;
case '2':
//删除
tree = del_node(tree);
break;
case '3':
//身份证查询
printf("\t\t 请输入要查询的身份证号: ");
char* ID;
ID = correct_ID();
searchByID(tree, ID);
break;
case '4':
//查看信息
{
int type;
printf("\t\t 请输入要查看的信息:\n ");
printf("\t\t 1、已结婚人的信息 \n");
printf("\t\t 2、已离婚人的信息\n ");
printf("\t\t 3、所有人的信息 \n");
printf("\t\t 请输入要查询选项(1-3): ");
//判断输入的类型
scanf("%d", &type);
switch (type)
{
case 1:
display_tree(tree); break;
case 2:
display_divorce(); break;
case 3:
display_all(tree);
break;
default:
break;
}
putchar('\n');
break;
}
case '5':
//修改婚姻信息
tree = correct_marriage(tree);
break;
case '6':
{
printf("\t\t 请输入查询类别:\n");
printf("\t\t 1、查询结婚人信息:\n");
printf("\t\t 2、查询离婚人的姓名:\n");
int type;
printf("\t\t 请输入要查询的选项(1-2):");
scanf("%d", &type);
printf("\t\t 请输入要查询的姓名:");
char nameToSearch[NameMax];
scanf("%s", nameToSearch);
int judge = searchByName(tree, nameToSearch, type);
if (judge != 1) {
printf("\t\t查无此人,请检查后再试!\n");
}
}
break;
case '7':
//按年龄进行排序
sort_age(tree);
break;
default:
printf("\t\t无效的选项!\n");
break;
break;
case '9':
memu();
break;
case '8':
system("cls");
break;
case 'a':
//修改管理员信息
admin = correct_admin();
break;
case 'b':
system("cls");
printf("\n\n\t\t\t\t 程序已退出!\n");
printf("\n\t\t\t\t 欢迎下次使用!\n");
saveTreeToFile(tree);
saveDivorceToFile(divorce);
saveAdminToFile(admin);fclose(file);
fclose(file_divorce);
fclose(file_admin);free_tree(&tree);
free_other(&divorce, &admin);
exit(0);
case 'c':
saveTreeToFile(tree);
saveDivorceToFile(divorce);
saveAdminToFile(admin);
printf("\t\t 保存成功!\n");
break;
}
}}
int main() {
running();
return 0;
}
相关文章:
婚姻管理系统-使用bbst数据结构
使用到希尔排序和归并排序,文件存储 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <string.h> //名字的最大长度 #define NameMax 30 //全局的文件指针变量 FILE* file, * file_admin, * file_divorce; /…...
软件架构的概念
1.软件架构演化 为了适应用户的新需求、业务环境和运行环境的变化等,软件架构需要不断地进行自身的演化,也就是说软件架构的演化就是为了维持软件架构自身的有用性。 本质上讲,软件架构的演化就是软件整体结构的演化,演化过程涵盖…...
kubernetes存储-secrets
一、从文件创建 二、编写yaml文件 三、将Secret挂载到Volume中 四、向指定路径映射 secret 密钥 五、将Secret设置为环境变量 六、存储docker registry的认证信息...

Springboot使用EasyExcel导入导出Excel文件
1,准备Excel文件和数据库表结果 2,导入代码 1,引入依赖 <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifac…...

Pytorch L1,L2正则化
L1正则化和L2正则化是常用的正则化技术,用于在机器学习模型中控制过拟合。它们的主要区别在于正则化项的形式和对模型参数的影响。 L1正则化(Lasso正则化): 正则化项形式:L1正则化使用模型参数的绝对值之和作为正则化…...

【Elasticsearch 未授权访问漏洞复现】
文章目录 一、漏洞描述二、漏洞复现三、修复建议 一、漏洞描述 ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布&am…...
pytorch笔记:PackedSequence对象送入RNN
pytorch 笔记:PAD_PACKED_SEQUENCE 和PACK_PADDED_SEQUENCE-CSDN博客 当使用pack_padded_sequence得到一个PackedSequence对象并将其送入RNN(如LSTM或GRU)时,RNN内部会进行特定的操作来处理这种特殊的输入形式。 使用PackedSequ…...
C#WPF工具提示(ToolTip)实例
本文演示C#WPF工具提示(ToolTip)实例 ToolTip ToolTip是当鼠标移到某个控件上后可以弹出提示的控件 属性说明 1、HasDropShadow 决定工具提示是否具有扩散的黑色阴影,使其和背后的窗口区别开来 2、Placement 使用PlacementMode枚举值决定如何放置工具提示。默认值是M…...

智慧矿山系统中的猴车安全监测与识别
智慧矿山是近年来兴起的一种采用人工智能(AI)技术的矿山管理方式,它通过利用智能传感设备和先进算法来实现对矿山环境和设备进行监测和管理,从而提高矿山的安全性和效率。在智慧矿山的AI算法系列中,猴车不安全行为识别…...

网络协议--TCP连接的建立与终止
18.1 引言 TCP是一个面向连接的协议。无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。本章将详细讨论一个TCP连接是如何建立的以及通信结束后是如何终止的。 这种两端间连接的建立与无连接协议如UDP不同。我们在第11章看到一端使用UDP向另一端发…...

react条件渲染
目录 前言 1. 使用if语句 2. 使用三元表达式 3. 使用逻辑与操作符 列表渲染 最佳实践和注意事项 1. 使用合适的条件判断 2. 提取重复的逻辑 3. 使用适当的key属性 总结 前言 在React中,条件渲染指的是根据某个条件来决定是否渲染特定的组件或元素。这在构…...
Docker中Failed to initialize NVML: Unknown Error
参考资料 Docker 中无法使用 GPU 时该怎么办(无法初始化 NVML:未知错误) SOLVED Docker with GPU: “Failed to initialize NVML: Unknown Error” 解决方案需要的条件: 需要在服务器上docker的admin list之中. 不需要服务器整体的admin权限.…...

学习笔记|单样本秩和检验|假设检验摘要|Wilcoxon符号检验|规范表达|《小白爱上SPSS》课程:SPSS第十一讲 | 单样本秩和检验如何做?很轻松!
目录 学习目的软件版本原始文档单样本秩和检验一、实战案例二、统计策略三、SPSS操作1、正态性检验2.单样本秩和检验 四、结果解读第一,假设检验摘要第二,Wilcoxon符号检验结果摘要。第三,Wilcoxon符号秩检验图第四,数…...
ttkefu在线客服在客户联络领域的价值
随着互联网的快速发展,越来越多的企业开始注重在线客服的应用。ttkefu作为一款智能在线客服系统,在客户联络领域中展现出了巨大的价值。本文将详细介绍ttkefu在线客服在客户联络领域的应用优势、专家分析以及未来发展趋势。 一、ttkefu在线客服简介 tt…...

创新方案|2023如何用5种新形式重塑疫后实体门店体验
在电商盛行的当下,线上购物已成为新零售的重要组成部分,实体零售业正处于两难境地。一方面,实体零售是绝对有必要的:美国约 85% 的销售额来自实体商店。 另一方面,尽管增长放缓,但电商收入占销售总额的比例…...

Aqua Data Studio 2023.1
为什么选择 Aqua Data Studio? 随着数据在业务中的作用不断发展,组织需要一种有效的方法来简化复杂的技术任务并缩小 IT 和业务团队之间的差距。 使用多个数据库平台不再复杂。使用 Aqua Data Studio 简化您的所有数据管理流程和任务:这是一…...

【C++智能指针】
智能指针 为什么使用智能指针?概念分类auto_ptrunique_ptrshared_ptr循环引用weak_ptr 为什么使用智能指针? 考虑以下场景: void div() {int a, b;cin >> a >> b;if (b 0)throw invalid_argument("除0错误");return…...

gcc/g++使用格式+各种选项,预处理/编译(分析树,编译优化,生成目标代码)/汇编/链接过程(函数库,动态链接)
目录 gcc/g--编译器 介绍 使用格式 通用选项 编译选项 链接选项 程序编译过程 预处理(宏替换) 编译 (生成汇编) 分析树(parse tree) 编译优化 删除死代码 寄存器分配和调度 强度削弱 内联函数 生成目标代码 汇编 (生成二进制代码) 链接(生成可执行文件) 函…...

OSPF复习(2)
目录 一、LSA的头部 二、6种类型的LSA(课堂演示) 1、type1-LSA:----重要且复杂 2、type2-LSA: 3、type3-LSA: 4、type4-LSA: 5、type5-LSA: 6、type7-LSA: 三、OSPF的网络类…...

FPGA时序分析与约束(9)——主时钟约束
一、时序约束 时序引擎能够正确分析4种时序路径的前提是,用户已经进行了正确的时序约束。时序约束本质上就是告知时序引擎一些进行时序分析所必要的信息,这些信息只能由用户主动告知,时序引擎对有些信息可以自动推断,但是推断得到…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...