数据结构项目设计

                         项目名称:ATM账户存取业务

1.项目介绍

1.1意义

ATM账户系统采用哈希表这种高效数据结构,可以快速读取后台用户信息文件,通过判断用户的卡号和密码匹配,方便了管理用户的账户信息,提高了账户信息的安全性和可管理性,让使用者轻松实现账户的信息修改、销户、存取业务和查询等操作,避免人工进行操作,提高银行存取款业务,并且可在用户操作完成后,重新读取哈希表数据并写入后台用户信息文件,而不需要手动进行复杂的管理工作。

1.2主要内容

用户管理系统是一个基于哈希表的数据结构的应用程序,用于管理用户账户。该系统可以执行以下操作:

  1. 新用户注册
  2. 老用户登录
    • 销户
    • 查找用户
    • 修改用户信息
    • 用户存取业务

2.概要设计

思路:该系统使用哈希表作为主要数据结构,可以实现快速登录、查找、修改和删除操作,使得用户账户的管理变得高效和方便。

哈希表采用链式哈希法来解决哈希冲突。在链式哈希法中,每个用户都是一个链表,当哈希冲突发生时,相同哈希值的键值对会以头插法的方式添加到相应的链表中。

 

项目流程图

3.数据结构

4.具体算法

该系统使用以下算法来实现创建哈希表、从文件中导入用户信息到Hash表,注册新用户、老用户销户、修改老用户信息、老用户进行存取业务,导出Hash表中用户信息至文件、和销毁哈希表的功能。

4.1创建哈希表

函数功能:创建哈希表

参数:无

返回值:返回定义好的哈希表
注意点:Hash表中数组元素的个数是采用宏定义

源码为:

Hash* creat_Hash()

{

       //定义一个Hash表指针

       Hash *pHash=(Hash *)malloc(sizeof(Hash));

       if(NULL==pHash)

       {

              perror("Malloc_ERR");

              return NULL;

       }

       //赋值

       //Hash表中数组中各元素的数据类型为节点

       pHash->arr=(Link **)malloc((sizeof(Link*))*SIZE);

       if(NULL==pHash->arr)

       {

              perror("Malloc_ERR");

              return NULL;

      

       }

       memset(pHash->arr,0,(sizeof(Link*))*SIZE);

       pHash->count=SIZE; //Hash表中数组个数值采用宏定义

       return pHash;

}

4.2从文件中导入用户信息

//函数功能:从文件中读取储户信息

//参数1:Hash表首地址 Hash *pHash

//返回值:成功返回OK,失败返回失败原因

算法思路:打开文件,创建储户结构体数据类型,读取文件中储户的信息,调用Add函数添加到Hash表内存中

源码为:

int Load_Depositor(Hash *pHash)

{

       Dep person={{0},0,0,{0}};//接受读取到的储户信息

       //入参检查

       if(NULL==pHash)

       {

              return Hash_NO_EXIST;

       }

       //打开文件读取信息

       FILE *FR=fopen("user_message.txt","r");

       if(NULL==FR)

       {

              return File_NO_EXIST;

       }

       while(!feof(FR))

       {

              if(fscanf(FR,"%s%d%lf%s",person.name, \

                                   &person.card, \

                                   &person.balance,person.pwd)!=EOF)//读取数据

              {

                     Add_Depositor(pHash,person);

              }

       }//信息插入到Hash表中

       fclose(FR);

       return OK;

      

}

4.3添加用户

函数功能:用户登陆

参数1:Hash表中首地址 Hash *pHash

参数2:要插入的储户 Dep New_dep;

返回值:成功返回OK,失败返回失败原因

算法思路:调用Search 函数判断插入的储户结构体是否存在,不存在则申请节点空间保存储户结构体信息,调用Hashfun得出Hash表中对应的数组下标,采用头插法将节点插入Hash表中。

源码如下:

int Add_Depositor(Hash*pHash,Dep New_dep)

{

       //入参判断

       if(NULL==pHash)

       {

              return Hash_NO_EXIST;

       }

       //调用Serch_Depositor函数查找是否存在

       Link* pRet=Search_Depositor(pHash,New_dep);

       //若不存在,创建新结点赋值,并插入

       if(NULL!=pRet)

       {

              printf("储户已存在,无须再新增!!\n");

              return Dep_EXSIT;

       }

       //创建新结点,判断,赋值

       Link *pNew=(Link *)malloc(sizeof(Link));

       if(NULL==pNew)

       {

              return Malloc_ERR;

       }

       memset(pNew,0,sizeof(Link));

       pNew->person=New_dep;

       //调用Hashfun()函数得出数组下标

       int pos=Hashfun(New_dep.card);

       //插入新结点

       pNew->pNext=pHash->arr[pos];

       pHash->arr[pos]=pNew;

       return OK;

}

4.4判断老用户是否存在

函数功能:  通过卡号密码查询保存用户信息的节点

参数1:Hash表首地址 Hash *pHash

参数2:储户类型Dep* pOld_user

返回值:成功返回储户结点首地址   失败返回NULL

