数据结构大型实验报告-用户登入系统模拟
- 格式:docx
- 大小:211.29 KB
- 文档页数:31
一、实验目的1. 熟悉系统登录流程;2. 掌握常见登录方式;3. 理解安全验证机制;4. 分析登录过程中的风险及防范措施。
二、实验环境1. 操作系统:Windows 10;2. 浏览器:Chrome;3. 实验网站:某知名网站(如:某电商平台、某社交平台等)。
三、实验内容1. 系统登录流程分析;2. 常见登录方式及原理;3. 安全验证机制及风险分析;4. 防范措施。
四、实验步骤1. 打开实验网站,点击“登录”按钮;2. 观察系统登录页面,分析登录流程;3. 尝试使用不同的登录方式(如:账号密码登录、手机短信验证码登录、第三方账号登录等);4. 分析登录过程中的安全验证机制;5. 分析登录过程中的风险及防范措施。
五、实验结果与分析1. 系统登录流程分析以某知名网站为例,登录流程如下:(1)打开网站,点击“登录”按钮;(2)进入登录页面,输入用户名和密码;(3)点击“登录”按钮,系统进行验证;(4)验证成功,进入网站首页;(5)验证失败,提示用户重新输入。
2. 常见登录方式及原理(1)账号密码登录:用户通过输入用户名和密码进行身份验证。
该方式简单易用,但存在密码泄露的风险。
(2)手机短信验证码登录:用户通过手机接收验证码,输入验证码进行身份验证。
该方式较为安全,但存在短信被拦截的风险。
(3)第三方账号登录:用户通过绑定第三方账号(如:QQ、微信等)进行登录。
该方式方便快捷,但存在第三方账号信息泄露的风险。
3. 安全验证机制及风险分析(1)密码加密存储:网站对用户密码进行加密存储,降低密码泄露风险。
(2)验证码验证:通过验证码验证用户身份,防止恶意登录。
(3)登录次数限制:限制用户登录次数,防止暴力破解。
风险分析:(1)密码泄露:用户密码若过于简单或泄露,可能导致账户被盗。
(2)短信拦截:恶意分子拦截用户短信,获取验证码,进行恶意登录。
(3)第三方账号信息泄露:绑定第三方账号后,若第三方账号信息泄露,可能导致账户被盗。
第1篇一、实验目的1. 熟悉登录系统的基本原理和设计流程。
2. 掌握使用常见开发工具进行登录系统设计的方法。
3. 提高编程能力和系统设计能力。
二、实验环境1. 操作系统:Windows 102. 开发工具:Java Web Development Kit (JDK) 1.83. 数据库:MySQL 5.74. 开发环境:Eclipse三、实验内容1. 需求分析2. 系统设计3. 系统实现4. 系统测试四、实验步骤1. 需求分析(1)用户需求登录系统应具备以下功能:1)用户注册:允许用户创建账户,输入用户名、密码、邮箱等基本信息。
2)用户登录:允许用户输入用户名和密码,验证用户身份。
3)找回密码:当用户忘记密码时,提供找回密码功能。
4)注销登录:允许用户退出登录状态。
(2)系统需求1)安全性:系统需保证用户数据的安全,防止数据泄露。
2)易用性:系统界面简洁,操作方便,易于用户使用。
3)稳定性:系统需具备良好的稳定性,能够应对高并发访问。
2. 系统设计(1)系统架构登录系统采用B/S(Browser/Server)架构,分为前端和后端两部分。
前端:使用HTML、CSS、JavaScript等技术实现用户界面。
后端:使用Java语言进行开发,结合MySQL数据库存储用户信息。
(2)模块设计1)用户注册模块:实现用户注册功能,包括输入用户名、密码、邮箱等基本信息。
2)用户登录模块:实现用户登录功能,验证用户身份。
3)找回密码模块:实现找回密码功能,允许用户通过邮箱或手机号找回密码。
4)注销登录模块:实现用户注销登录状态。
3. 系统实现(1)前端实现使用HTML、CSS、JavaScript等技术实现登录系统界面,包括注册、登录、找回密码等页面。
(2)后端实现1)使用Java语言实现用户注册、登录、找回密码等业务逻辑。
2)使用JDBC连接MySQL数据库,实现用户信息的存储和查询。
4. 系统测试(1)功能测试1)测试用户注册功能,确保用户可以成功注册账户。
数据结构实验报告想必学计算机专业的同学都知道数据结构是一门比较重要的课程,那么,下面是小编给大家整理收集的数据结构实验报告,供大家阅读参考。
数据结构实验报告1一、实验目的及要求1)掌握栈和队列这两种特殊的线性表,熟悉它们的特性,在实际问题背景下灵活运用它们。
本实验训练的要点是“栈”和“队列”的观点;二、实验内容1) 利用栈,实现数制转换。
2) 利用栈,实现任一个表达式中的语法检查(选做)。
3) 编程实现队列在两种存储结构中的基本操作(队列的初始化、判队列空、入队列、出队列);三、实验流程、操作步骤或核心代码、算法片段顺序栈:Status InitStack(SqStack &S){S.base=(ElemType*)malloc(STACK_INIT_SIZE*sizeof(ElemTyp e));if(!S.base)return ERROR;S.top=S.base;S.stacksize=STACK_INIT_SIZE;return OK;}Status DestoryStack(SqStack &S){free(S.base);return OK;}Status ClearStack(SqStack &S){S.top=S.base;return OK;}Status StackEmpty(SqStack S){if(S.base==S.top)return OK;return ERROR;}int StackLength(SqStack S){return S.top-S.base;}Status GetTop(SqStack S,ElemType &e){if(S.top-S.base>=S.stacksize){S.base=(ElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(ElemTyp e));if(!S.base) return ERROR;S.top=S.base+S.stacksize;S.stacksize+=STACKINCREMENT;}*S.top++=e;return OK;Status Push(SqStack &S,ElemType e){if(S.top-S.base>=S.stacksize){S.base=(ElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(ElemTyp e));if(!S.base)return ERROR;S.top=S.base+S.stacksize;S.stacksize+=STACKINCREMENT;}*S.top++=e;return OK;}Status Pop(SqStack &S,ElemType &e){if(S.top==S.base)return ERROR;e=*--S.top;return OK;}Status StackTraverse(SqStack S){ElemType *p;p=(ElemType *)malloc(sizeof(ElemType));if(!p) return ERROR;p=S.top;while(p!=S.base)//S.top上面一个...p--;printf("%d ",*p);}return OK;}Status Compare(SqStack &S){int flag,TURE=OK,FALSE=ERROR; ElemType e,x;InitStack(S);flag=OK;printf("请输入要进栈或出栈的元素:"); while((x= getchar)!='#'&&flag) {switch (x){case '(':case '[':case '{':if(Push(S,x)==OK)printf("括号匹配成功!\n\n"); break;case ')':if(Pop(S,e)==ERROR || e!='('){printf("没有满足条件\n");flag=FALSE;}break;case ']':if ( Pop(S,e)==ERROR || e!='[')flag=FALSE;break;case '}':if ( Pop(S,e)==ERROR || e!='{')flag=FALSE;break;}}if (flag && x=='#' && StackEmpty(S)) return OK;elsereturn ERROR;}链队列:Status InitQueue(LinkQueue &Q) {Q.front =Q.rear=(QueuePtr)malloc(sizeof(QNode));if (!Q.front) return ERROR;Q.front->next = NULL;return OK;}Status DestoryQueue(LinkQueue &Q) {while(Q.front){Q.rear=Q.front->next;free(Q.front);Q.front=Q.rear;}return OK;}Status QueueEmpty(LinkQueue &Q){if(Q.front->next==NULL)return OK;return ERROR;}Status QueueLength(LinkQueue Q){int i=0;QueuePtr p,q;p=Q.front;while(p->next){i++;p=Q.front;q=p->next;p=q;}return i;}Status GetHead(LinkQueue Q,ElemType &e) {QueuePtr p;p=Q.front->next;if(!p)return ERROR;e=p->data;return e;}Status ClearQueue(LinkQueue &Q){QueuePtr p;while(Q.front->next ){p=Q.front->next;free(Q.front);Q.front=p;}Q.front->next=NULL;Q.rear->next=NULL;return OK;}Status EnQueue(LinkQueue &Q,ElemType e) {QueuePtr p;p=(QueuePtr)malloc(sizeof (QNode));if(!p)return ERROR;p->data=e;p->next=NULL;Q.rear->next = p;Q.rear=p; //p->next 为空return OK;}Status DeQueue(LinkQueue &Q,ElemType &e) {QueuePtr p;if (Q.front == Q.rear)return ERROR;p = Q.front->next;e = p->data;Q.front->next = p->next;if (Q.rear == p)Q.rear = Q.front; //只有一个元素时(不存在指向尾指针) free (p);return OK;}Status QueueTraverse(LinkQueue Q){QueuePtr p,q;if( QueueEmpty(Q)==OK){printf("这是一个空队列!\n");return ERROR;}p=Q.front->next;while(p){q=p;printf("%d<-\n",q->data);q=p->next;p=q;}return OK;}循环队列:Status InitQueue(SqQueue &Q){Q.base=(QElemType*)malloc(MAXQSIZE*sizeof(QElemType)); if(!Q.base)exit(OWERFLOW);Q.front=Q.rear=0;return OK;}Status EnQueue(SqQueue &Q,QElemType e){if((Q.rear+1)%MAXQSIZE==Q.front)return ERROR;Q.base[Q.rear]=e;Q.rear=(Q.rear+1)%MAXQSIZE;return OK;}Status DeQueue(SqQueue &Q,QElemType &e){if(Q.front==Q.rear)return ERROR;e=Q.base[Q.front];Q.front=(Q.front+1)%MAXQSIZE;return OK;}int QueueLength(SqQueue Q){return(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;}Status DestoryQueue(SqQueue &Q){free(Q.base);return OK;}Status QueueEmpty(SqQueue Q) //判空{if(Q.front ==Q.rear)return OK;return ERROR;}Status QueueTraverse(SqQueue Q){if(Q.front==Q.rear)printf("这是一个空队列!");while(Q.front%MAXQSIZE!=Q.rear){printf("%d<- ",Q.base[Q.front]);Q.front++;}return OK;}数据结构实验报告2一.实验内容:实现哈夫曼编码的生成算法。
一、实验背景随着互联网的普及和快速发展,系统登录已经成为各种在线应用的重要组成部分。
为了提高用户体验和系统安全性,本实验旨在实现一个功能完善、界面友好的系统登录控件,通过学习前端技术、Servlet/JSP后端程序开发、使用Tomcat发布Web 应用以及使用Spring Boot进行后端开发,提升自己的编程能力。
二、实验目的1. 熟悉前端技术,掌握HTML、CSS、JavaScript等基本技能。
2. 掌握Servlet/JSP后端程序开发,了解Java Web开发流程。
3. 学习使用Tomcat发布Web应用,熟悉Web服务器配置。
4. 了解Spring Boot框架,掌握快速开发Web应用的方法。
三、实验内容1. 前端开发(1)创建login.html文件,定义登录表单,包括用户名、密码、登录按钮等元素。
(2)编写login.css文件,设置登录表单的样式,包括字体、颜色、边框等。
(3)编写login.js文件,实现前端验证功能,如检查用户名和密码是否为空、是否符合要求等。
2. 后端开发(1)使用Servlet和JSP实现后端① 创建数据库,并添加驱动程序到Tomcat。
② 创建项目并添加相关库。
③ 编写result.jsp文件,用于显示登录结果。
④ 创建相应的包结构及DBUtil类,用于处理数据库操作。
(2)使用Spring Boot实现后端① 创建Spring Boot项目。
② 配置数据库连接信息。
③ 编写Controller类,处理登录请求。
四、实验步骤1. 前端开发(1)创建login.html文件,添加登录表单元素。
(2)编写login.css文件,设置登录表单样式。
(3)编写login.js文件,实现前端验证功能。
2. 后端开发(1)使用Servlet和JSP实现后端① 创建数据库,并添加驱动程序到Tomcat。
② 创建项目并添加相关库。
③ 编写result.jsp文件,用于显示登录结果。
数据结构图的实验报告数据结构图的实验报告引言:数据结构图是计算机科学中重要的概念之一。
它是一种用图形表示数据元素之间关系的数据结构,广泛应用于算法设计、程序开发和系统优化等领域。
本实验报告旨在介绍数据结构图的基本原理、实验过程和结果分析。
一、实验目的本次实验的主要目的是掌握数据结构图的基本概念和操作方法,以及通过实验验证其在解决实际问题中的有效性。
具体而言,我们将通过构建一个社交网络关系图,实现对用户关系的管理和分析。
二、实验方法1. 确定数据结构在本次实验中,我们选择了无向图作为数据结构图的基础。
无向图由顶点集和边集组成,每条边连接两个顶点,且没有方向性。
2. 数据输入为了模拟真实的社交网络,我们首先需要输入一组用户的基本信息,如姓名、年龄、性别等。
然后,根据用户之间的关系建立边,表示用户之间的交流和联系。
3. 数据操作基于构建好的数据结构图,我们可以进行多种操作,如添加用户、删除用户、查询用户关系等。
这些操作将通过图的遍历、搜索和排序等算法实现。
三、实验过程1. 数据输入我们首先创建一个空的无向图,并通过用户输入的方式逐步添加用户和用户关系。
例如,我们可以输入用户A和用户B的姓名、年龄和性别,并建立一条边连接这两个用户。
2. 数据操作在构建好数据结构图后,我们可以进行多种操作。
例如,我们可以通过深度优先搜索算法遍历整个图,查找与某个用户具有特定关系的用户。
我们也可以通过广度优先搜索算法计算某个用户的社交网络影响力,即与该用户直接或间接相连的其他用户数量。
3. 结果分析通过实验,我们可以观察到数据结构图在管理和分析用户关系方面的优势。
它能够快速地找到用户之间的关系,帮助我们了解用户的社交网络结构和影响力。
同时,数据结构图也为我们提供了一种可视化的方式来展示用户之间的关系,使得分析更加直观和易于理解。
四、实验结果通过实验,我们成功构建了一个社交网络关系图,并实现了多种数据操作。
我们可以根据用户的姓名、年龄和性别等信息进行查询,也可以根据用户之间的关系进行遍历和排序。
数据结构实验报告一、实验目的数据结构是计算机科学中重要的基础课程,通过本次实验,旨在深入理解和掌握常见数据结构的基本概念、操作方法以及在实际问题中的应用。
具体目的包括:1、熟练掌握线性表(如顺序表、链表)的基本操作,如插入、删除、查找等。
2、理解栈和队列的特性,并能够实现其基本操作。
3、掌握树(二叉树、二叉搜索树)的遍历算法和基本操作。
4、学会使用图的数据结构,并实现图的遍历和相关算法。
二、实验环境本次实验使用的编程环境为具体编程环境名称,编程语言为具体编程语言名称。
三、实验内容及步骤(一)线性表的实现与操作1、顺序表的实现定义顺序表的数据结构,包括数组和表的长度等。
实现顺序表的初始化、插入、删除和查找操作。
2、链表的实现定义链表的节点结构,包含数据域和指针域。
实现链表的创建、插入、删除和查找操作。
(二)栈和队列的实现1、栈的实现使用数组或链表实现栈的数据结构。
实现栈的入栈、出栈和栈顶元素获取操作。
2、队列的实现采用循环队列的方式实现队列的数据结构。
完成队列的入队、出队和队头队尾元素获取操作。
(三)树的实现与遍历1、二叉树的创建以递归或迭代的方式创建二叉树。
2、二叉树的遍历实现前序遍历、中序遍历和后序遍历算法。
3、二叉搜索树的操作实现二叉搜索树的插入、删除和查找操作。
(四)图的实现与遍历1、图的表示使用邻接矩阵或邻接表来表示图的数据结构。
2、图的遍历实现深度优先遍历和广度优先遍历算法。
四、实验结果与分析(一)线性表1、顺序表插入操作在表尾进行时效率较高,在表头或中间位置插入时需要移动大量元素,时间复杂度较高。
删除操作同理,在表尾删除效率高,在表头或中间删除需要移动元素。
2、链表插入和删除操作只需修改指针,时间复杂度较低,但查找操作需要遍历链表,效率相对较低。
(二)栈和队列1、栈栈的特点是先进后出,适用于函数调用、表达式求值等场景。
入栈和出栈操作的时间复杂度均为 O(1)。
2、队列队列的特点是先进先出,常用于排队、任务调度等场景。
一、实验目的本次实验旨在让学生掌握数据结构的基本概念、逻辑结构、存储结构以及各种基本操作,并通过实际编程操作,加深对数据结构理论知识的理解,提高编程能力和算法设计能力。
二、实验内容1. 线性表(1)顺序表1)初始化顺序表2)向顺序表插入元素3)从顺序表删除元素4)查找顺序表中的元素5)顺序表的逆序操作(2)链表1)创建链表2)在链表中插入元素3)在链表中删除元素4)查找链表中的元素5)链表的逆序操作2. 栈与队列(1)栈1)栈的初始化2)入栈操作3)出栈操作4)获取栈顶元素5)判断栈是否为空(2)队列1)队列的初始化2)入队操作3)出队操作4)获取队首元素5)判断队列是否为空3. 树与图(1)二叉树1)创建二叉树2)遍历二叉树(前序、中序、后序)3)求二叉树的深度4)求二叉树的宽度5)二叉树的镜像(2)图1)创建图2)图的深度优先遍历3)图的广度优先遍历4)最小生成树5)最短路径三、实验过程1. 线性表(1)顺序表1)初始化顺序表:创建一个长度为10的顺序表,初始化为空。
2)向顺序表插入元素:在顺序表的第i个位置插入元素x。
3)从顺序表删除元素:从顺序表中删除第i个位置的元素。
4)查找顺序表中的元素:在顺序表中查找元素x。
5)顺序表的逆序操作:将顺序表中的元素逆序排列。
(2)链表1)创建链表:创建一个带头结点的循环链表。
2)在链表中插入元素:在链表的第i个位置插入元素x。
3)在链表中删除元素:从链表中删除第i个位置的元素。
4)查找链表中的元素:在链表中查找元素x。
5)链表的逆序操作:将链表中的元素逆序排列。
2. 栈与队列(1)栈1)栈的初始化:创建一个栈,初始化为空。
2)入栈操作:将元素x压入栈中。
3)出栈操作:从栈中弹出元素。
4)获取栈顶元素:获取栈顶元素。
5)判断栈是否为空:判断栈是否为空。
(2)队列1)队列的初始化:创建一个队列,初始化为空。
2)入队操作:将元素x入队。
3)出队操作:从队列中出队元素。
一、实验目的本次实验旨在了解用户登录过程,分析用户登录过程中的常见问题,并针对这些问题提出相应的解决方案,以提高用户登录的效率和安全性。
二、实验内容1. 用户登录流程分析(1)用户输入用户名和密码(2)服务器验证用户名和密码(3)验证成功,用户登录成功;验证失败,提示用户名或密码错误2. 用户登录过程中常见问题(1)用户名或密码错误(2)账号被锁定(3)登录页面加载缓慢(4)登录过程中出现异常3. 解决方案(1)用户名或密码错误原因:用户输入错误或系统错误解决方案:①在用户登录页面增加密码提示功能,方便用户找回密码;②在用户登录失败时,记录失败次数,超过一定次数后锁定账号,防止恶意攻击;③优化用户名和密码验证算法,提高验证效率。
(2)账号被锁定原因:用户连续多次输入错误密码,导致账号被锁定解决方案:①在用户登录失败时,记录失败次数,超过一定次数后锁定账号,防止恶意攻击;②在账号被锁定后,允许用户通过邮箱、手机等方式找回账号;③设置账号解锁时间,如24小时,方便用户及时解锁账号。
(3)登录页面加载缓慢原因:服务器性能不足或网络延迟解决方案:①优化服务器性能,提高处理速度;②优化前端代码,减少页面加载时间;③优化数据库查询,提高查询效率。
(4)登录过程中出现异常原因:系统错误或用户操作不当解决方案:①优化系统稳定性,减少异常发生;②在登录过程中,增加异常处理机制,确保用户数据安全;③提供详细的错误提示,方便用户了解异常原因。
三、实验结果通过本次实验,我们分析了用户登录过程中的常见问题,并提出了相应的解决方案。
以下为实验结果:1. 用户登录流程分析用户登录流程如下:(1)用户输入用户名和密码;(2)服务器验证用户名和密码;(3)验证成功,用户登录成功;验证失败,提示用户名或密码错误。
2. 用户登录过程中常见问题及解决方案(1)用户名或密码错误:增加密码提示功能,记录失败次数,优化验证算法;(2)账号被锁定:记录失败次数,允许用户找回账号,设置账号解锁时间;(3)登录页面加载缓慢:优化服务器性能,优化前端代码,优化数据库查询;(4)登录过程中出现异常:优化系统稳定性,增加异常处理机制,提供详细的错误提示。
数据结构实验报告一、实验目的本次实验的目的是通过实际操作,深入理解数据结构的概念、特性和应用,并运用所学知识进行问题解决和算法设计。
二、实验内容本次实验主要包括以下内容:1. 数组的创建和操作:- 数组的定义和初始化- 数组元素的读取和修改- 数组的遍历和排序2. 链表的创建和操作:- 单链表的定义和初始化- 单链表的插入和删除- 单链表的遍历和逆序输出3. 栈和队列的创建和操作:- 栈的初始化和压栈、弹栈操作- 队列的初始化和入队、出队操作4. 树的创建和操作:- 二叉树的定义和初始化- 二叉树的遍历(前序、中序、后序遍历)- 二叉树的查找、插入和删除操作三、实验步骤和方法1. 数组的创建和操作:- 根据题目要求,声明和初始化数组;- 使用循环结构,遍历数组,并根据需求进行元素的修改;- 运用排序算法对数组进行排序,并验证排序结果的正确性。
2. 链表的创建和操作:- 根据题目要求,创建单链表的结构体和相关操作函数;- 使用动态内存分配函数malloc(),创建链表节点并插入到链表中;- 根据题目要求,设计相应的插入和删除函数,实现链表的插入和删除操作;- 遍历链表,并将链表节点的数据逆序输出。
3. 栈和队列的创建和操作:- 根据题目要求,创建栈和队列的结构体和相关操作函数;- 使用数组和指针实现栈和队列的功能,并初始化相关变量;- 实现栈的压栈和弹栈操作,并验证结果的正确性;- 实现队列的入队和出队操作,并验证结果的正确性。
4. 树的创建和操作:- 根据题目要求,创建二叉树的结构体和相关操作函数;- 使用动态内存分配函数malloc(),创建二叉树的节点,并根据题目要求插入到二叉树中;- 实现二叉树的遍历(前序、中序、后序遍历),并验证遍历结果的正确性;- 根据题目要求,实现二叉树的查找、插入和删除操作。
四、实验结果与分析在实验过程中,我按照题目的要求,使用所学的数据结构相关知识,设计了相应的代码,并通过调试和运行,得到了实验结果。
实验名称:数据结构实验实验时间:2021年X月X日实验地点:计算机实验室实验目的:1. 理解并掌握基本数据结构(线性表、栈、队列、链表、树、图)的概念和操作。
2. 能够运用C语言实现基本数据结构的各种操作。
3. 培养编程能力和问题解决能力。
实验内容:1. 线性表2. 栈3. 队列4. 链表5. 树6. 图实验环境:1. 操作系统:Windows 102. 编程语言:C语言3. 开发环境:Visual Studio 2019实验步骤:一、线性表1. 实现线性表的创建、插入、删除、查找和遍历等基本操作。
2. 编写代码,实现以下功能:- 创建一个线性表,包含10个元素。
- 在第3个位置插入一个新元素。
- 删除第5个位置的元素。
- 查找线性表中的第7个元素。
- 遍历线性表,并打印所有元素。
二、栈1. 实现栈的创建、入栈、出栈、判空和求栈顶元素等基本操作。
2. 编写代码,实现以下功能:- 创建一个栈。
- 向栈中依次入栈元素1、2、3、4、5。
- 判断栈是否为空。
- 求栈顶元素。
- 出栈元素,并打印出栈的元素。
三、队列1. 实现队列的创建、入队、出队、判空和求队头元素等基本操作。
2. 编写代码,实现以下功能:- 创建一个队列。
- 向队列中依次入队元素1、2、3、4、5。
- 判断队列是否为空。
- 求队头元素。
- 出队元素,并打印出队的元素。
四、链表1. 实现单链表、双向链表和循环链表的创建、插入、删除、查找和遍历等基本操作。
2. 编写代码,实现以下功能:- 创建一个单链表,包含元素1、2、3、4、5。
- 在第2个位置插入一个新元素。
- 删除第3个位置的元素。
- 查找链表中的第4个元素。
- 遍历链表,并打印所有元素。
五、树1. 实现二叉树的创建、插入、删除、查找和遍历等基本操作。
2. 编写代码,实现以下功能:- 创建一个二叉树,包含元素1、2、3、4、5。
- 在第2个位置插入一个新元素。
- 删除第3个位置的元素。
数据结构大型实验报告---用户登录系统模拟姓名:金天昊班级:网络工程一班浙江工业大学计算机学院目录实验分析 (3)实验目的 (3)实验基本数据结构 (3)实验基本流程图 (3)输入的形式和输入值的范围 (4)输出的形式 (4)程序所能达到的功能 (4)调试分析 (5)讨论等系调试过程中的主要技术问题以及具体解决方法 (5)技术难点分析 (5)测试结果 (7)心得体会 (11)附录 (12)实验分析实验目的在登录服务器系统时,都需要验证用户名和密码,如telnet远程登录服务器。
用户输入用户名和密码后,服务器程序会首先验证用户信息的合法性。
由于用户信息的验证频率很高,系统有必要有效地组织这些用户信息,从而快速查找和验证用户。
另外,系统也会经常会添加新用户、删除老用户和更新用户密码等操作,因此,系统必须采用动态结构,在添加、删除或更新后,依然能保证验证过程的快速。
请采用相应的数据结构模拟用户登录系统,其功能要求包括用户登录、用户密码更新、用户添加和用户删除等。
实验基本数据结构实验基本流程图输入的形式与输入值的范围用户名与密码均采用string形输出的形式界面输出选择框程序所能达到的功能模拟用户登入系统实现用户登录、注册、删除、修改密码以及信息的本地存储和读取。
调试分析讨论分析调试过程中的技术问题以及具体的解决方法①问题:AVL树元素的添加删除需要修改路径上的所有节点的平衡因子方法:引入一个栈类(Stack)用于将搜索目的节点路径上的节点依次压入栈中②问题:用户名与密码可能是数字也可能是字母亦可能是数字与字母的组合方法:统一采用string技术难点分析技术难点:实现二叉树的平衡,即树的旋转二叉树的旋转共四种,分别为左旋、右旋、左右旋、右左旋转,对应情况如下:左旋右旋左右旋右左旋测试结果用户的注册、登录、删除、修改密码以及信息的本地存储和读取customer.txt文件中)。
①用户登录②用户注册③用户删除④用户密码修改登录时测试不存在的用户或者错误的密码用户删除时验证密码错误提示删除失败修改密码时验证密码错误提示修改失败心得体会与大一不同,这一次的大型实验是我一个人独立完成的。
中间也遇到了些许困难,但通过自己的钻研以及查阅了相关的资料成功的解决了问题。
这个实验中最难的部分在于平衡旋转,平衡旋转使用在新建用户和删除用户上,期中尤为困难的是删除,这个环节中还需引入栈用于存储搜索目的用户过程中路径上的节点指针,从而达到从删除节点开始往根节点进行调整的操作。
通过这次大型实验我的编码能力得到了训练,熟悉了平衡二叉树的建立,也锻炼了算法的分析能力。
附录//==================================================================// Customer.h////==================================================================#include <iostream>using namespace std;#include "Stack.h"class CCustomer{public:CCustomer();~CCustomer();bool empty();//判空void remove();//删除用户void ChangePassword();//修改密码void Save();//保存用户信息到本地文本文件中bool search(string name);//判断用户是否已存在void insert(string name, string paw); //新增用户void entry(string name, string paw); //用于判断登陆时的帐号密码是否正确private:class CustomerNode{public:string username;string password;int balanceFactor;CustomerNode * left;CustomerNode * right;CustomerNode(){balanceFactor = 0;left = 0;right = 0;}CustomerNode(string name, string word){username = name;password = word;balanceFactor = 0;left = 0;right = 0;}};typedef CustomerNode *CustomerPointer;CustomerPointer Root;Stack<CustomerPointer> path;Stack<CustomerPointer> path2;void release(CustomerPointer TreeRoot);//析构函数的辅助函数void save_aux(CustomerPointer root);//保存用户信息的辅助函数void Rotation(int newBF, CustomerPointer root); //旋转函数,用于调整二叉树的结构void search2(string name, bool &flag, CustomerPointer &location,CustomerPointer &parent); //删除操作的辅助函数//左旋转函数CustomerPointer L_Rotate(CustomerPointer root){CustomerPointer lc;lc = root->right;root->right = lc->left;lc->left = root;if (lc->balanceFactor == -1){root->balanceFactor = 0;lc->balanceFactor = 0;}else{root->balanceFactor = -1;lc->balanceFactor = 1;}return lc;}//右旋转函数CustomerPointer R_Rotate(CustomerPointer root){CustomerPointer lc;lc = root->left;root->left = lc->right;lc->right = root;if (lc->balanceFactor == 1){root->balanceFactor = 0;lc->balanceFactor = 0;}else{root->balanceFactor = 1;lc->balanceFactor = -1;}return lc;}//左-右旋转函数CustomerPointer LR_Rotate(CustomerPointer root){CustomerPointer ptr = root->left;CustomerPointer lc = ptr->right;root->left = lc->right;ptr->right = lc->left;lc->left = ptr;lc->right = root;switch (lc->balanceFactor){case 0://情况1:新节点插入之前,原旋转根的左孩子没有右孩子,新插入的节点成为其右孩子root->balanceFactor = 0;ptr->balanceFactor = 0;break;case 1://情况2:新节点插入之前,原旋转根的左孩子有右孩子C,新节点被插入到C的左子树中root->balanceFactor = -1;ptr->balanceFactor = 0;case -1://情况3:新节点插入之前,原旋转根的左孩子有右孩子C,新节点被插入到C的右子树中root->balanceFactor = 0;ptr->balanceFactor = 1;break;}lc->balanceFactor = 0;return lc;}//右-左旋转函数CustomerPointer RL_Rotate(CustomerPointer root){CustomerPointer ptr = root->right;CustomerPointer lc = ptr->left;root->right = lc->left;ptr->left = lc->right;lc->right = ptr;lc->left = root;switch (lc->balanceFactor){case 0: //情况1:新节点插入之前,原根的右孩子没有左孩子,新插入的节点成为其左孩子root->balanceFactor = 0;ptr->balanceFactor = 0;break;case 1: //情况2:新节点插入之前,原根的右孩子有左孩子C,新节点被插入到C的右子树中root->balanceFactor = 0;ptr->balanceFactor = -1;case -1://情况3:新节点插入之前,原根的右孩子有左孩子C,新节点被插入到C的左子树中root->balanceFactor = 1;ptr->balanceFactor = 0;break;}lc->balanceFactor = 0;return lc;}};//================================================================== ==================================================================== //// Stack.h////================================================================== ==================================================================== #include <string>#include<iostream>using namespace std;template <typename DataType>class Stack{private:class Node{public:DataType data;Node *next;Node(DataType value,Node *link = 0):data(value),next(link){}};public:typedef Node * NodePointer;Stack();~Stack();bool empty();void push( DataType &value);DataType top() ;void pop();private:NodePointer myTop;};template <typename DataType>inline Stack<DataType>::Stack():myTop(0){}template <typename DataType>inline Stack<DataType>::~Stack(){Stack::NodePointer currPtr = myTop,nextPtr;while (currPtr != 0){nextPtr = currPtr->next;delete currPtr;currPtr = nextPtr;}}template <typename DataType>inline bool Stack<DataType>::empty(){return (myTop == 0);}template <typename DataType>inline void Stack<DataType>::push( DataType & value) {myTop = new Stack::Node(value,myTop);}template <typename DataType>inline DataType Stack<DataType>::top(){return (myTop->data);}template <typename DataType>inline void Stack<DataType>::pop(){Stack::NodePointer ptr = myTop;myTop = myTop->next;delete ptr;}//================================================================== ==================================================================== //// Customer.cpp//////================================================================== ==================================================================== #include "Customer.h"#include<string>#include<iostream>#include <fstream>using namespace std;CCustomer::CCustomer(){Root = 0;}CCustomer::~CCustomer(){release(Root);}void CCustomer::release(CustomerPointer TreeRoot){if (TreeRoot != 0){release(TreeRoot->left);release(TreeRoot->right);delete TreeRoot;}}//判空bool CCustomer::empty(){return Root == 0;}//删除用户void CCustomer::remove(){string name;string paw;cout << "请输入想删除的用户名:"<<endl;cin >> name;while (!path.empty())path.pop();bool flag;CustomerPointer lc;CustomerPointer parent;search2(name, flag, lc, parent);if (!flag){//没有找到该用户;system("cls");cout << "该用户不存在" << endl;return;}cout<<"请输入该用户的密码:"<<endl;cin>>paw;if (paw != lc->password){system("cls");cout<<"密码错误,删除失败"<<endl;return;}if (lc->left != 0 && lc->right != 0){ //如果要删除的节点有左右节点;CustomerPointer rchild = lc->right; //定义辅助指针rchild指向被删节点的右孩子;parent = lc;while (rchild->left != 0){ //寻找被删节点的中序后继节点,便于删除;path.push(rchild);//寻找时同样需要将访问路径上的节点压入栈中;parent = rchild;rchild = rchild->left;}lc->username = rchild->username; //交换被删节点与其后继节点的用户名与密码;lc->password = rchild->password;lc = rchild;}CustomerPointer lchild = lc->left; //指向lc的子树的指针if (lchild == 0){lchild = lc->right;//若左节点不存在,则指向右节点(右节点也可能为0);}if (parent == 0){//若要删除的是根节点;Root = lchild;}else if (parent->left == lc) //若lc是parent的左节点;{parent->left = lchild;//则parent的左指针指向lchild;}else{//若lc是parent的右节点;parent->right = lchild;//则parent的右指针指向lchild;}string username = lc->username;delete lc;while (!(path.empty())){//修改平衡因子并旋转;CustomerPointer ptr = path.top();//从删除位置开始,逐层向上修改平衡因子,需要弹出栈中元素;if (username>ptr->username)//若删除的是左子树中的节点;ptr->balanceFactor++;else if (username<ptr->username) //若删除的是右子树中的节点;ptr->balanceFactor--;int newBF = ptr->balanceFactor;//修改后的平衡因子;path.pop();//删除栈顶元素;if (newBF != 0){ //如果修改后的平衡因子不为0;if (newBF == 1 || newBF == -1) //平衡因子为1或-1时说明删除后的树还是平衡的,结束循环;return;else if (newBF == 2 || newBF == -2)//如果为2或-2,则进行旋转;Rotation(newBF, ptr);}}system("cls");cout << "删除成功!" << endl;}void CCustomer::search2(string name, bool &flag, CustomerPointer &lc, CustomerPointer &parent){lc = Root;parent = 0;flag = false;while (!flag && lc != 0){if (name<lc->username){path.push(lc);parent = lc;lc = lc->left;}else if (lc->username<name){path.push(lc);parent = lc;lc = lc->right;}elseflag = true;}}//修改密码void CCustomer::ChangePassword(){string name;CustomerPointer lc = Root;cout << "请输入要修改密码的用户名"<<endl;cin >> name;bool flag = false;while (!flag && lc != 0){if (name<lc->username){lc = lc->left;}else if (name>lc->username){lc = lc->right;}else{flag = true; //找到该用户}}if (flag == false)//未找到该用户{{system("cls");cout << "该用户名不存在" << endl;}return;}else{string Pword1;string Pword2;cout <<"请输入原密码:"<<endl;cin >> Pword1;if (Pword1 == lc->password)//密码正确{cout << "请输入新密码:"<<endl;cin >> Pword2;lc->password = Pword2;system("cls");cout << "密码修改成功!" << endl;}else{system("cls");cout << "原密码错误!修改失败!" << endl;return;}}}bool CCustomer::search(string name){CustomerPointer lc = Root;bool flag = false;while (lc!= 0 && flag == false){if (name<lc->username){lc = lc->left;}else if (name>lc->username){lc = lc->right;}else{flag = true;//该用户已存在}}return flag;}void CCustomer::insert(string name, string paw) {while (!path.empty()){path.pop();}CustomerPointer lc = Root;CustomerPointer parent = 0;bool flag = false;while (lc != 0 && !flag){parent = lc;//保存当前节点if (name<lc->username){path.push(lc);lc = lc->left;}else if (lc->username<name){path.push(lc);lc = lc->right;}else{flag = true;}}if (!flag){lc = new CustomerNode(name, paw);if (parent == 0){//如果二叉树为空,则插入的节点为根节点;Root = lc;}else if (name<parent->username){//如果要插入的节点的用户名小于插入点中的用户名;parent->left = lc;}else{parent->right = lc;}}while (!path.empty()){//插入完成后,修改插入路径上的平衡因子,可能会旋转;CustomerPointer lc = path.top();//从插入位置开始,逐层向上修改平衡因子,需要弹出栈中元素;if (name>lc->username){//若插入到当前节点的右子树中时;(lc->balanceFactor)--;}else if (name<lc->username){//若插入到当前节点的左子树中时;(lc->balanceFactor)++;}int newBF = lc->balanceFactor;//修改后的平衡因子;CustomerPointer ptr = lc;path.pop();if (newBF == 0){//若修改后的平衡因子为0,则该树已经平衡,结束循环;break;}if (newBF == 2 || newBF == -2){//若修改后的平衡因子为2或者-2,则需要旋转;Rotation(newBF, ptr);return;}}}void CCustomer::entry(string name, string paw){CustomerPointer lc = Root;bool flag = false;//检查用户名是否匹配while (!flag && lc != 0){if (name<lc->username){lc = lc->left;}else if (lc->username<name){lc = lc->right;}else{//如果用户名相等;if (paw == lc->password){//密码相等;flag = true;system("cls");cout<<"登录成功"<<" "<<"当前用户:"<<" "<<name<<endl;}else{flag = true;system("cls");cout<<"密码错误"<<endl;}}if(!flag){system("cls");cout<<"该用户不存在";}}}void CCustomer::Rotation(int newBF, CustomerPointer root) {//当平衡因子为2或者-2时则需要进行旋转;CustomerPointer newroot = 0;if (newBF == 2){//如果平衡因子为2时,可能进行右旋或者左右旋;int leftBF = root->left->balanceFactor;if (leftBF == -1){newroot = LR_Rotate(root);}else{newroot = R_Rotate(root);}}else if (newBF == -2){//如果平衡因子为-2时,可能进行左旋或者右左旋;int rightBF = root->right->balanceFactor;if (rightBF == 1){newroot = RL_Rotate(root);}else{newroot = L_Rotate(root);}}if (!(path.empty())){//此时的栈顶元素为原旋转根的双亲;CustomerPointer ptr = path.top();//弹出栈顶元素;if ((ptr->username)>(root->username)){ptr->left = newroot;}else{ptr->right = newroot;}}elseRoot = newroot;//如果栈是空的,说明原根为AVL的根,只需交换根;}void CCustomer::Save(){ofstream outfile("Customer.txt", ios::out);if (!outfile){cerr << "用户文件不存在,请检查" << endl;exit(1);}save_aux(Root);while (!path2.empty()){CustomerPointer lc = path2.top(); //一边出栈,一边将出来的元素读到文件中;outfile << lc->username << " " << lc->password << endl;path2.pop();}outfile.close();system("cls");cout<<"保存成功!";}void CCustomer::save_aux(CustomerPointer root){if(root != 0){path2.push(root);save_aux(root->left);save_aux(root->right);}}//================================================================== ==================================================================== //// main.cpp//////================================================================== ==================================================================== #include"Customer.h"#include<iostream>#include <fstream>using namespace std;int main(){ifstream infile("Customer.txt", ios::in);if (!infile){cerr << "用户信息不存在,请检查!" << endl;exit(1);}CCustomer C;string num;string name;string paw;while (infile >> name){infile >> paw;C.insert(name, paw);}infile.close();while (1){cout << " 欢迎进入登录系统" << endl;cout << "============================================" << endl;cout << "**************** 1.用户登录 **************" << endl;cout << "**************** 2.用户注册 **************" << endl;cout << "**************** 3.用户删除 **************" << endl; cout << "**************** 4.修改用户密码***********" << endl; cout << "**************** 5.保存******************" << endl; cout << "**************** 6.退出*******************" << endl; cout << " ========================================" << endl; cout << endl;cout << "请选择:"<<endl;cin >> num;if (num == "1"){string name;string paw;cout << "请输入用户名:"<<endl;cin >> name;cout << "请输入密码:"<<endl;cin >> paw;C.entry(name,paw);}else if (num == "2"){string name;string paw;cout << "请要注册的用户名:"<<endl;cin >> name;if (C.search(name) == true){system("cls");cout << "用户名已经存在,不能注册!" << endl;}else{cout << "请要注册用户的密码:"<<endl;cin >> paw;system("cls");C.insert(name, paw);cout<<"注册成功!";}}else if (num == "3"){C.remove();}else if (num == "4"){C.ChangePassword();}else if (num == "5"){C.Save();}else if (num == "6"){system("cls");cout<<"退出成功"<<endl;break;}else{system("cls");cout << "无效的口令,请重新输入" << endl;}}return 0;}31。