基于排序二叉树的身份证管理系统

/****************************************************\


模块名称:
    基于二叉排序树的身份证管理系统
摘要:
(1)能够进行身份证号码及相关信息的录入,相关信息包括姓名、年龄和手机号;
(2)能够快速进行身份证号码的查询,并输出相关信息;
(3)可以修改身份证号码对应的其他信息,如姓名、地址;
(4)可以完成身份证信息的删除。
(5)录入信息可以保存到数据文件中。
(6)可以将文件信息录入到管理系统中
(7)需要做到识别出身份证号码错误、超出规定长度等。

    叶艺衡于2023年5月13日创建本模块
  
\****************************************************/

#include <iostream>
#include <fstream>
#include < sstream >
#include <map>

using namespace std;

// 注册账号
void registerAccount(map<string, string>& accounts)
{
    string username, password;

    cout << "请输入用户名(10位):";
    cin >> username;
    if (username.length() != 10) {
        cout << "该用户名不符合规范,请重新输入!" << endl;
        return registerAccount(accounts);
    }
       
    // 检查用户名是否已经存在
    if (accounts.find(username) != accounts.end()) {
        cout << "该用户名已经存在,请重新输入!" << endl;
        return registerAccount(accounts);
    }

    cout << "请输入密码(10位):";
    cin >> password;
    if (password.length() != 10) {
        cout << "该密码不符合规范,请重新输入!" << endl;
        return registerAccount(accounts);
    }
    // 将账号密码存储到map中
    accounts[username] = password;

    cout << "注册成功!" << endl;
}

// 导出账号密码
void exportAccounts(map<string, string>& accounts)
{
    ofstream outFile("accounts.txt");

    // 将map中的账号密码写入文件
    for (auto it = accounts.begin(); it != accounts.end(); ++it) {
        outFile << it->first << " " << it->second << endl;
    }

    outFile.close();

   
}

// 读取账号密码
void readAccounts(map<string, string>& accounts)
{
    ifstream inFile("accounts.txt");

    // 读取文件中的账号密码,并存储到map中
    string username, password;
    while (inFile >> username >> password) {
        accounts[username] = password;
    }

    inFile.close();
}

// 验证账号密码
bool verifyAccount(map<string, string>& accounts, string username, string password)
{
    // 检查用户名是否存在
    if (accounts.find(username) == accounts.end()) {
        cout << "用户名不存在,请重新输入!" << endl;
        return false;
    }

    // 比较输入的密码和map中存储的密码是否一致
    if (accounts[username] != password) {
        cout << "密码错误,请重新输入!" << endl;
        return false;
    }

    // 验证通过
    return true;
}

// 登录账号
void loginAccount(map<string, string>& accounts)
{
    string username, password;

    cout << "请输入用户名:";
    cin >> username;

    cout << "请输入密码:";
    cin >> password;

    if (verifyAccount(accounts, username, password)) {
        cout << "登录成功!" << endl;
    }
    else {
        
        loginAccount(accounts);
    }
}


struct IDCard {
    string id;
    string name;
    string age;
    string time;
};
struct BSTNode {
    IDCard data;
    BSTNode* left;
    BSTNode* right;
    BSTNode* parent;
    int balanceFactor;
    
};


