数据结构课程设计——用户管理系统

涉及到的东西:MFC,file,AVL;
作为一名初学者,记录一下这个学期的数据结构的课程设计;先上任务书要求。
1.【问题描述】:
在登录服务器系统时,都需要验证用户名和密码,如 telnet 远程登录服务器。
用户输入用户名和密码后,服务器程序会首先验证用户信息的合法性。由于用户信息的验证
频率很高,系统有必要有效地组织这些用户信息,从而快速查找和验证用户。另外,系统也
会经常会添加新用户、删除老用户和更新用户密码等操作,因此,系统必须采用动态结构,
在添加、删除或更新后,依然能保证验证过程的快速。请采用相应的数据结构模拟用户登录
系统,其功能要求包括用户登录、用户密码更新、用户添加和用户删除等。
2.【基本要求】:

  1. 要求自己编程实现二叉树结构及其相关功能,以存储用户信息,不允许使用标准模板类
    的二叉树结构和函数。同时要求根据二叉树的变化情况,进行相应的平衡操作,即 AVL
    平衡树操作,四种平衡操作都必须考虑。测试时,各种情况都需要测试,并附上测试截
    图;
  2. 要求采用类的设计思路,不允许出现类以外的函数定义,但允许友元函数。主函数中只
    能出现类的成员函数的调用,不允许出现对其它函数的调用。
  3. 要求采用多文件方式:.h 文件存储类的声明,.cpp 文件存储类的实现,主函数 main 存
    储在另外一个单独的 cpp 文件中。如果采用类模板,则类的声明和实现都放在.h 文件中。
  4. 不强制要求采用类模板,也不要求采用可视化窗口;要求源程序中有相应注释;
  5. 要求测试例子要比较详尽,各种极限情况也要考虑到,测试的输出信息要详细易懂,表
    明各个功能的执行正确;
  6. 建议采用 Visual C++ 6.0 及以上版本进行调试;

简单的说就是三点1.实现平衡二叉树的操作;2.文件读写;3.登陆界面的设计;

1.平衡二叉树的实现

原理不过多赘述,直接写关键函数;关于AVL树的关键函数有更新树的高度,以及四种旋转的操作;
1.LL(左单旋)