算法思路:search得出银行卡号得出Hash表中对应的节点,节点确定后进一步匹配储户输入的密码,来最终确定储户节点;

#include"../include/Bank.h"

//返回值:老用户存在的结点Link *pRet

Link * determine_Olduser(Hash *pHash,Dep* pOld_user)

{

      Link *pRet=NULL;

      char cc[20]={0};

      //调用Search_Depositor 查找用户结点

      while(1)

      {

             printf("请输入登录账号:");

             scanf("%d",&(pOld_user->card));

             pRet=Search_Depositor(pHash,*pOld_user);

             if(NULL==pRet)//用户不存在

             {

                    printf("用户不存在!\n");

                    printf("是否重新输入?  是:Y  否:N\n");

                    scanf("%s",cc);

                    //结点不存在判断是否结束还是重新输入

                    if(0==strcmp(cc,"Y")||0==strcmp(cc,"y"))

                    {

                           continue;

                    }

                    else if(0==strcmp(cc,"N")||0==strcmp(cc,"n"))

                    {

                           break;

                    }

                    else

                    {

                           printf("指令有误!!\n");

                           return NULL;

                    }

             }

             else

             {

     

                    printf("请输入登录密码:");

                    scanf("%s",pOld_user->pwd);

                    if(0==strcmp(pOld_user->pwd,pRet->person.pwd))

                    {

                           printf("登录成功!!\n");

                           break;

                    }

                    else//密码错误

                    {

                           printf("密码错误!!\n");

                           printf("是否重新输入?  是:Y  否:N\n");

                           scanf("%s",cc);

                           if(0==strcmp(cc,"Y")||0==strcmp(cc,"y"))

                           {

                                  continue;

                           }

                           else if(0==strcmp(cc,"N")||0==strcmp(cc,"n"))

                           {

                                  pRet=NULL;

                                  break;

                           }

                           else

                           {

                                  printf("指令有误!!\n");

                                  return NULL;

                           }

                    }

             }

             break;

      }

      return pRet;

      //找到结点返回

}

4.5修改老用户信息

函数功能:通过执行选项来修改人员信息

参数1:Hash表首地址 Hash *pHash

参数2: 老储户数据类型 Dep

返回值:成功返回OK,失败返回失败原因

算法思路:调用Search函数找到储户节点下标,在选择修改用户具体信息

int modify(Hash *pHash,Dep Old_user)

{

       int put=0;//决定取钱还是存钱

       char  New_name[50]={0};//要修改的名字

       char  New_pwd[50]={0};//要修改的密码

       char  cc[100]={0};;//接收是否继续存储

       //入参判断

       if(    NULL== pHash)

       {

              return Hash_NO_EXIST;

       }

       //调用Search_Depositor函数寻找目标姓名

       Link *pRet=Search_Depositor(pHash,Old_user);

       //目标不存在直接返回

       if(NULL==pRet)

       {

              return Dep_NO_EXIST;

       }

       //目标存在执行存取操作

       while(1)

       {

              printf("选择你要修改的信息:\n");

              printf("1:姓名  2:密码\n");

              scanf("%d",&put);

              if(put!=1&&put!=2)

              {

                     printf("操作有误,请重新输入");

                     continue;

              }

              break;

       }

       switch(put)

       {

              case 1://修改姓名

                     while(1)

                     {

                            printf("请输入新名字\n");

                            scanf("%s",New_name);

                            printf("修改前名字为:%s\n",pRet->person.name);

                            printf("修改后名字为:%s\n",New_name);

                            printf("请确认是否修改?是:Y 否:N\n");

                            scanf("%s",cc);

                            if(0==strcmp("Y",cc)||0==strcmp("y",cc))

                            {

                                   strcpy(pRet->person.name,New_name);

                                   break;

                            }

                            else if(0==strcmp("N",cc)||0==strcmp("n",cc))

                            {

                                   continue;

                            }

                            else

                            {

                                   printf("指令错误!!\n");

                                   continue;

                            }

                     }

                     break;

              case 2://修改密码

                     while(1)

                     {

                            printf("请输入新密码\n");

                            scanf("%s",New_pwd);

                            printf("修改前密码为:%s\n",pRet->person.pwd);

                            printf("修改后密码为:%s\n",New_pwd);

                            printf("请确认是否修改?是:Y 否:N\n");

                            scanf("%s",cc);

                            if(0==strcmp("Y",cc)||0==strcmp("y",cc))

                            {

                                   strcpy(pRet->person.pwd,New_pwd);

                                   break;

                            }

                            else if(0==strcmp("N",cc)||0==strcmp("n",cc))

                            {

                                   continue;

                            }

                            else

                            {

                                   printf("指令错误!!\n");

                                   continue;

                            }

                     }

                     break;

       }

       return OK;

}

4.5 老用户进行存储业务

#include"../include/Bank.h"

//函数功能:通过执行选项来确定储户存钱还是取钱

//参数1:Hash表首地址 Hash *pHash

//参数3: 老储户 Old_user

//返回值:成功返回OK,失败返回失败原因

int money(Hash *pHash,Dep Old_user)