/***********************************************\
函数名称:creatBST

功能描述:创建一个新的二叉排序树节点

函数参数:
data:要插入的IDCard数据

返回值:
返回一个新创建的BSTNode节点,如果创建失败则返回nullptr

模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/
BSTNode* creatBST(IDCard data) {// 创建一个新的二叉排序树节点
    BSTNode* node = new BSTNode;
    node->data = data;
    node->left = nullptr;
    node->right = nullptr;
    return node;

}

/***********************************************\
函数名称:insertBST

功能描述:将一个IDCard插入到二叉搜索树中

函数参数:
IDCard data: 要插入的IDCard数据
BSTNode* node: 当前操作的BSTNode指针

返回值:BSTNode*: 返回操作后的BSTNode指针

模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/

BSTNode* insertBST(IDCard data, BSTNode* node) {
    if (node == nullptr) {
        node = creatBST(data);
    }
    else if (data.id < node->data.id) {
        node->left = insertBST(data, node->left);
    }
    else if (data.id > node->data.id) {
        node->right = insertBST(data, node->right);
    }
    return node;
}
/***********************************************\
函数名称:findMinNode

功能描述:在二叉搜索树中查找最小结点

函数参数:
BSTNode* node:指向当前二叉搜索树的指针,用于查找最小结点

返回值:
BSTNode*:返回查找到的最小结点的指针


模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/

/*查找最小结点,用于后续删除算法时如果有左右子树,
找到其右子树中的最小结点替换其值*/
BSTNode* findMinNode(BSTNode* node) {
    while (node->left != nullptr) {
        node = node->left;
    }
    return node;
}
/***********************************************\

函数名称: deleteBST
功能描述: 在二叉搜索树中删除指定的数据,并返回根节点指针
函数参数:
node: 当前递归处理的二叉搜索树节点指针
data: 待删除的数据
返回值:
返回删除操作后的二叉搜索树的根节点指针

模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/

BSTNode* deleteBST(BSTNode* node, IDCard data) {
    if (node == nullptr) {
        return nullptr;
    }
    //递归,查找需要删除的结点
    if (data.id < node->data.id) {
        node->left = deleteBST(node->left, data);
    }
    else if (data.id > node->data.id) {
        node->right = deleteBST(node->right, data);
    }
    else {
        // 找到要删除的结点
        if (node->left == nullptr && node->right == nullptr) {
            // 如果是叶子结点,直接删除
            delete node;
            node = nullptr;
        }
        else if (node->left == nullptr) {
            // 如果只有右子树,将其右子树移至删除结点的位置
            BSTNode* temp = node;
            node = node->right;
            delete temp;
        }
        else if (node->right == nullptr) {
            // 如果只有左子树,将其左子树移至删除结点的位置
            BSTNode* temp = node;
            node = node->left;
            delete temp;
        }
        else {
            // 如果有左右子树,找到其右子树中的最小结点替换其值
            BSTNode* minNode = findMinNode(node->right);
            node->data.id = minNode->data.id;
            node->right = deleteBST(node->right, minNode->data);
        }
    }
    return node;
}
int getHeight(BSTNode* node) {
    if (node == nullptr) {
        return 0;
    }
    int leftHeight = getHeight(node->left);
    int rightHeight = getHeight(node->right);
    return max(leftHeight, rightHeight) + 1;
}
//计算平衡因子(-1,0,1),并将其作为结果返回
int getBalanceFactor(BSTNode* node) {
    int leftHeight = getHeight(node->left);
    int rightHeight = getHeight(node->right);
    return rightHeight - leftHeight;
}

// 更新BST结构并更新压缩路径信息
BSTNode* searchBST(IDCard data, BSTNode* node);

void updateBST(IDCard data, BSTNode* node) {
    BSTNode* p = searchBST(data, node);
    if (p == nullptr) return;

    // 更新节点数据
    p->data = data;

    // 更新左子树和右子树
    BSTNode* left = p->left;
    BSTNode* right = p->right;
    p->left = nullptr;
    p->right = nullptr;
    insertBST(data, node->left);
    insertBST(data, node->right);

    // 更新父节点
    BSTNode* parent = p->parent;
    if (parent != nullptr) {
        if (parent->left == p) {
            parent->left = left != nullptr ? left : right;
        }
        else {
            parent->right = left != nullptr ? left : right;
        }
    }
    else {
        node = left != nullptr ? left : right;
    }

    // 更新所有受影响的节点的压缩路径信息
    while (parent != nullptr) {
        parent->balanceFactor = getBalanceFactor(parent);
        parent = parent->parent;
    }
}

/***********************************************\

函数名称: whether_choose

功能描述:让用户选择是否继续使用该系统
函数参数:

choose:选择

返回值: choose

模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/


void isTrue(int functionality) {
    switch (functionality) {
    case 1: //判断是否使用
        int choose;
        cout << "\n继续使用:1\n结束使用:0\n请输入您的选择:";
        cin >> choose;
        system("cls");
        if (choose == 0)
            exit(0);
        break;
    case 2: 
        
        
        break;
        // 添加更多功能的判断规定

    default:
        // 未知功能编号,返回false或抛出错误
        break;
    }

    // 默认返回false,可以根据需要进行修改
    
}


/***********************************************\

函数名称: outfiletxt

功能描述: 将二叉搜索树中的 IDCard 数据输出到指定的输出流中。
导出身份证信息,并将导出的文档设置为txt格式,保存在根目录下


函数参数:

node: 当前遍历的二叉搜索树节点。
outfile: 要输出数据的输出流。

返回值: 无返回值。

模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/
BSTNode* searchBST(IDCard data, BSTNode* node);
void modifyBST(IDCard data, BSTNode* node) {
    BSTNode* target = searchBST(data, node );
    if (target== nullptr) {
        cout << "身份证号码不存在" << endl;
        return;
    }
   
    cout << "请输入新的姓名:" << endl;

    cin >> target->data.name;
    
    
    
    bool isValud1 = false;
    while (!isValud1) {
        cout << "请输入年龄:";
        cin >> target->data.age;

        if ((target->data.age.length() == 1 || target->data.age.length() == 2) &&
            isdigit(target->data.age[0]) &&
            (target->data.age.length() == 1 || isdigit(target->data.age[1])) &&
            stoi(target->data.age) >= 0 && stoi(target->data.age) <= 120) {

            // 年龄符合要求,执行相应操作
            isValud1 = true;
        }
        else {
            cout << "您输入的年龄有误" << endl;
        }

    }

    
    bool isValid = false;
    while (!isValid) {

        cout << "请输入新的签发日期(xxxx.xx):" << endl;
        cin >> target->data.time;

        if (target->data.time.length() != 7 ||
            target->data.time[4] != '.' ||
            (target->data.time[5] != '0' && target->data.time[5] != '1') ||
            (target->data.time[5] == '1' && (target->data.time[6] < '0' || target->data.time[6] > '2')) ||
            (target->data.time[5] == '0' && (target->data.time[6] < '0'))
            ) {

            cout << "输入的签发日期格式错误" << endl;
        }
        else {
            isValid = true;

        }
    }
    
    cout << "修改成功!" << endl;
}



void inorderTraversal(BSTNode* node) {
    
    if (node != nullptr) {
        inorderTraversal(node->left);
       
        
        cout << node->data.id<<'\t';
        cout <<node->data.name << '\t';
        cout << node->data.age << '\t';
        cout << node->data.time << '\t';
        cout << endl;
        inorderTraversal(node->right);
    }
}
/***********************************************\
函数名称: outfiletxt

功能描述: 将二叉搜索树中的 IDCard 数据输出到指定的输出流中。
导出身份证信息,并将导出的文档设置为txt格式,保存在根目录下


函数参数:

node: 当前遍历的二叉搜索树节点。
outfile: 要输出数据的输出流。

返回值: 无返回值。

模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/

//将二叉搜索树中每个节点的数据写入到文件中
void outfiletxt(BSTNode* node, ofstream& outfile) {
    //如果当前节点非空
    if (node != nullptr) {
        //遍历左子树
        outfiletxt(node->left, outfile);
        //将当前节点的数据写入文件
        outfile << "姓名:" << node->data.name << "  身份证:" << node->data.id << "  年龄:" << node->data.age<< "  签发日期:" << node->data.time << endl;
        //遍历右子树
        outfiletxt(node->right, outfile);
    }
}

/***********************************************\
函数名称: infiletxt

功能描述: 从指定文件中读取 IDCard 数据,将其插入到二叉搜索树中。

函数参数:

node: 二叉搜索树的根节点指针的引用。
filename: 要读取数据的文件的文件名。

返回值: 无返回值。

模块:
创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/
void infiletxt(BSTNode*& node, const string& filename) {
    //打开指定文件
    ifstream infile(filename);
    //如果文件打开失败
    if (!infile.is_open()) {
        //输出错误信息并返回
        cout << "文件打开失败" << endl;
        return;
    }
    //逐行读取文件
    string line;
   
    while (getline(infile, line)) {
        //使用 stringstream 将一行数据分解为三个字段
        stringstream ss(line);
        string id, name, age, time;
        //在每行中逐句输入身份证号,姓名,年龄,并以逗号作为分隔符
        getline(ss, id, ',');
        getline(ss, name, ',');
        getline(ss, age, ',');
        getline(ss, time, ',');
        //创建一个 IDCard 结构体对象
        IDCard data = { id, name, age,time };
        

        if (data.id.length() != 18 || data.time.length() != 7 || data.time[4] != '.') {
            cout << "(文件中出现格式错误信息,导入中断,请检查......)" << endl;
            return;
           
        }
    
       
        if (searchBST(data, node) != nullptr) {
            cerr << "导入的身份证内容出现重复,导入中断,请检查......";
            return;
        }
        //将该对象插入到二叉搜索树中
        node = insertBST(data, node);
        
    }
    cout << "导入成功!" << endl;
    //关闭文件
    infile.close();
}

/***********************************************\
函数名称: searchBST

功能描述: 在二叉搜索树中查找与给定IDCard数据相匹配的节点。

函数参数:

data: 要查找的IDCard数据。
node: 当前查找的节点。
返回值:

如果找到匹配的节点,则返回该节点。
如果未找到匹配的节点,则返回空指针。
模块:

创建人: 叶艺衡,时间: 2023.5.13
修改人: 叶艺衡,时间: 2023.5.13
\**********************************************/
 BSTNode* searchBST(IDCard data, BSTNode* node) {
    if (node == nullptr || node->data.id == data.id) {
        return node;
    }
    else if (data.id > node->data.id) {
        return searchBST(data, node->right);
    }
    else if (data.id < node->data.id) {
        return searchBST(data, node->left);
    }
    return nullptr;
}
/***********************************************\
函数名称:
    main
功能描述:
    通过主页面上的数字来选择对应的功能

模块  :
    叶艺衡于2023年5月13日创建本模块
    叶艺衡于2023年5月13日修改本模块
    修改原因:增加可读性
\**********************************************/