template<typename T>
binnode<T>*AVL<T>::LL(binnode<T>*ptr) {binnode<T>*tmp = ptr->right;
//将传进来的结点的右结点进行旋转操作;ptr->right = tmp->left;//将其tmp的左子树挂在传ptr的右子树上tmp->left = ptr;//将ptr做为tmp的左子树挂上去ptr->height = getheight(ptr->left) > getheight(ptr->right) ? getheight(ptr->left)+1 : getheight(ptr->right)+1;//更新树高的函数在后面解释tmp->height = getheight(tmp->left) > ptr->height ? getheight(tmp->left) + 1 : ptr->height + 1;return tmp;//返回旋转之后的根结点;}

左单旋图示:

2.RR旋转(右单旋)

template<typename T>
binnode<T>* AVL<T>::RR(binnode<T>*ptr) {binnode<T>*tmp = ptr->left;//tmp是ptr的左子女ptr->left = tmp->right;//将tmp的右子树挂在ptr的左子树上tmp->right = ptr;//将ptr作为子树挂在tmp的右子树上;ptr->height = getheight(ptr->left) > getheight(ptr->right) ? getheight(ptr->left)+1 : getheight(ptr->right)+1;//更新树高tmp->height = getheight(tmp->left) > ptr->height ? getheight(tmp->left) + 1 : ptr->height + 1;return tmp;//返回现在的根结点;
}

右单旋图示:

3.左右双旋(LR):麻烦结点出现在不平衡结点的左子树的右子树上;

template<typename T>
binnode<T>*AVL<T>::LR(binnode<T>*ptr) {ptr->left = LL(ptr->left);//先对ptr的左结点进行左旋return RR(ptr);//在对ptr进行右旋并返回;//可以将双旋看成是两次单旋;}

左右双旋图示:

4.右左双旋(RL):麻烦结点出现在不平衡结点的右子树的左子树上时;

template<typename T>
binnode<T>*AVL<T>::RL(binnode<T>*ptr) {//同上可以将其分解成两次双旋的过程;ptr->right= RR(ptr->right);//对右子女进行右旋return LL(ptr);//对其左旋;
}

右左双旋图示:

5.插入函数:对于要插入的结点,先对AVL树进行查找,若找到了则不插入,若没找到进行插入,(注意AVL是排序树所以插入的操作与BST树插入的操作相似,只不过多了一个更新树的高度的操作);

template<typename T>
void AVL<T>::insert( binnode<T>* &ptr, const T &item) {if (ptr==NULL){ptr = new binnode<T>();//当ptr为NULL时,证明该中没有要插入的结点,所以要进行插入操作;ptr->data = item;ptr->height=1;//将树的高度置为1;ptr->left = ptr->right = NULL;//左右子树置空;}else if (item<ptr->data){insert(ptr->left, item);//递归插入左子树if (getheight(ptr->left)-getheight(ptr->right)==2){//发生不平衡时,因为是在左子树上是进行操作,所以只存在左子树高于右子树;if (item<ptr->left->data){//当插入的结点构成了RR不平衡,即麻烦结点在不平衡结点的左子树的左子树上时;ptr = RR(ptr);//右旋  }else {ptr = LR(ptr);//若构成了LR不平衡,左旋;}}}else if (item > ptr->data) {//对于右子树的操作同左子树;insert(ptr->right, item);if (getheight(ptr->left)-getheight(ptr->right)==-2){if (item > ptr->right->data) {ptr = LL(ptr);}else {ptr = RL(ptr);}}}else{cerr << "树中已存在该项,插入失败";return;}ptr->height=getheight(ptr->left) > getheight(ptr->right) ? getheight(ptr->left) +1: getheight(ptr->right)+1;
//在函数最后需要更新树高;
}

6.删除函数:同BST树的删除,需要分三种情况,且注意平衡情况;代码如下:

template <typename T>
void AVL<T>::remove(binnode<T>*&ptr, const T &item) {//操作与插入相似,但是删除的时候需要分左右子树都存在,或者都不存在,或只存在一个
//不赘述了;if (ptr == NULL) {return;}else {if (item < ptr->data) {remove(ptr->left, item);if (getheight(ptr->right) - getheight(ptr->left) > 1) {if (getheight(ptr->right->left) > getheight(ptr->right->left)) {ptr = RL(ptr);}else {ptr = LL(ptr);}}else {ptr->height = getheight(ptr->left) > getheight(ptr->right) ? getheight(ptr->left) + 1 : getheight(ptr->right) + 1;}}else if (item > ptr->data) {remove(ptr->right, item);if (getheight(ptr->left) - getheight(ptr->right) > 1) {if (getheight(ptr->left->right) > getheight(ptr->left->left)) {ptr = LR(ptr);}else {ptr = RR(ptr);}}else{ptr->height = getheight(ptr->left) > getheight(ptr->right) ? getheight(ptr->left) + 1 : getheight(ptr->right) + 1;}}else {if (ptr->left != NULL && ptr->right != NULL) {if (getheight(ptr->left) > getheight(ptr->right)) {binnode<T>*tmp = ptr->left;while (tmp->right != NULL) {tmp = tmp->right;}ptr->data = tmp->data;remove(ptr->left, ptr->data);}else {binnode<T>*tmp = ptr->right;while (tmp->left != NULL) {tmp = tmp->left;}ptr->data = tmp->data;remove(ptr->right, ptr->data);}}else {binnode<T>*tmp = ptr;if (ptr->left != NULL) {ptr = ptr->left;}else {ptr = ptr->right;}delete  tmp;}}}}

7.树高更新:在node结点中加入数据height用来记录当前结点的树的高度;

template<typename T>
class binnode {public:T data;binnode*left;binnode*right;int  height;//记录树的高度;};

获取树高的函数get_height

template<typename T>
int AVL<T>::getheight(binnode<T>*p) {if (p == NULL) {int a = 0;return a;}else{return p->height;//对于非空结点直接访问其树高即可;}}

用户界面设计(MFC库)

在这次作业中使用了MFC(VS中可以下载)做用户的界面;先上成果图在一步步解释;

界面由密码输入框,用户名输入框,和四个控件组成;
1.新建一个MFC对话框;

在VS的新建中选择MFC应用程序,没有的朋友们可以自己去扩展程序中下载;打开后选择基于对话框然后一直下一步就好了;

接着就会来到像下面图片一样的界面
在左边的工具栏中添加相关控件;添加完之后我们需要对对话框进行一个添加类的操作,以及对相关控件进行添加变量的操作;(目的是为了是他们能够被正常的调用和程序关联起来);
1.添加类(1)右击对话框,添加类;之后会自动生成一个.h的头文件;(2)添加变量:右击相关控件,添加变量,对变量进行命名;
2.相关控件的编程:以登陆按钮为例子,添加变量之后,双击登陆按钮;会进入刚刚添加的类中,将头文件包括进来;


#include "stdafx.h"
#include "classwork.h"
#include "CDia.h"//刚刚添加的文件,将其include进来;
#include "afxdialogex.h"
#include "AVL.h"//将写好的AVL树头文件include进来,并根据文件内容初始化一颗树

双击登陆之后会得到自动跳到对该控件的编写之中;

void CclassworkDlg::OnBnClickedButton1()
{      //登陆按钮的实现。UpdateData(true);//获取最新的用户名和密码输入框中的值if (user_name.IsEmpty()) {//User_name是添加的用户名变量;MessageBox(_T("登陆失败,用户名不能为空"));return;//当用户名为空时,返回;}string str2 = CW2A(user_name.GetString());
//由于用户输入框的类型时cstring 类型的所以需要将其转化为string类型;
//使用CW2A将CSstring 转化为string类型。if (t.search(str2)) {//在树中查找给定的用户名,调用树中的查找函数(本文章中并没有写出)//查找函数若成功找到返回true,未能找到返回false;string str1 = CW2A(user_pwd.GetString());//若找到了,将输入框中的值,赋给str1;if (f.search(str2)==str1) {//调用File类查找功能并且返回密码进行对比//flie类中的查找功能根据用户名在文件中进行查找,若找到则返回密码;//若密码相符,则弹出登陆成功;MessageBox(_T("登陆成功!欢迎你!"));}else {MessageBox(_T("登陆失败,密码错误"));}}else {MessageBox(_T("登陆失败,用户名不存在"));}
}

其他控件写法类似不过多赘述;

file文件类(读写)

需要实现的目的:根据文件中的内容返回其密码等;

class file{public:void Insert(string name,string pwd);//向文本中插入新用户void remove(string name);//删除文本中的指定用户string search(string name);//根据查找的用户名返回密码;private:fstream f;
};

插入函数:

void file::Insert(string name,string pwd){if(search(name)!="-1"){return;}f.open("1.txt",ios::app|ios::out);f<<name<<" "<<pwd<<endl;f.close();
}

删除函数:首先,因为flie没有办法删除指定的内容,所以想法就是将文本中的内容先选择性保存起来,再重新写入;代码如下;

void file::remove(string name){fstream tmpf; tmpf.open("2.txt",ios::out|ios::trunc);f.open("1.txt",ios::in); while(1){string str1,str2;f>>str1>>str2;if(str1!=name){    tmpf<<str1<<" "<<str2<<endl;}if(f.eof()){break; }}  f.close();tmpf.close();tmpf.open("2.txt",ios::in);f.open("1.txt",ios::out|ios::trunc) ;while(1){string str1,str2;tmpf>>str1>>str2;f<<str1<<" "<<str2<<endl;if(tmpf.eof()){break;}   } tmpf.close() ;tmpf.open("2.txt",ios::trunc|ios::out);tmpf.close();f.close();
}

查找函数:对给定的用户名进行查找,并且返回密码;

string file::search(string name){f.open("1.txt",ios::in);while(1){string str,str2;f>>str>>str2;if(name==str){f.close();return str2;}else if(f.eof()){f.close();break;}} f.close();return "-1";//用-1作为特殊值;}

以上就是大概的这次课程设计的内容了,经过老师的指正后发现了一些错误,比如登陆控件的查找中,应该是对AVL树的查找和删除,文件流只提供读写的操作等;以上只是一些关键函数的实现;并非完整的代码,能力有限,希望大佬指点,这学期刚转的计算机专业,还是个菜鸟(记录自己的成长~~),欢迎大家指点呀~~;如果想要完整代码的可以私信我;(介于很多朋友私信我要代码,我已经把代码上传到了github上面以免我回复不及时。github地址能点两个星嘛再好不过。不点嘛也就算了。祝大家学业有成!!
//如果对AVL树的操作还有问题的可以参照一下《数据结构第二版》陈越老师的这本书(书上解析更详细)

数据结构——用户登陆系统相关推荐

  1. Centos系统创建用户oracle后,用该用户登陆系统,页面加载报错GConf error

    Linux 的 GConf error 解决办法 问题: Centos系统创建用户oracle后,用该用户登陆系统,页面加载报错,导致重新进入Centos系统后出现: GConf error:Fail ...

  2. 计算机用户无法加载配置文件,用户登陆系统时提示无法加载用户配置文件

    一.问题表现现象: 用户无法加载桌面,提示无法加载用户桌面或者正在使用临时配置文件登陆. 二.解决方法. 1.打开注册表编辑器(registry editor),找到一下路径的注册表值:HKEY_LO ...

  3. python之for循环使用(奇数和、偶数和、最大公因数和最小公倍数、用户登陆系统)

    需要知道 有关range: >>> range(5)[0, 1, 2, 3, 4]>>> range(7)[0, 1, 2, 3, 4, 5, 6]>> ...

  4. linux 普通用户登陆系统su - root的时候报错su: Authentication failure

    今天登陆服务器的时候,需要提权做一些操作,普通用户su - root的时候提示密码错误 [xtwh@jmw8a2003 ~]$ su Password: su: Authentication fail ...

  5. windows无法连接到group policy client服务.此问题阻止标准用户登陆系统.

    问题描述如图: 解决: 1.win+R 输入 regedit,打开注册表编辑器 2.对上图区域右键->权限 3.选定你的用户,点添加->高级->立即查找 4.找到SYSTEM,点击确 ...

  6. JSP 登陆系统 登陆界面/处理界面/成功界面/失败界面/注销界面(无数据库版) 包含源文件分享

    陆系统设计 1.程序要求: 完成用户登陆功能. 用户名及密码保存在程序之中完成验证,通过则表示用户为合法用户,跳转到登陆成功页,否则表示用户名或密码不正确,跳转到登陆失败页. 2.输出页面: 2.1. ...

  7. springboot整合mybaits-plusmybaits实现用户登陆界面(适合入门)+唯美界面

    springboot整合mybaits-plus/mybaits实现用户登陆界面(一步步解析)+唯美界面 文章目录 springboot整合mybaits-plus/mybaits实现用户登陆界面(一 ...

  8. 只在用户登陆时运行_linux 系统的7个运行级别

    一.Linux的运行级别(runlevel) 二.运行级别的原理 1.在目录/etc/rc.d/init.d下有许多服务器脚本程序,一般称为服务(service) 2.在/etc/rc.d下有7个名为 ...

  9. 查看登陆系统用户的信息的三种方法详解

    查看登陆系统用户的信息的三种方法详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.who这个命令显示可以谁在登陆,但是这个有很多的花式玩法,这个命令超简单 语法:who [O ...

最新文章

  1. 三级下拉框连动的数据库版
  2. PLSQL_海量数据处理系列3_索引
  3. 【VC基础】3、配置参数文件
  4. introduction to mechanism
  5. C#中二进制和流之间的各种相互转换
  6. 任务管理平台_软件品质评测系统任务分发管理平台
  7. Elasticsearch 5.6.5 安装head插件
  8. 2020年7月4日 随机过程大作业
  9. 图像均值滤波简介及实现
  10. 入门佳作《例解Python》来了!案例丰富尽显风度ƪ(´▽`ƪ)
  11. 服务器部署Nodejs api 接口
  12. 基于搜狗平台的微信文章爬虫
  13. 马原复习思维导图-前三章
  14. 算术平均数、几何平均数、调和平均数的、标准差、方差、正态分布、异常值噪声处理
  15. 贪心算法-2.找钱问题
  16. 基于GitHub的敏捷学习方法之道与术
  17. Android中连接MQTT服务器实现订阅主题并接收消息推送在通知栏显示(附代码下载)
  18. IBMV7000存储电源模块PSU报错“Power Supply Fault type 2“
  19. 【优化规划】基于matlab禁忌搜索算法求解配电网无功补偿优化规划问题【含Matlab源码 1842期】
  20. Oracle中coalesce函数的用法

热门文章

  1. 使用UltraISO(软碟通)制作系统盘 / U盘启动-linux版、 双系统的运行
  2. 【uniapp】【QA】
  3. Ubuntu22.04右上角网络图标消失
  4. EtherCAT主站SOEM —— 分布式时钟(Distributed Clock)抓包分析
  5. MDIO: Management Data Input/Output
  6. amtisy带你暴炒基金Action-Two:选基金
  7. 【工具】监听手机短信转发到群聊或服务器
  8. 图像篡改数据集CASIA 1.0分享 001
  9. Scrapy问题总结
  10. MapStruct分析