{

       int put=0;//决定取钱还是存钱

       double amount=0;//存取的金额

       char  cc[100]={0};;//接收是否继续存储

       //入参判断

       if(    NULL== pHash)

       {

              return Hash_NO_EXIST;

       }

       //调用Search_Depositor函数寻找目标姓名

       Link *pRet=Search_Depositor(pHash,Old_user);

       //目标不存在直接返回

       if(NULL==pRet)

       {

              return Dep_NO_EXIST;

       }

       //目标存在执行存取操作

       while(1)

       {

              printf("请输入你想执行的操作:1:存钱  2:取钱\n");

              scanf("%d",&put);

              if(put!=1&&put!=2)

              {

                     printf("操作有误,请重新输入");

                     continue;

              }

              break;

       }

       switch(put)

       {

              case IN://存钱

                     while(1)

                     {

                            printf("请输入你要存的金额\n");

                            scanf("%lf",&amount);

                            pRet->person.balance=pRet->person.balance+amount;

                            printf("是否退出?是:Y 退出:N\n");

                            scanf("%s",cc);

                            if(0==strcmp("Y",cc)||0==strcmp("y",cc))

                            {

                                   break;

                            }

                     }

                     break;

              case OUT://取钱

                     while(1)

                     {

                            printf("请输入你要取的金额\n");

                            scanf("%lf",&amount);

                            if(amount>pRet->person.balance)

                            {

                                   printf("账户余额不足\n");

                                   printf("是否继续?是:Y 否:N\n");

                                   scanf("%s",cc);

                                   if(0==strcmp("Y",cc)||0==strcmp("y",cc))

                                   {

                                          continue;

                                   }

                                   else if(0==strcmp("N",cc)||0==strcmp("n",cc))

                                   {

                                          break;

                                   }

                            }     

                            pRet->person.balance=pRet->person.balance-amount;

                            printf("是否继续?是:yes 退出:no\n");

                            scanf("%s",cc);

                            if(0==strcmp("n",cc)||0==strcmp("N",cc))

                            {

                                   break;

                            }

                            else if(0==strcmp("Y",cc)||0==strcmp("y",cc))

                            {

                                   continue;

                            }

                            else

                            {

                                   printf("指令有误!!\n");

                                   return OK;

                            }

                     }

                     break;

       }

       return OK;

}

4.6 新用户申请注册得到随机三位卡号

函数功能:得到8位随即账号

成功返回ok,失败返回失败原因

注意点:得到的卡号要重新在主函数中调用search函数,已确保没有重复卡号

int get_cardID(int *pcard)

{

      

       *pcard=rand()%(int)(pow(10,3));

       return OK;

}

4.7导出用户信息至文件

遍历整个哈希表,将其中的信息输出至指定文件中, 首先以只写方式打开指定文件,如果不存在就创建一个,每次写入信息时,清空上次的内容。遍历每个结点时,调用fprintf函数将该名用户的信息输出至文件中,末尾加上”\n”,最后关闭文件。

#include"../include/Bank.h"

int export_Depositor(Hash *pHash)

{

       //入参判断

       if(NULL==pHash)

       {

              return Hash_NO_EXIST;

       }

       //打开文件

       FILE *FW=fopen("user_message.txt","w");

       //for循还  写入数据域

       Link *pFind=NULL;

       int i=0;

       for(i=0;i<pHash->count;i++)

       {

              pFind=pHash->arr[i];

              while(pFind!=NULL)

              {

                     fprintf(FW,"%s %d %.2lf %s\n",pFind->person.name,pFind->person.card, \

                                   pFind->person.balance,pFind->person.pwd);

                     pFind=pFind->pNext;

              }

       }

       fclose(FW);

       return OK;

}

4.8销毁整个哈希表

函数功能:销毁整个哈希表

参数:1.哈希表首地址的地址。

返回值:成功返回OK,失败返回失败原因

       哈希表申请的空间释放时,要确保申请每个空间都被释放了。

int destory(Hash **ppHash)

{

       //入参判断

       if(NULL==*ppHash)

       {

              return Hash_NO_EXIST;

       }

       int i=0;

       Link *pDel=NULL;

       //for循环 销毁链表

       for(i=0;i<(*ppHash)->count;i++)

       {

              pDel=(*ppHash)->arr[i];//指针指向数组元素位置

              while(pDel!=NULL)//数组元素不为空时

              {

                     (*ppHash)->arr[i]=pDel->pNext;//保护后结点

                     free(pDel);//释放结点

                     pDel=(*ppHash)->arr[i];//指针重新指向数组元素位置

              }

       }

       //销毁*ppHash->arr

       free((*ppHash)->arr);

      

       //销毁*ppHash

       free(*ppHash);

       return OK;

}

5.调试分析

5.1判断老用户登录

通过卡号查找到用户信息节点后,必须再继续判断输入的密码是否与节点中的密码匹配,如果不进行匹配可能会导致登录错误,防止信息出现混乱。

5.2销毁哈希表出错

销毁哈希表时,应传入存储哈希表地址的地址.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值