int main() {
    int choice;
    BSTNode* node = nullptr;
    IDCard data;
   
    int choose = 1;
    map<string, string> accounts;

    // 读取之前导出的账号密码
    readAccounts(accounts);
    while (true) {
        cout << "\n";
        cout << "               ------------------身份证管理系统登录页面-----------------" << endl;

        cout << "                ======================================================" << endl;
        cout << "                =                   1- 注册用户                      =" << endl;
        cout << "                =                   2- 登录账号                      =" << endl;
        cout << "                =                   3- 退出                          =" << endl;
        cout << "                ======================================================" << endl;
        cout << "                  \n请输入你的选择:" << endl;
        cin >> choice;
        switch (choice) {
        case 1:
            registerAccount(accounts);
            exportAccounts(accounts);


            break;


        case 2:
            loginAccount(accounts);
            system("cls");
           



            cout << "\n";
            cout << "               ------------------欢迎来到身份证管理系统-----------------" << endl;
            while (choose == 1) {
                cout << "                                                                      " << endl;
                cout << "                                          主页                        " << endl;
                cout << "                ======================================================" << endl;
                cout << "                =                   1-输入身份证信息                 =" << endl;
                cout << "                =                   2-删除身份证信息                 =" << endl;
                cout << "                =                   3-查找身份证信息                 =" << endl;
                cout << "                =                   4-修改身份证信息                 =" << endl;
                cout << "                =                   5-展示身份证信息                 =" << endl;
                cout << "                =                   6-导出身份证信息                 =" << endl;
                cout << "                =                   7-导入身份证信息                 =" << endl;
                cout << "                =                   8-退出系统                       =" << endl;
                cout << "                ======================================================" << endl;
                cout << "@请输入你的选择:";
                int choice;
                cin >> choice;
                system("cls");
                IDCard data;
                BSTNode* search;
                bool isValid = false;
                bool isValud1 = false;
                switch (choice) {
                case 1:
                    cout << "                ------------------输入身份证信息---------------------" << endl;
                    cout << "请输入身份证号码:";
                    cin >> data.id;
                    if (searchBST(data, node) == nullptr) {
                        if (data.id.length() != 18) {
                            cout << "格式错误\n";
                            isTrue(1);
                            break;
                        }
                        cout << "请输入姓名:";
                        cin >> data.name;
                        while (!isValud1) {
                            cout << "请输入年龄:";
                            cin >> data.age;
                          
                            if ((data.age.length() == 1 || data.age.length() == 2) &&
                                isdigit(data.age[0]) &&
                                (data.age.length() == 1 || isdigit(data.age[1])) &&
                                stoi(data.age) >= 0 && stoi(data.age) <= 100)
                            {
                                isValud1 = true; 
                            }
                            else {
                                cout << "您输入的年龄有误" << endl;
                            }

                        }
                          

                      

                        while (!isValid) {

                            cout << "请输入签发日期(xxxx.xx):";
                            cin >> data.time;

                            if (data.time.length() != 7 ||
                                data.time[4] != '.' ||
                                (data.time[5] != '0' && data.time[5] != '1' ) || 
                                (data.time[5] == '1' && (data.time[6] < '0' || data.time[6] > '2'))||
                                (data.time[5] == '0' && (data.time[6] <= '0' ))
                                ) 
                            {

                                cout << "输入的签发日期格式错误" << endl;
                            }
                            else {
                                isValid = true;

                            }
                        }


                        node = insertBST(data, node);
                        cout << "身份证号码存储成功!\n";
                        isTrue(1);
                    }
                    else {
                        cout << "身份证号码已存在" << endl;
                        isTrue(1);
                    }
                    
                    break;
                case 2:
                    cout << "                ------------------删除身份证信息---------------------" << endl;
                    cout << "请输入要删除的身份证号码:";
                    cin >> data.id;
                    if (data.id.length() != 18) {
                        cout << "格式错误\n";
                        isTrue(1);
                        break;
                    }
                    search = searchBST(data, node);
                    if (search == nullptr) {
                        cout << "身份证号码不存在\n";
                        isTrue(1);
                        break;
                    }
                    node = deleteBST(node, data);
                    cout << "删除成功";
                    updateBST(data, node);
                    isTrue(1);
                    break;
                case 3:
                    cout << "                ------------------查找身份证信息---------------------" << endl;
                    cout << "请输入要查找的身份证号码:";
                    cin >> data.id;
                    search = searchBST(data, node);
                    if (data.id.length() != 18) {
                        cout << "格式错误\n";
                        isTrue(1);
                        break;
                    }
                    if (search == nullptr) {
                        cout << "身份证号码不存在\n";
                        isTrue(1);
                        break;
                    }
                    else {
                        cout << "身份证号码存在\n";
                        
                        cout << "身份证:" << search->data.id << endl;

                        cout << "姓名:" << search->data.name << endl;
                        cout << "年龄:" << search->data.age << endl;
                        cout << "签发日期:" << search->data.time << endl;
                        cout << endl;

                        isTrue(1);
                        break;
                    }
                    if (data.id.length() != 18) {
                        cout << "格式错误\n";
                        isTrue(1);
                        break;
                    }

                case 4:
                    cout << "               ------------------修改身份证信息---------------------" << endl;
                    cout << "请输入要修改的身份证号码:";
                    cin >> data.id;
                    
                    modifyBST(data, node);

                   
                    isTrue(1);
                    break;

                case 5:
                    cout << "                ------------------展示身份证信息---------------------" << endl;
                    cout << "身份证                  姓名   年龄     签发日期:" << endl;
                    inorderTraversal(node);
                    cout << endl;

                    isTrue(1);
                    break;

                case 6:

                {   cout << "                ------------------导出身份证信息---------------------" << endl;
                cout << "               正在导出中,请等待.........." << endl;
                ofstream outfile("person_out.txt");
                if (!outfile.is_open()) {
                    cout << "身份证信息导出失败." << endl;
                    return 1;
                   
                }

                // 中序遍历二叉树,并将结果保存到文件中
                outfiletxt(node, outfile);

                // 关闭输出文件
                outfile.close();
                cout << "身份证信息导出成功!\n";
                isTrue(1);
                break; }


                case 7: {
                    // 从文件导入数据
                    cout << "                ------------------导入身份证信息---------------------" << endl;
                    string filename;
                    cout << "请输入要导入的文件名:";
                    cin >> filename;
                    cout << " 正在导入身份证信息,请等待........" << endl;
                    infiletxt(node, filename);

                    isTrue(1);
                    break;
                }
                case 8:
                    exit(0);
                default:
                    cout << "无效的选择,请重新输入!" << endl;
                    break;

                }
            }
            return 0;



        }
    }
}



使用时要注意几个点:

1.要注意导入文档,要提前在根目录下创建相应名字的txt文档

2.txt文档中要注意删除多余的空格,并按照正确的格式输入各种信息

比如

446666666666666666,王大力,19,2003.08

3.创建过的账号密码会保存在account文档中,下一次也可以使用,不需要重新创建

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值