分类

课内:
不限
类型:
不限 毕业设计 课程设计 小学期 大作业
汇编语言 C语言 C++ JAVA C# JSP PYTHON PHP
数据结构与算法 操作系统 编译原理 数据库 计算机网络 软件工程 VC++程序设计
游戏 PC程序 APP 网站 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
年份:
不限 2018 2019 2020

资源列表

  • 基于C++语言在Linux环境下模拟实现命令解释器

    一 需求分析程序实现的功能如下:

    显示当前所在目录的路径名
    列出指定目录中所有的目录和文件
    改变当前工作目录
    新建一个目录即新建一个文件夹
    删除一个目录即删除一个文件夹
    退出命令解释程序
    重命名一个文件或目录
    复制已经存在的目录
    在指定的一个目录及其子目录中查找指定的文件和目录,并输出查找到的文件和目录的绝对路径,并指明是文件还是目录

    二 程序设计2.1 菜单在列举菜单之前先把控制台用clear命令清除内容,再进行显示,以保证界面美观,在菜单之后直接调用pwd()函数显示当前工作目录,方便用户查看当前工作目录。
    system("clear");cout<<"*****************"<<endl;......cout<<"*****************"<<endl;pwd();cout<<endl;
    2.2 显示当前所在目录的路径名这个功能写在pwd()函数中,使用getcwd()函数获取当前目录存进path数组中并且打印在控制台。
    char path[100];getcwd(path,100);//Getpathcout<<"currentdirectory: "<<path<<endl;
    2.3 列举指定目录中的所有目录及文件此功能写在list()函数中,通过传入的目录,用opendir()函数打开目录,获取目录流,并且用readdir()函数读取每一个目录节点,打印出信息,最后closedir()关闭该目录。
    DIR* d =opendir(dir.c_str());if(d==NULL) { return false;} else{ struct dirent *dirent; while(dirent=readdir(d)) { cout<<endl; cout<<" "<<dirent->d_name<<" "<<dirent->d_type<<" "<<dirent->d_reclen<<endl; cout<<endl; }closedir(d); return true;}
    2.4 改变当前目录使用chdir()函数改变当前打开的工作目录,返回0时,改变成功,chdir()函数返回true,否则返回false。
    if(chdir(path.c_str())==0){ return true; }else { return false;}
    2.5 新建目录在函数makedir()中调用系统的mkdir函数创建指定目录名的目录,当返回0时创建成功,makedir ()函数返回true,否则返回false,创建的目录一般具有所有权限。
    if(mkdir(dir.c_str(),S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)==0) { return true; }else { return false;}
    2.6 删除目录在deldir()中调用rmdir函数删除指定目录,返回0时删除成功,deldir ()函数返回true,否则返回false。
    if(rmdir(dir.c_str())==0){ return true; }else { return false;}
    2.7 重命名在rename()函数中调用C中的标准函数rename,将旧的目录或文件名改为新的目录或文件名,当返回0时,重命名成功,rename()函数返回true,否则返回false。
    if(rename(lastname.c_str(),newname.c_str())==0){ return true; }else { return false;}
    2.8 复制文件先判断文件是否存在,若存在则判断目标文件是否存在,假如已经存在那么便在原来的文件名字后缀加上(1)再复制,加入不存在则直接复制,复制的方式是先调用read()函数从源文件读出内容存进buf数组,接着调用write()函数将内容写进目标文件。
    int fo1,fo2;char buf[1024];fo1=open(existname.c_str(),O_RDONLY);if(fo1==-1) { return false;}else { fo2=open(newname.c_str(),O_RDONLY); if(fo2!=-1) { int i; cout<<"Overwrite original file??"<<endl; cout<<"----1 is yes,not 1 is no."; cin>>i; if(i!=1) { newname+="(1)"; } close(fo2);}fo2=open(newname.c_str(),O_WRONLY|O_CREAT,S_IRWXU);int size = read(fo1,buf,sizeof(buf));write(fo2,buf,size);close(fo1);close(fo2);return true;}
    2.9 查找指定文件和目录通过调用ftw函数回调遍历指定目录中的文件,fn是回调函数,每一次遍历到一个节点,ftw函数都会把节点路径和节点信息以及类型传入fn函数中,同时,把需要查找的文件名字作为全局变量,在fn中判断是否存在并且输出。
    ftw(dir.c_str(),fn,500);int fn(const char fpath, const struct statst, int typeflag) { for(int i=strlen(fpath)-1,j=file.length()-1;;i--,j--) { if(j==-1&&fpath[i]=='/'){ cout<<" "<<fpath; if(typeflag==FTW_F) cout<<"FILE"<<endl; else if(typeflag==FTW_D) cout<<"DIRECTORY"<<endl; num++; break; } if(fpath[i]=='/') break; if(j==-1) break; if(fpath[i]!=file[j]){ break; } } return 0;}
    2.10 退出直接在main函数中返回0。
    三 程序实现3.1 实现原理
    目录:为了方便对存储介质中的文件的管理而产生的一种索引结构,可以理解为目录中包含有另外的目录和文件
    路径:说明一个文件或者一个子目录在整个目录系统中的位置,用于定位一个文件或者子目录,包括绝对路径和相对路径两中方式
    文件:文件是指存储在存储介质中的一段特定格式的数据资料
    目录流:对一个目录中的每个项进行读取的方式,是目录中所有节点的信息序列
    文件流:是该文件中数据资料的格式化序列,代表着所有数据的信息
    文件复制:将一个文件中所有的内容全部备份到另外一个文件中
    函数回调:回调是一种双向调用模式,C中通过函数指针来实现

    四 运行测试4.1 进入程序在进入程序会有菜单可供选择,一共有8个功能,并且在菜单下面会有当前工作目录显示在界面上,如图:

    4.2 展示目录显示出指定目录下的所有目录和文件,当输入‘.’的时候为当前工作目录的内容,如图:


    4.3 改变当前目录将当前所在的工作目录改为所输入的目录,可以是绝对路径,也可以是当前目录下的子目录,如图:

    4.4 创建目录可以在任意目录下创建一个文件夹即目录,如图:

    创建目录的结果如图:

    4.5 删除目录:可以在任意目录下删除一个文件夹即目录,如图:

    删除结果如图:

    4.6 重命名把文件名或者目录名更改,更改前与更改后如图:


    4.7 复制文件从一个目录将文件复制到另一个目录并且命名,如图,图中为同个目录下的复制:

    4.8 搜索文件从指定目录下搜索指定文件,如图,图中为当前工作目录搜索:

    4.9 退出程序
    1 评论 74 下载 2018-11-01 09:48:47 下载需要8点积分
  • 基于C语言的八大排序算法的比较

    一、项目内容将冒泡排序,选择排序,直接插入排序,希尔排序,快速排序,堆排序,归并排序,基数排序等八种排序方法做横向比较,针对相同的随机数据,比较排序算法所消耗的时间以及交换次数。
    二、算法描述2.1 冒泡排序算法描述:

    比较相邻的元素。如果第一个比第二个大,就交换他们两个
    对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数
    针对所有的元素重复以上的步骤,除了最后一个
    持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

    2.2 选择排序算法描述:
    对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较如果后面的元素比他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。
    2.3 直接插入排序算法描述:
    每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
    第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
    2.4 希尔排序算法描述:
    先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
    2.5 快速排序算法描述:
    设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
    一趟快速排序的算法是:

    设置两个变量i、j,排序开始的时候:i=0,j=N-1
    以第一个数组元素作为关键数据,赋值给key,即key=A[0]
    从j开始向前搜索,即由后开始向前搜索(j—),找到第一个小于key的值A[j],将A[j]赋给A[i]
    从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]赋给A[j]
    重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)

    2.6 堆排序堆的定义:n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
    ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n)(当然,这是小根堆,大根堆则换成>=号)。
    算法描述:

    先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
    再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
    由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆,直到无序区只有一个元素为止

    2.7 归并排序定义归并操作:

    申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
    设定两个指针,最初位置分别为两个已经排序序列的起始位置比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
    重复步骤3直到某一指针到达序列尾
    将另一序列剩下的所有元素直接复制到合并序列尾

    算法描述:
    对于无序数组d1,d2,d3,…,dn,递归操作,将d1..dn/2排序,再将dn/2+1..dn排序,然后对两个有序数组进行归并操作,得到有序数组d。
    2.8 基数排序算法描述:
    将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
    三、算法分析3.1 冒泡排序
    冒泡排序的最坏时间复杂度为O(n^2)
    冒泡排序的平均时间复杂度为O(n^2)

    3.2 选择排序
    选择排序的最坏时间复杂度为O(n^2)。
    选择排序的平均时间复杂度为O(n^2)。

    3.3 直接插入排序
    直接插入排序的最坏时间复杂度为O(n^2)
    直接插入排序的平均时间复杂度为O(n^2)

    3.4 希尔排序
    希尔排序的最坏时间复杂度为O(n^2)
    希尔排序的平均时间复杂度为O(n log ^2 n)

    3.5 快速排序
    快速排序的最坏时间复杂度为O(n^2)
    快速排序的平均时间复杂度为O(n log n)

    3.6 堆排序
    堆排序的最坏时间复杂度为O(n log ^2 n)
    堆排序的平均时间复杂度为O(n log n)。

    3.7 归并排序
    归并排序的最坏时间复杂度为O(n log n)
    归并排序的平均时间复杂度为O(n log n)

    3.8 基数排序
    基数排序的最坏时间复杂度为O(kn)
    基数排序的平均时间复杂度为O(kn)。

    四、操作说明
    进入程序后按照提示输入产生随机数的个数
    输入1—8并按回车选择排序算法,选择后程序会输出此算法所用时间和所用交换次数
    输入9退出程序


    1 评论 46 下载 2018-10-31 22:30:04 下载需要7点积分
  • 基于C++的分组密码加解密实现

    1 设计实现程序完成课程设计所有必做与选做的要求,包含的函数如下:
    // S 盒置换 BlockType SBox_Encode(BlockType x); // S 盒逆变换BlockType SBox_Decode(BlockType x); // P 盒置换BlockType PBox_Encode(BlockType x); // P 盒逆变换BlockType PBox_Decode(BlockType x); // 输出显示一个 16 位二进制数void OutPut_Bin(BlockType p); // 输出显示一个密钥 void OutPut_Key(KeyType key);// 分组加密函数 void BlockEncryption(BlockType PlainText, BlockType &CipherText, KeyType Key); // 分组解密函数 void BlockDecryption(BlockType &PlainText, BlockType CipherText, KeyType Key); // 生成指定密钥 void Key_Engine();// 随机生成密钥 void Key_Random();// 文件加密 int FileEncryption(char *PlainFile,char *CipherFile,KeyType Key); // 文件解密 int FileDecryption(char *PlainFile,char *CipherFile,KeyType Key); // 加密函数的运行速度 unsigned long EncryptionTime(unsigned long Times); // 线性密码分析 BlockType LinearCryptanalysis(unsigned long T,BlockType Text[][2]); // 差分密码分析 BlockType DiffCryptanalysis(unsigned long T,BlockType Text[][4]); // 测试分组加密与解密 void TestBlockEncrypt();// 测试文件加密与解密 void TestFileEncrypt();// 测试运行速度 void TestEncryptionTime();// 测试线性密码分析 void TestLinearCryptanalysis();// 测试差分密码分析 void TestDiffCryptanalysis();// 测试线性分析函数成功时明密文对数 void TestLinearSucceedTimes();// 测试差分分析函数成功时明密文对数 void TestDiffSucceedTimes();// 暂停,按回车键继续 void Wait();
    测试程序只需打开生成的可执行文件,按提示操作即可。
    运行截图如下:

    任意输入一个小于 65536 的非负整数,即可进行 16 位数据分组加密与解密的演示。

    测试文件加密与解密:请确保输入的“目录\文件名”正确,否则会返回“文件不存在,失败”。对文件加密之后会在原目录中生成加密文件“文件名.cip”,继续则会自动进行解密,重新在原目录下生成新的原文件,建议文件加密之后将原文件移至其他地方,再进行解密操作,方能见到文件解密效果。
    文件加密对任意文件格式有效。
    接下去的步骤是测试平均加密时间,采用 1000 个随机密钥分别对 0—65535 的每个数进行加密,给出平均一个密钥所用的加密时间。

    下面会测试线性密码分析与差分密码分析,随机产生的明密文对分别为 8000 与 100 对。此过程可能成功或失败,猜想失败可能与随机明文的产生有关。

    最后进行密码分析成功时的明密文对数量的测试。
    附带程序:
    随作业附带的可执行文件FileEncryption.exe可方便地进行文件的加密与解密。示例如下:

    如图,可自行输入加密所取密钥,也可使用默认密钥。只要对文件解密时所用密钥与文件加密时相同,即可还原原文件,若解密时采用密钥与加密时不同,则可能生成另一个乱码文件或产生错误。
    2 效率为了提高加密与解密的效率,S 盒与 P 盒以及它们的逆变换直接采用数组存储,使用时采用查表的方式直接查询获得。
    移位运算中,尽量将一个数对同一个方向的移位按照从近到远的方式进行,减少重复平移的位数。
    2.1 测试平均加密时间
    如上图所示,总共对 10000 个随机密钥进行了测试,得到的平均加密时间为 80ms。
    测试平台如下:

    软件平台:操作系统 WIN7 32 位,编译器 VC6.0
    硬件平台:处理器 Intel(R) Core(TM)2 Duo CPU T6570 2.1GHz
    内存 4GB

    2.2 密码分析成功时的明密文对数量采用 6000—20000 对随机明密文分别进行线性密码分析,明密文对数量每增加 200 测试一次并输出结果“成功”或“失败”。
    结果如下:

    采用 50—300 对随机选择明密文分别进行差分密码分析,明密文对数量每增加 10 测试一次并输出结果“成功”或“失败”。
    结果如下:

    由结果可发现,对于线性密码分析与差分密码分析,随着明密文对数量的增加,分析成功的概率都会明显增大,但仍然有一定的可能出现攻击失败的情况,这也许与随机明密文对的产生有关,也可能是我在程序编制过程中没有意识到的错误。
    在明密文对取到一定大的值时,线性分析为 7200,差分分析为180,可近似认为密码分析一定会成功,因为出现失败的概率已经很小。
    1 评论 31 下载 2018-10-31 17:58:40 下载需要7点积分
  • C++实现的基于NSM的简易数据库

    1 引言1.1 实验目的
    深入掌握数据库系统的原理和技术,进而从事数据库管理软件和工具的开发
    深入了解数据库系统的内部结构,以开发出高效的数据库应用系统

    1.2 实验要求实验的总体要求是:利用C++作为编程,使用Microsoft Visual Studio 2010实现基于NSM的简易数据库的设计,实现基于NSM的简易数据库。
    2 程序设计说明2.1 功能概述该基于NSM的简易数据库,实现的功能有:

    从文件中读取模式信息,并显示出来
    插入一条、多条元组到关系表中
    将TPC-H产生的Customer与Order表数据自动导入到相应文件
    在DBMS中对单表进行选择、投影操作
    Customer与Order表进行连接算法实现。选择三者之一实现:块嵌套循环连接算法、Hash连接算法、归并排序连接算法
    索引快速定位

    2.2 NSM的具体构造及解释
    NSM(N-ary Storage Model):Traditionally, database systems use the N-ary storage model (NSM), a page-based storage layout in which tuples (or rows) are stored contiguously in pages. NSM may waste disk and memory bandwidth if only a small fraction of each row is needed.

    变长记录的页面组织(page organization for variable-length record),每个槽slot<偏移record offset,记录程度record length>

    NSM的一条记录实例:All fields of record stored together + slots

    3 程序实现3.1 流程及算法描述命令模拟MySQL的命令。Main的while函数实现消息队列。

    3.2 主要函数及其调用关系
    3.2.1 程序类结构图
    3.2.2 主要函数及代码实现见附件code文件夹,有详细的代码注释。
    3.3 测试样例运行结果3.3.1 程序主界面
    3.3.2 使用基础文字提示所有命令都是以分号结尾,否则会出现提示如下所示:

    命令1:help;
    显示帮助

    命令2:Clear;
    清除屏幕

    命令3:exit;
    离开终端

    命令4:use xxx;
    (xxx为数据库名字)切换数据库
    说明:数据库是一个全局变量,因为单人在同一时间只能使用一个数据库。
    例子:

    如果我们切换到数据库名为suzie的数据库下,显示customer这张表,实际上没有这张表,会出现没有这张表的提示。

    3.3.3 高级从文件中读取模式信息,并且显示出来。
    说明:程序下有database文件夹,表示存储的是每个数据库,database里每个文件夹表示一个数据库,里面有以.schema结尾的表示模式文件。
    命令4:desc xxx;
    (xxxx为表的名字,不需要加xxx.table)显示表结构

    插入一条,多条元组到关系表中:Insert into tablename values(“xxxx|xxxx”);
    例子:
    Test这张表原来共有4条记录

    自动导入表到相应文件:Load xx.txt
    说明:这时候会在database/库名/下生成xx.table(表文件)和xx.schema模式文件。
    例子:
    首先有test.txt文件(由TPH生成)

    输入命令:load test.txt;

    生成以下两种文件

    打开文件,可以看到生成的文件内容

    在DBMS中对单表进行投影操作:Select 字段名 from 表名

    索引查找
    说明:索引文件大小4KB,刚好是一次IO,然后通过索引文件找到实际物理磁盘上的位置,第2次I/O,所以本次查询共需要2次I/O
    演示:我只对test的name这一列做了索引
    命令:index test;

    3.4 实验中遇到的问题
    对于C++不熟练了,平时对于脚本使用惯了,没了好用的函数和库了
    文件的操作的不熟练。Fseek,fread,fopen,fwrite几个重点函数的学习
    Char与string 和模板类的学习
    对于B+的设计,通读了别人的代码,对于这类数据结构的实现遇到很多问题,仍然待解决

    4 总结通过这次实验,我对于c++这类底层的语言有了更深 的了解,不过对于数据库的底层组织认识更深了。
    平时使用数据库,人人都会使用,大家也都在谈NoSQL,海量数据之类的,MongoDB,redis,MySQL都使用过,但是用归用,原理上没有搞明白,会用再多的也没什么意思,只有在原理上搞明白了,就没有问题了。
    在我们的windows操作系统一次磁头读取的页(块)是4KB(Linux可以重新设置这个值),所以这在数据库系统设计是相当重要。特别重新认真学习了MySQL的实现,MyISAM和InnDB的设计上的区别和优化,B树,B+树的设计与实现,让我对于索引上的效率认识更加深刻了。
    1 评论 18 下载 2018-10-31 17:52:32 下载需要8点积分
  • 基于VC++和OpenCV实现的全民飞机大战游戏

    摘要
    功能:利用C++语言完成了一个小游戏项目-全民飞机大战,该游戏首先能够给用户提供注册,登录功能;提供了菜单栏及两种游戏模式,一种是无尽模式,另一种是一般模式;一般模式中用户通过控制玩家飞机攻击敌方飞机获得分数以及奖励,打死boss飞机后可进入下一关,难度一次增加;玩家也可捡取道具,获得生命值,变换飞机形态。无尽模式中玩家通过躲避炸弹,捡取星星获得奖励,随时间推移,炸弹移动速度加快。玩家飞机阵亡后会显示自己分数,及排行榜
    核心算法:游戏主控制算法、图片绘制算法、飞机移动算法、导弹追踪算法
    优点:有较为清楚的软件运行流程,用户可以登录注册,保存数据,还有两种模式可供用户选择,敌方导弹还有追踪功能
    不足:没有图形化的登录界面,画面感不强,游戏过程中道具种类较少,没有加入鼠标操作

    一、项目概述1.1 项目简介全民飞机大战,是一款经典的游戏。本软件,首先用户若有账号可以直接登录,若没有可以直接注册,然后登录。登陆成功进入菜单界面,选择模式,进入游戏。游戏中用户通过消灭敌方飞机获得分数,敌方飞机毁灭会爆出奖励,吃到奖励也可以加分,同时还有道具,飞机一共有三种形态,根据捡到道具个数,飞机依次变换形态。在击毁一定数量敌机后,会出现boos飞机,击毁boss飞机后会进入下一关卡,关卡难度依次递增。在通关或我方飞机阵亡时,会出现排行榜,记录当前获得分数,和排名。此软件还有无尽模式,飞机通过捡取奖励星星获得分数,若被障碍物炸弹击中会耗损生命值,根据时间推移,障碍物会移动越来越快,增加游戏难度。直到我方飞机阵亡,而后也会出现排行榜。此外游戏还设有音乐,按键等一些操作。
    1.2 功能要求


    编号
    功能模块
    输入描述
    操作步骤
    输出描述




    1
    开始系统
    程序已经运行

    系统开始


    2
    登录
    程序已经进行
    按 1键
    开始登陆


    3
    注册
    程序已经进行
    按 2 键
    开始注册


    4
    菜单界面
    程序已经运行
    通过按键
    选择模式


    5
    无尽模式
    程序已经运行
    按Enter 键进入
    开始游戏


    6
    一般模式
    程序已经运行
    按Enter 键进入
    开始游戏


    7
    退出游戏
    程序已经运行
    按Enter 键进入
    退出游戏


    8
    飞机上移
    程序已经运行
    按W键
    飞机向上移动


    9
    飞机下移
    程序已经运行
    按S键
    飞机向下移动


    10
    飞机左移
    程序已经运行
    按A键
    飞机向左移动


    11
    飞机右移
    程序已经运行
    按D键
    飞机向右移动


    12
    攻击
    程序已经进行
    按J键
    我方飞机发出子弹,不同飞机子弹类型不同


    13
    消灭
    程序已经进行
    玩家子弹与敌方飞机碰撞
    敌方飞机销毁,爆出奖励


    14
    消灭
    程序已经运行
    敌方子弹与玩家飞机碰撞
    玩家飞机掉血,直到被击毁,游戏结束


    15
    碰撞1
    程序已经运行
    敌方飞机与玩家飞机碰撞
    敌方飞机与玩家飞机都失血


    16
    计分
    程序已经运行

    击毁不同飞机,得到分数不同


    17
    碰撞2
    程序已经运行
    玩家飞机与奖励星星碰撞
    得到分数奖励


    18
    碰撞3
    程序已经运行
    玩家飞机与炸弹碰撞
    玩家飞机失血


    19
    排行榜
    程序已经运行,游戏结束

    显示当前分数,与排名


    20
    重玩游戏
    程序已经运行,游戏结束
    按Enter键
    进入菜单选项


    21
    退出游戏
    程序已经运行,游戏结束
    按ESC键
    退出游戏



    二、总体设计2.1 类关系图
    2.2 结构关系图
    简要说明:plane为飞机基类,mplane, Enemyplane, EnemyFightplane, EnemyBossplane分别为派生的子类,这样封装可以任意增加子类,删除子类,子类可以从基类继承方法,还可以对某些方法进行多态继承,子类统一使用同一接口,而自己在类中实现自己特有的方法。
    2.3 设计类图(所有类图)














    三、核心算法3.1 游戏总控算法该算法完成控制整个游戏进程的功能,判断游戏进行状态,对角色道具进行更新,该算法主要是通过CManager类中的Run函数进行控制,对枚举变量m_state进行判断达到控制开始,运行,结束界面。当m_state=0时,进入开始界面;m_state=1时,进入运行界面;m_state=2时,进入结束界面。流程图如下:

    算法对应实现函数:CManager类下的Run函数。
    3.2 导弹追踪该算法是Cbullet类下的Move,Angle函数,该两个函数用于敌方导弹追踪我方飞机,该算法先利用子弹,飞机的坐标,利用反三角函数算出角度,再利用三角函数sin,cos算出x,y方向的分速度,再进行子弹移动。流程图如下:

    算法对应实现函数:CBullet类下的Move,Angle函数。
    四、程序实现4.1 开发平台与编译运行要求


    硬件配置
    版本




    Windows操作系统
    Windows 10


    Microsoft Visual studio
    VS2013


    OpenCV
    2.4.11



    4.2 核心功能分析登录注册



    开始界面—菜单栏

    运行界面 – 无尽模式 – 一般模式


    结束界面: 实现分数显示,排行榜

    导弹追踪:玩家旁边的两枚导弹为追踪弹

    存储功能 – 用户注册

    存储功能 – 得分存储

    4.3 功能完成度


    编号
    功能模块
    完成情况描述
    完成度




    1
    开始系统
    出现登录,注册选择界面
    100%


    2
    登录
    登录成功,出现开始界面菜单
    100%


    3
    注册
    注册成功,出现登录界面
    100%


    4
    菜单界面
    出现菜单界面
    100%


    5
    无尽模式
    进入无尽模式
    100%


    6
    一般模式
    进入一般模式
    100%


    7
    退出游戏
    退出游戏
    100%


    8
    飞机上移
    飞机向上移动
    100%


    9
    飞机下移
    飞机向下移动
    100%


    10
    飞机左移
    飞机向左移动
    100%


    11
    飞机右移
    飞机向右移动
    100%


    12
    攻击
    子弹从飞机炮口发出
    100%


    13
    消灭
    敌方飞机消失,出现爆炸特效并且出现爆炸奖励
    100%


    14
    消灭
    玩家飞机掉血
    100%


    15
    碰撞1
    玩家飞机,敌方飞机都掉血
    100%


    16
    计分
    分数增加
    100%


    17
    碰撞2
    得分增加
    100%


    18
    碰撞3
    血量减少
    100%


    19
    排行榜
    显示当前分数与排行
    100%


    20
    重玩游戏
    游戏重新回到开始菜单界面
    100%


    21
    退出游戏
    退出游戏
    100%



    五、总结终于完成了该项目——全民飞机大战,在结束时,也对自己的游戏总结了一下,有些优点,也有些不足之出。优点:有较为清楚的软件运行流程,用户可以登录注册,保存数据,还有两种模式可供用户选择,敌方导弹还有追踪功能。不足:没有图形化的登录界面,画面感不强,游戏过程中道具种类较少,没有加入鼠标操作。完成此项目,自己收获也有很多,能够清楚地了解到制作一个软件所必要的流程,类的使用,继承,多态也有很好的了解,能够明白什么时候使用继承,什么方法有必要使用多态。虽然这些还不能熟练的使用,但是我会努力的学习使用它。
    1 评论 41 下载 2018-10-31 17:42:56 下载需要10点积分
  • 基于VC++的WIN32 API界面编程实现的百战天虫小游戏

    1 游戏介绍本游戏是建立在百战天虫游戏框架下的,具有完全不同的游戏背景的一款回合制对战游戏。游戏设计者受到口袋妖怪,以及近期上映的电影《神奇动物在哪里》的启发,设定了“收服精灵”的游戏背景。本游戏共分为两个阵营,HERO阵营,以及WIZARD(精灵)阵营。HERO阵营的目标为阻止精灵继续逍遥法外,但是为了保护珍稀精灵,HERO需要尽量避免杀死精灵,并且收服精灵。WIZARD阵营的目标为杀死HERO阵营中每一个英雄,防止他们继续追捕自己。
    2 功能说明
    人物移动:W键人物跳起、AD键分别控制人物左右移动
    发射武器:鼠标所处的位置为发射方向,按下Q键为蓄力,松开Q键为发射武器
    武器种类:武器共分两种,第一种为炮弹,在人物周围一定范围内爆开会对人物造成一定程度的杀伤;第二种为精灵球,仅限HERO阵营人物使用,当精灵的生命值低于一定的值的时候,精灵球在精灵身边爆开的时候会成功收服精灵
    画面移动:按下左右方向键可以平滑的移动画面

    3 流程图
    4 自评表
    5 遇到的问题和解决方案
    问题一:由于碰撞算法写的比较简单粗暴,所以在通过波浪形地形的时候会出现有一部分人物被挡在地形之下的情况。
    解决方法:采用比较瘦小的人物,使得人物的落脚面积比较小,这样上述问题可以得到缓解。
    问题二:随机地形算法是比较难写的,一开始写出来就是一个简单的正弦函数
    解决方法:还是以正弦函数为基础,对正弦函数的三个参量(周期,振幅,Y方向的偏移量)进行随机赋值,每一个周期更换一次,这样可以有效地生成随机地形。
    问题三:画面平滑移动的功能,原来只能直接直接跳转,而不能平滑移动
    解决方法:设定一个状态参量,当画面移动时,其他一切活动停止刷新,每次timeupdate画面移动一个小量,最后移动到预期位置的时候重新开始其他活动的刷新。
    问题四:加上背景音乐,看了网上很多的MCI编程的方法,但是还是不太懂
    解决方法:抱大腿(最后发现原来只要一两行代码就可以了QAQ)。

    6 心得体会其实刚开始写这个大作业的时候,还是有点小看了这个游戏。前前后后也写了两个多星期,有很多的事情是一开始没有想到的。比如画面平滑移动,刚开始的时候画面大小是限制住的,没有考虑到要画面移动的问题,所以一开始写流程的时候没有考虑到要加上一些参数来控制更加细致的游戏流程,所以后来加上画面平滑移动的时候就特别难受,也出了很多bug,调了很久。所以以后开始写这种工程的时候还是要在一开始考虑好要写哪些功能,而不是写一点想一点。
    还有一点,命名空间的统一是很重要的,一开始我还是按照原来给的框架中的命名规则来给新的变量命名,但是后来感觉太麻烦了,就使用了一些比较简单的命名方法,第一天写第二天就忘,还得重新看一遍程序才能弄明白当初自己的命名方法,所以以后在这种工程中就需要一套严格的命名空间。
    还有,良好的代码风格也是很重要的,有时候为了图方便,套循环、套判断的时候就有些层次没有缩进,这就导致了代码维护的时候的巨大的麻烦,貌似VS2015可以自动将代码规范化,可以考虑使用一下。
    最后,通过这次大作业,我感受到了一个工程的框架的重要性,虽然说助教给的框架一开始还是不太能看得懂,但是写到后来,发现这种框架是非常有利于工程的构建,(但是还是感觉global.cpp命名为global还是有点不太合理…)。
    7 游戏演示初始画面

    游戏说明

    游戏关卡选择

    游戏关卡1

    游戏关卡2

    游戏关卡3

    游戏关卡4

    游戏结束
    1 评论 47 下载 2018-10-31 17:28:34 下载需要12点积分
  • 基于AVL树表示的集合ADT实现与应用

    1 项目介绍1.1 设计目的平衡二叉树(AVL)作为一种重要的查找表结构,能有效地支持数据的并行处理。本设计使学生牢固掌握AVL树及其实现方法,并应用该结构实现集合抽象数据类型,提升学生对数据结构与数据抽象的认识,提高学生的综合实践与应用能力。
    1.2 设计内容本设计分为三个层次:

    以二叉链表为存储结构,设计与实现AVL树-动态查找表及其6种基本运算
    以AVL树表示集合,实现集合抽象数据类型及其10种基本运算
    以集合表示个人微博或社交网络中好友集、粉丝集、关注人集,实现共同关注、共同喜好、二度好友等查询功能

    1.3 主要数据对象
    好友集、粉丝集、关注人集等
    1.4 主要数据关系
    抽象层面AVL可以表示数据元素之间层次关系或一对多关系
    实际应用层面,所讨论的人物关系为集合内元素间的关系。立足于集合建立数据的逻辑模型

    1.5 主要运算与功能要求
    交互式操作界面(并非一定指图形式界面)
    AVL树的6种基本运算:InitAVL、DestroyAVL、SearchAVL、InsertAVL、DeleteAVL、TraverseAVL
    基于AVL表示及调用其6种基本运算实现集合ADT的基本运算:初始化set_init,销毁set_destroy,插入set_insert,删除set_remove,交set_intersection,并set_union,差set_diffrence,成员个数set_size,判断元素是否为集合成员的查找set_member,判断是否为子集set_subset,判断集合是否相等set_equal
    基于集合ADT实现应用层功能:好友集、粉丝集、关注人集等的初始化与对成员的增删改查,实现共同关注、共同喜好、二度好友等查询
    主要数据对象的数据文件组织与存储

    1.6 设计提示
    参考有关文献,实现AVL树的删除操作,维护其动态平衡,这可能是设计中较为复杂的算法;要求提供关键算法的时间与空间复杂度分析
    要求从互联网上获取测试数据集或随机生成测试数据集,数据集的大小具有一定规模;数据与结果以文件保存

    1.7 结构特点对一棵查找树(search tree)进行查询/新增/删除 等动作, 所花的时间与树的高度h 成比例, 并不与树的容量 n 成比例。如果可以让树维持矮矮胖胖的好身材, 也就是让h维持在O(log n)左右, 完成上述工作就很省时间。能够一直维持好身材, 不因新增删除而长歪的搜寻树, 叫做balanced search tree(平衡树)。非平衡树会影响树中数据的查询,插入和删除的效率。比如当一个二叉树极不平衡时,即所有的节点都在根的同一侧,此时树没有分支,就变成了一个链表。数据的排列是一维的,而不是二维的。在这种情况下,查找的速度下降到O(N),而不是平衡二叉树的O(logN)。
    AVL树是典型的平衡二叉树,定义如下:
    AVL树,它或者是一颗空二叉树,或者是具有下列性质的二叉树:

    其根的左右子树高度之差的绝对值不能超过1
    其根的左右子树都是二叉平衡树

    1.8 应用场景由于在查询以及插入上具有优良的特性,AVL树常用来构造动态查找表(Dynamic Search Table),可以在对数时间内完成插入或者查询操作。
    我们常常需要查询某一个元素是否在集合中,或者向集合中插入元素,因此集合可以认为是一种典型的动态查找表,基于AVL树实现的集合(称为TreeSet)因此在插入以及查询上具有非常好的性能,而集合的交并补差操作又可以基于查询和插入实现,因此也具有良好的性能。而常用社交软件微博中粉丝、朋友、关注以及兴趣皆可以抽象为一个集合,朋友是粉丝和关注的交集,共同好友是两个用户好友的交集,二度好友是两个用户好友的差集,基于TreeSet实现的微博应用也因此继承了AVL树优良的特性。
    2 模块设计2.1 主程序模块系统由三个主模块构成,具体如下图2.1.1:

    2.2 SystemMenu模块SystemMenu模块又由许多小的模块构成,具体如下图2.2.1:

    2.3 用户登陆模块用户登陆模块又由不同的小功能模块构成,具体如下图2.3.1:

    3 数据结构设计3.1 AVLTreeNode类template<typename T>class AVLTreeNode{public: T data; //树节点的值 int height; //以该节点为根的树的高度 unsigned int num; //查找次数 AVLTreeNode* lChild; //指向左孩子 AVLTreeNode* rChild; //指向右孩子 /*构造函数*/ AVLTreeNode() :lChild(NULL), rChild(NULL), num(1), height(0) {} int getHeight(AVLTreeNode<T>* node) ; void Visit() ;};
    3.2 AVLTree类//AVL树类的属性和方法声明template<typename T>class AVLTree{private: AVLTreeNode<T>* root;//根节点 int size;//元素个数 bool IsElempri(AVLTreeNode<T>* node, T e) ;//判断e是否为node的元素 bool insertPri(AVLTreeNode<T>* &node, T x);//插入 void insertPri(AVLTreeNode<T>* &node, vector<T> vec); void insertPri(AVLTreeNode<T>* &node, AVLTreeNode<T>* tree2); void insertPri(AVLTreeNode<T>* &node, AVLTree<T> avltree); AVLTreeNode<T>* findPri(AVLTreeNode<T>* &node, T x);//查找 vector<T> InOrderTraverse( AVLTreeNode<T> * node) ;//中序遍历 bool DeletePri(AVLTreeNode<T>* &node, T x);//删除 void destroypri(AVLTreeNode<T>* &node); AVLTreeNode<T>* SingleRotateLeft(AVLTreeNode<T>* &k2);//左左单旋转 AVLTreeNode<T>* SingleRotateRight(AVLTreeNode<T>* &k2);//右右单旋转 AVLTreeNode<T>* DoubleRotateLR(AVLTreeNode<T>* &k3);//左右双旋转 AVLTreeNode<T>* DoubleRotateRL(AVLTreeNode<T>* &k3);//右左双旋转 int Max(int compa, int compb);//求最大值 int Heightpri(AVLTreeNode<T>* &node) ; void displayPri( AVLTreeNode<T>* node) ; void loadpri(FILE* fp,AVLTreeNode<T>* &node); void loadpri(char* path,AVLTreeNode<T>* &node); void loadpri(FILE* fp, AVLTreeNode<T>* &node, int elemNum); void savepri(FILE* fp, AVLTreeNode<T>* node) ; void savepri(char* path, AVLTreeNode<T>* node) ;public: /*构造函数*/ AVLTree() :root(NULL), size(0) {} AVLTree( vector<T> TVec); /*操作符重载*/ void operator=( AVLTree<T> &tree);/*赋值操作符重载*/ void Init(); void Init( vector<T> vec); AVLTreeNode<T>* getRoot();//返回根节点,用于测试 bool IsElem(T e) ;//判断e是否在树中 bool insert(T x);//插入接口 void insert( vector<T> vec); void insert( AVLTreeNode<T>* tree2); void insert( AVLTree<T> avltree); AVLTreeNode<T>* find(T x);//查找接口 bool Delete(T x); vector<T> Traverse() ;//遍历接口 void destroy();//销毁接口 int Size() ; void load(FILE* fp); void load(FILE* fp, int elemNum); void load(char* path); void save(FILE* fp) ; void save(char* path) ; void display() ; void display(ostream& ofile); void getRandom(int elemNum); int Height() ; //void operator=( AVLTree<T> avl);};
    3.3 TreeSet类template<typename T>class TreeSet{private: AVLTree<T> item;//集合容器,AVLTreepublic: TreeSet();/*构造函数*/ //TreeSet(AVLTree<T> avlTree); TreeSet(vector<T> TVec); void Init();/*初始化*/ void Init( vector<T> TVec); //void Init( AVLTree<T> TAvl); void Destory();/*销毁*/ bool insert(T e);//插入 void insert( vector<T> vec); void insert( AVLTreeNode<T>* tree2); void insert( AVLTree<T> avltree); void insert( TreeSet<T> ts); bool remove(T e);//删除 vector<T> Traverse() ; TreeSet<T> intersection( TreeSet<T>& s) ;//交集 TreeSet<T> Union( TreeSet<T>& s) ;//并集 TreeSet<T> difference( TreeSet<T>& s) ;//差集 int Size() ;//集合元素个数 bool IsMember( T e) ;//是否为成员 bool IsSubset( TreeSet<T>& s) ;//是否为子集 bool equal( TreeSet<T>& s) ;//是否相等 TreeSet<T> operator+( TreeSet<T>& s) ;//并集 TreeSet<T> operator-( TreeSet<T>& s) ;//差集 void operator=( TreeSet<T> &ts);//赋值 void display(); void load(FILE* fp); void load(FILE* fp, int elemNum); void load(char* path); void save(FILE* fp) ; void save(char* path) ; void getRandom(int elemNum);};
    3.4 User类相关数据结构定义:
    typedef string Hobby;/*兴趣*/typedef string Name;/*姓名*/typedef string Password;/*密码*/typedef string Account;/*账号*/typedef struct People{ Account account;//用户账号 Password password;//密码 Name name;//用户姓名 bool operator<(struct People p) { return account < p.account; } bool operator>(struct People p) { return account > p.account; } bool operator==(struct People p) { return account == p.account; } bool operator<=(struct People p) { return account <= p.account; } bool operator>=(struct People p) { return account >= p.account; } bool operator!=(struct People p) { return account != p.account; } void operator=( struct People &p) { account = p.account; name.assign(p.name); password.assign(p.password); }}People;
    用户User类如下:
    class User{private: People self;//自己的相关信息 TreeSet<Hobby> hobby;//兴趣列表 TreeSet<Account> friends;//好友集合,所谓好友即为互相关注的 TreeSet<Account> fans;//粉丝集合,即关注该用户的 TreeSet<Account> attention;//关注集合,即该用户关注的 void IO_OP(ostream& ofile, int mode,User& other) ;/*文件操作*/public: User(); User(People); User(Account account, Password password, Password name); User(Account account); bool operator<( User p) ; bool operator>( User p) ; bool operator==( User p) ; bool operator<=( User p) ; bool operator>=( User p) ; bool operator!=( User p) ; void operator=( User &p); /*可读接口*/ Account getAccount() ; Password getPassword() ; Name getName() ; vector<Account> getFriends() ; vector<Account> getFans() ; vector<Account> getAttention() ; vector<Hobby> getHobby() ; bool IsFriends(Account people) ; bool IsFans(Account people) ; bool IsAttention(Account people) ; bool IsHobby(Hobby h) ; int getHobbyNum() ; int getFriendsNum() ; int getFansNum() ; int getAttentionNum() ; /*可写接口*/ void setAccount( Account acc); void setPassword( Password newPassword); void setName( Name newName); void setFriends();//好友可由关注集合以及粉丝集合的交集得来 void addFriends( Account p); void removeFriends( Account p); void addFans( Account p); void removeFans( Account p); void addAttention( Account p); void removeAttention( Account p); void addHobby( Hobby h); void removeHobby( Hobby h); void setFriends( vector<Account> friendsVec); void setFans( vector<Account> fansVec); void setAttention( vector<Account> attentionVec); void setHobby( vector<Hobby> hobbyVec); void removeFriends( vector<Account> friendsVec); void removeFans( vector<Account> fansVec); void removeAttention( vector<Account> attentionVec); void removeHobby( vector<Hobby> hobbyVec); void load(istream& ifile, int hohNum, int friNum, int fansNum, int attNum) ; void save(ostream& ofile) ; void save_with_text(fstream& ofile) ; void print_by_self() ; void print_by_other( User& other) ; vector<Account> commonAttention( User& other) ; vector<Account> commonFriends( User& other) ; vector<Hobby> commonHobby( User& other) ;};
    3.5 系统数据SystemData定义typedef User ElemType;typedef void(*VisitFunction)(ElemType e);//定义visit函数类型typedef vector<User> SystemData;
    3.6 随机姓名产生类randomNameClassclass randomNameClass{public: randomNameClass(); virtual ~randomNameClass(); char* GetName();protected: void InitSurname(); void InitName(); char* m_pSurname_OneDimensional; char** m_ppSurname; // 姓 char* m_pName_OneDimensional; char** m_ppName; // 名 char m_szName[7]; // 3 个中文占 6 个字符};
    3.7 性能分析辅助数据结构性能分析模块将在庞大数据集上测试AVL树的操作性能,采用多线程的处理方式可以大大节省等待时间,让可以在同一个时间段内并行运行的任务同时运行。其中HashSet为基于哈希表HashMap实现的集合,用于和基于AVL树实现的集合TreeSet做对比,因HashSet不是本课设主要研究的问题,在此不展开说明。
    typedef struct TreeSet_insert_data{ TreeSet<int> treeSet; int size;} TreeSet_insert_data;typedef struct TreeSet_operation_data{ TreeSet<int> treeSet1; TreeSet<int> treeSet2; int mode;/*mode=1,2,3,4分别对应交并补差*/}TreeSet_operation_data;typedef struct HashSet_insert_data { HashSet<int, HashFuncInt, EqualFuncInt> hashSet; int size;}HashSet_insert_data;typedef struct HashSet_operation_data { HashSet<int, HashFuncInt, EqualFuncInt> hashSet1; HashSet<int, HashFuncInt, EqualFuncInt> hashSet2; int mode;}HashSet_operation_data;
    4 关键算法描述及复杂度分析4.1 查找算法Search in AVLTreeAVL树是典型的查找树。当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,若小于根节点值,则在左子树上进行查找,若大于根节点值,则在右子树上进行查找,若根节点为空,则查找失败。
    复杂度:该算法为递归算法,考虑最坏情况下的时间复杂度,即查找失败或在树的最深处找到该元素。最长查找路径为根节点到叶子节点的距离,而树的深度为logN,因此Searchin AVLTree时间复杂度为O(logN)。
    4.2 插入算法Insert在AVL树AVLTREE上插入一个新的数据元素e的递归算法可描述如下:

    若AVLTREE为空树,则插入一个数据元素为e的新结点作为AVLTREE的根结点,树的深度增1
    若e的关键字和AVLTREE的根结点的关键字相等,则不进行插入
    若e的关键字小于AVLTREE的根结点的关键字,而且在AVLTREE的左子树中不存在和e有相同关键字的结点,则将e插入在AVLTREE的左子树上,并且当插入之后的左子树深度增加(+1)时,分别就下列不同情况处理之:

    AVLTREE的根结点的平衡因子为-1(右子树的深度大于左子树的深度),则将根结点的平衡因子更改为0,AVLTREE的深度不变
    AVLTREE的根结点的平衡因子为0(左、右子树的深度相等):则将根结点的平衡因子更改为1,AVLTREE的深度增1
    AVLTREE的根结点的平衡因子为1(左子树的深度大于右子树的深度):则若AVLTREE的左子树根结点的平衡因子为1:则需进行单向右旋平衡处理,并且在右旋处理之后,将根结点和其右子树根结点的平衡因子更改为0,树的深度不变

    若e的关键字大于AVLTREE的根结点的关键字,而且在AVLTREE的右子树中不存在和e有相同关键字的结点,则将e插入在AVLTREE的右子树上,并且当插入之后的右子树深度增加(+1)时,分别就不同情况处理之,处理情况类似步骤(3)。

    旋转情况如下:
    左左情况

    左右情况

    右右情况

    右左情况

    时间复杂度分析:经过上述分析,该算法的时间复杂度主要集中在两部分,第一部分为找到该元素在树中的位置,时间复杂度为O(logN),第二部分为调节平衡,由于AVL树左右子树皆保持平衡,因此该步骤可在常数时间内完成。故总的时间复杂度为O(logN)。
    4.3 删除算法Delete删除AVL树AVLTREE上某一个元素e大致有三种情况:

    该元素所在节点为叶子节点,即左右子树皆为空
    该节点的左子树或者右子树为空
    左右子树皆不空

    从AVLTREE根节点向下检查,若根节点元素和e相等,若为第一种情况,则直接释放根节点存储空间,AVLTREE成为空树;若为第二种情况,假设左子树为空,则AVLTREE的根节点成为右子树的根节点,释放原根节点空间,由于左右子树皆保持平衡,因此新的AVLTREE仍然保持平衡;若为第三种情况,则可以递归地向下删除该元素,递归策略为:

    将根节点元素值赋值为左子树中元素值最大的或者右子树中元素值最小的,左子树中元素值最大的节点为最右端的节点,右子树中元素值最大的节点为最左端的节点,在此假设选择左子树中元素值最大的节点,由于平衡二叉树的性质,根节点元素赋值后AVLTREE仍然满足查找树性质
    根节点元素值赋值为左子树LTree中最大元素值LMax后,我们需要在左子树中删除该元素LMax
    在LTree中删除元素LMax遵循同样的原则,当递归执行到树的最底时,删除条件自动满足三种情况的(1)或者(2)
    删除该节点后,根节点可能会出现失衡,比对4.2中介绍的失衡调节方法调节平衡

    该算法需要回答两个问题:

    删除某个元素后,AVLTREE是否仍然保持平衡?
    该算法的时间复杂度是什么?

    回答:仍然平衡。对于第(1)(2)中情况,结论毋庸置疑,平衡性自动满足。对于第(3)种情况,我们向下执行删除操作时,递归返回的情况也是遇到了(1)(2)情况,而在每一次递归返回时,相当于子树完成删除操作,我们每次都会检查子树根节点是否失衡,如果失衡会调节平衡,因此当完成对元素e的删除后,整棵树是从下往上动态的维持了平衡的特性。
    该算法的时间复杂度主要集中在两部分,第一部分为找到元素在AVLTREE中的位置,即Search算法,复杂度为O(logN),第二部分为调节平衡,我们假设为一个最糟糕的情况,删除根节点元素,并且从最底层网上需要不断的调节平衡,如前所述,由于AVL树左右子树皆平衡的特点,一次调节平衡可以在常数时间内完成,我们假设的最糟糕情况需要调节平衡的次数为树的深度,因此时间复杂度为O(logN)。故总的时间复杂度为O(logN)。
    4.4 插入用户InsertUserInsertUser是微博系统中经常被调用的一个函数,该函数的算法思想来源于简单插入排序,即向一个有序的数组中插入一个元素使插入元素后的数组仍然有序。
    该算法时间复杂度为O(N),在这里不宜直接在数组末尾插入的方法以及其他时间复杂度更低的排序算法,原因有二:

    微博系统中需要大量用到定位函数LocateUser,如果数组有序可以大大加快定位速度,直接在数组末尾插入会导致数组杂乱无章,因此不宜使用此方法
    其他复杂度更低的排序算法,以快速排序为例,快速排序操作过程中需要频繁的对元素进行移动和交换,而数组中User类是一个数据项较大的类,粉丝、朋友、关注以及兴趣这些集合的容器为AVL树,若要对User类进行拷贝赋值需要反复调用底层AVLTree的Insert插入函数,因此对User类的赋值在时间上是一笔庞大的开销,我们应该尽量避免这种赋值,所以不宜使用其他复杂度更低的排序算法

    4.5 定位用户LocateUserLocateUser函数是在Application层微博应用中被调用最频繁的一个函数,该函数算法思想来源于折半查找,在InsertUser保证数组有序的前提下,LocateUser的折半查找路线为一棵查找树,时间复杂度为查找树的深度,即O(logN)。
    5 程序实现5.1 开发环境及其他依赖开发所用IDE为Microsoft Visual Studio Community 2017(以下简称VS),所用编译器为Microsoft Visual C++ 2013。pthread.h线程库头文件为Linux上开源头文件,下载地址为http://sourceware.org/pthreads-win32 ,该地址同时包含所需的库文件(即.lib文件和.dll文件)。由于引入线程库,因此需要在程序运行目录下复制动态库文件pthreadVC2.dll。VS下使用线程库的方法见于CSDN博客 http://blog.csdn.net/u010097616/article/details/53708718 。
    5.2 系统头文件#include<vector>#include<stack>#include<string>#include<iostream>#include<ostream>#include<istream>#include<fstream>#include<set> /*标准库stl集合,用于在性能测试中和TreeSet做对比*/#include<algorithm>/*stl集合交并补差运算*/#include<cstdlib>#include<conio.h>#include<time.h>#include<math.h>#include<pthread.h>/*c++线程库头文件*/
    5.3 预处理#pragma comment(lib,”pthreadVC2.lib”)/*用于加载线程库*/
    5.4 全局变量SystemData sysData;/*系统全局变量,所有用户的载体*/
    说明:在程序中使用全局变量不认为是一种明智的方法,良好的模块化编程习惯应该尽量避免全局变量的出现。
    5.5 主要功能函数原型程序部分功能函数原型已在第三部分——数据结构定义及声明中描述,在此只描述除此之外的其他功能函数。
    /*文件操作模块*/void LoadData(SystemData& sys, const char* path1 = "systemRelation.dat", const char* path3 = "systemString.txt");void SaveData(SystemData sys, const char* path1 = "systemRelation.dat", const char* path3 = "systemMessage.txt", const char* path4 = "systemString.txt");void InsertUser(SystemData& s, User u);Position LocateUser( SystemData& s, Account acc);Position LocateUserCore( SystemData& s, Account acc, int low, int high);void VisitUser(ElemType e);void SystemTraverse( SystemData s, VisitFunction visit);void SystemMenu();void Register();void Register(SystemData &s, User& u);void Register(SystemData &s,Account acc, Name name, Password password);int Login();void PerformanceTest();void About();void AllUsers();void UserMenu(User &u);void RandomData(SystemData& s);void AddFriends(User& u,Account acc);void DeleteFriends(User & u, Account acc);void AddAttention(User & u, Account acc);void DeleteAttention(User & u, Account acc);void AddHobby(User & u, Hobby h);void DeleteHobby(User & u, Hobby h);void AddFans(User& u, Account acc);/*性能测试模块*/void* treeSet_insert_test(void* insert_data);void* treeSet_operation_test(void* operation_data);void* hashSet_insert_test(void* insert_data);void* hashSet_operation_test(void* operation_data);/*格式化打印vector*/template<typename Elemtype>void print_vec(std::ostream& ofile, std::vector<Elemtype> Vec);
    6 测试和结果分析6.1 系统界面
    6.2 文件模块6.2.1 加载系统数据LoadData
    6.2.2 保存系统数据SaveData
    6.3 AVLTree 模块6.3.1 Insert插入元素
    6.3.2 查找Search in AVLTree
    6.3.3 Delete删除元素
    6.3.4 Traverse遍历AVLTree
    6.4 TreeSet模块6.4.1 往集合TreeSet插入元素
    6.4.2 删除集合元素
    6.4.3 判断元素是否在集合中
    6.4.4 交集
    6.4.5 并集
    6.4.6 差集
    6.4.7 判断是否为子集
    6.4.8 判断两个集合是否相等
    6.4.9 集合的遍历方式调用的AVLTree的遍历接口,因此遍历形式一致
    7 特色与不足7.1 特色我觉得这次课设的特色主要体现在以下四点:

    采用面向对象的编程技术,底层AVLTree采用模板类实现,并且较好地封装了对外的函数接口,系统的AVLTree和TreeSet测试采用的均为int整型数据,而Application微博应用层考虑到账户的多样性,不宜直接使用数字账户,因此账户类型为string类型,而且兴趣也为string类型,正是因为使用了模板类,使得我们不必为了重复的功能去编写类似的代码。
    系统具有方便而可靠的随机数据生成功能,该系统的随机数据生成功能可以让程序测试人员瞬间产生庞大的数据量,这些数据会保存到一个文本文件randomTestMessage.txt,数据量足够庞大的时候如果我们文件中信息与我们期待的吻合那我们将有充分的理由相信我们编写的程序无误,我们不需要每次都要去做那些琐碎繁琐的重复劳动来验证我们的程序是否正确。
    全面高效的性能测试。通过6.6.2的测试截图我们知道,TreeSet的性能在中小数据集上性能优异,考虑到现实应用(比如本课设中的好友集和兴趣集)大概率上不会超过1000,因此这个TreeSet完全能够满足微博应用系统的需要,通过性能测试我们也发现基于哈希表HashMap实现的集合HashSet在性能上几乎全面包围TreeSet,这点的原因我们早已经在数据结构课程里明白,哈希表采用的是空间换时间的策略,哈希表的所需存储空间是AVLTree的两倍,因而能够获得常数时间的操作时间复杂度,那我们是否应该用HashSet替代TreeSet,答案是不必要,因为如前所述,TreeSet已经完全能够满足我们的需要,而现实应用中集合中的元素常常蕴含着庞大的数据,我们若采用HashSet我们需要浪费大量的存储空间,这显然是不值的。当我们的测试数据集增长到50000时,TreeSet在性能上已显疲惫,若这时我们采用传统串行执行的策略,即第二个测试发生于第一个测试完成之后,这样子是非常不明智的,我们将会在重复的操作中浪费大量时间,所以我们采用了多线程并行测试每个功能的方法,在同一时间高效的完成了重复的不同测试。
    基于流的输入输出处理。该系统Application层的输出基本上都是对两个函数的调用,第一个为User类private成员函数IO_OP(ostream&ofile, int mode),第二个为格式化打印函数print_vec(std::ostream& ofile,std::vector<ElemType>vec),这两个函数帮助我们方便的在屏幕上显示用户信息,也帮助我们很方便的将用户信息输出到文本文件。

    7.2 不足该系统的不足也是我这次对于本课设比较大的遗憾吧,主要体现在以下三点:

    系统没有简单易交互的图形界面,黑框框的程序操作界面在输入上存在严重的瑕疵,用户的不合法输入容易导致程序不正确运行或者运行自己不希望执行的功能。
    由于时间仓促且学习C++的时间不长,在设计数据结构的时候没有充分体现面向对象的编程思维,程序存在大量丑陋的冗余代码,到写到一半的时候已经发现无法回头了,只能望而生叹,争取下次先构思好再写。
    我们很好地完成了AVLTree的基本功能,Insert,Search以及Delete,却没有对这些功能进行很好的优化,在细节上存在一些瑕疵,算法的时间复杂度虽然较低但因为这些细节上的瑕疵程序仍然体现出比较高的时间复杂性,比如通过性能测试的截图我们发现在O(logN)时间复杂度内执行的算法实际上并没有想象中的快。另外,在程序中我们也没有很好的完成对AVLTree的拷贝赋值操作,我们只是不断的调用Insert函数来进行赋值操作,使得程序中很多不显眼的地方也呈现出O(logN)的时间复杂度。
    1 评论 5 下载 2018-10-31 17:12:29 下载需要5点积分
  • 基于虚拟存储区和内存工作区的页面置换算法

    一 需求分析编写程序实现:

    先进先出页面置换算法(FIFO)
    最近最久未使用页面置换算法(LRU)
    最佳置换页面置换算法(OPT)

    设计一个虚拟存储区和内存工作区,编程序演示以上三种算法的具体实现过程,并计算访问命中率,演示页面置换的三种算法,通过随机数产生一个指令序列,将指令序列转换为页地址流,计算并输出各种算法在不同内存容量下的命中率。
    二 程序设计2.1 功能设计
    产生随机序列功能

    随机生成1-128之间的整数,作为指令序列号,同时将随机生成的数字除以10取余作为该指令的页地址,随机数的生成以当前时钟做种子,保证每次生成的随机性。
    算法运行功能

    根据先进先出算法进行页面置换
    根据最近最久未使用算法进行页面置换
    根据最佳置换页面算法进行页面置换

    结果分析功能

    计算先进先出算法命中率
    计算最近最久未使用算法命中率
    计算最佳置换页面算法命中率
    分析出最优算法

    演示效果功能

    手动运行页面置换算法,一次运行一步
    自动运行页面置换算法,系统每个时间间隔自动运行一步


    2.2 运行流程程序流程图如下所示:

    算法流程图如下所示:

    三 程序实现3.1 FIFO算法 if (comboBox.getSelectedItem().equals("FIFO")) { for (int a = 0; a < block; a++) Memory[a] = -1; // 初始化为-1 for (int q = 0; q < 128; q++) { flag = false; pos++; int temp = seq[pos];// 中间变量暂时存放当前指令所在页地址 // 查看是否已经存在内存中 for (int i = 0; i < block; i++) { if (Memory[i] == temp) {// 如果命中,命中数+1,跳出循环 FIFOhit++; flag = true; break; } } // 如果未命中,考虑是否要替换 if (!flag) { if (memorynum < block) {// 如果内存没满,则不用替换 Memory[memorynum] = temp; memorynum++; } else {// 如果内存已满,选择最早调入的页面进行替换 Memory[replacepos] = temp;// Memory[replacepos]为被替换的元素,第一次满即替换memory[0] changecolor[replacepos][pos + 1] = 1;// 标记待变颜色的表格框 replacepos = (replacepos + 1) % block;// 按照block大小来循环替换 } } for (int i = 0; i < block; i++) data1[i][pos + 1] = Memory[i]; } // 显示命中率 FIFOrate.setText(String.valueOf((double) FIFOhit / 128)); int a = 0; for (int i = 0; i < block; i++) { a = i + 1; data1[i][0] = "第" + a + "块"; } DefaultTableModel tableModel1 = new DefaultTableModel(data1, tableTitle); // 表格模型对象 JTable Result1 = new JTable(tableModel1); int columnCount1 = Result1.getColumnCount(); Result1.getColumnModel().getColumn(0).setPreferredWidth(80); for (int i = 1; i < columnCount1; i++) { TableColumn tableColumn1 = Result1.getColumnModel().getColumn(i); tableColumn1.setPreferredWidth(80); } Result1.setRowHeight(40);// 指定每一行的行高40 Result1.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); JScrollPane jspResult1 = new JScrollPane(Result1); jspResult1.setBounds(10, 10, 1018, 320); jspResult1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); jspResult1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); TableCellRenderer tcr1 = new ColorTableCellRenderer(block, changecolor); Result1.setDefaultRenderer(Object.class, tcr1); JFrame FIFO = new JFrame("FIFO算法结果 命中率:" + (double) FIFOhit / 128); FIFO.getContentPane().setLayout(null); FIFO.setBounds(920, 10, 1048, 380); FIFO.setDefaultCloseOperation(2); FIFO.getContentPane().add(jspResult1); FIFO.setVisible(true); }
    3.2 LRU算法 if (comboBox.getSelectedItem().equals("FIFO")) { for (int a = 0; a < block; a++) Memory[a] = -1; // 初始化为-1 for (int q = 0; q < 128; q++) { flag = false; pos++; int temp = seq[pos];// 中间变量暂时存放当前指令所在页地址 // 查看是否已经存在内存中 for (int i = 0; i < block; i++) { if (Memory[i] == temp) {// 如果命中,命中数+1,跳出循环 FIFOhit++; flag = true; break; } } // 如果未命中,考虑是否要替换 if (!flag) { if (memorynum < block) {// 如果内存没满,则不用替换 Memory[memorynum] = temp; memorynum++; } else {// 如果内存已满,选择最早调入的页面进行替换 Memory[replacepos] = temp;// Memory[replacepos]为被替换的元素,第一次满即替换memory[0] changecolor[replacepos][pos + 1] = 1;// 标记待变颜色的表格框 replacepos = (replacepos + 1) % block;// 按照block大小来循环替换 } } for (int i = 0; i < block; i++) data1[i][pos + 1] = Memory[i]; } // 显示命中率 FIFOrate.setText(String.valueOf((double) FIFOhit / 128)); int a = 0; for (int i = 0; i < block; i++) { a = i + 1; data1[i][0] = "第" + a + "块"; } DefaultTableModel tableModel1 = new DefaultTableModel(data1, tableTitle); // 表格模型对象 JTable Result1 = new JTable(tableModel1); int columnCount1 = Result1.getColumnCount(); Result1.getColumnModel().getColumn(0).setPreferredWidth(80); for (int i = 1; i < columnCount1; i++) { TableColumn tableColumn1 = Result1.getColumnModel().getColumn(i); tableColumn1.setPreferredWidth(80); } Result1.setRowHeight(40);// 指定每一行的行高40 Result1.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); JScrollPane jspResult1 = new JScrollPane(Result1); jspResult1.setBounds(10, 10, 1018, 320); jspResult1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); jspResult1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); TableCellRenderer tcr1 = new ColorTableCellRenderer(block, changecolor); Result1.setDefaultRenderer(Object.class, tcr1); JFrame FIFO = new JFrame("FIFO算法结果命中率:" + (double) FIFOhit / 128); FIFO.getContentPane().setLayout(null); FIFO.setBounds(920, 10, 1048, 380); FIFO.setDefaultCloseOperation(2); FIFO.getContentPane().add(jspResult1); FIFO.setVisible(true); }
    3.3 OPT算法 if (comboBox.getSelectedItem().equals("FIFO")) { for (int a = 0; a < block; a++) Memory[a] = -1; // 初始化为-1 for (int q = 0; q < 128; q++) { flag = false; pos++; int temp = seq[pos];// 中间变量暂时存放当前指令所在页地址 // 查看是否已经存在内存中 for (int i = 0; i < block; i++) { if (Memory[i] == temp) {// 如果命中,命中数+1,跳出循环 FIFOhit++; flag = true; break; } } // 如果未命中,考虑是否要替换 if (!flag) { if (memorynum < block) {// 如果内存没满,则不用替换 Memory[memorynum] = temp; memorynum++; } else {// 如果内存已满,选择最早调入的页面进行替换 Memory[replacepos] = temp;// Memory[replacepos]为被替换的元素,第一次满即替换memory[0] changecolor[replacepos][pos + 1] = 1;// 标记待变颜色的表格框 replacepos = (replacepos + 1) % block;// 按照block大小来循环替换 } } for (int i = 0; i < block; i++) data1[i][pos + 1] = Memory[i]; } // 显示命中率 FIFOrate.setText(String.valueOf((double) FIFOhit / 128)); int a = 0; for (int i = 0; i < block; i++) { a = i + 1; data1[i][0] = "第" + a + "块"; } DefaultTableModel tableModel1 = new DefaultTableModel(data1, tableTitle); // 表格模型对象 JTable Result1 = new JTable(tableModel1); int columnCount1 = Result1.getColumnCount(); Result1.getColumnModel().getColumn(0).setPreferredWidth(80); for (int i = 1; i < columnCount1; i++) { TableColumn tableColumn1 = Result1.getColumnModel().getColumn(i); tableColumn1.setPreferredWidth(80); } Result1.setRowHeight(40);// 指定每一行的行高40 Result1.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); JScrollPane jspResult1 = new JScrollPane(Result1); jspResult1.setBounds(10, 10, 1018, 320); jspResult1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); jspResult1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); TableCellRenderer tcr1 = new ColorTableCellRenderer(block, changecolor); Result1.setDefaultRenderer(Object.class, tcr1); JFrame FIFO = new JFrame("FIFO算法结果命中率:" + (double) FIFOhit / 128); FIFO.getContentPane().setLayout(null); FIFO.setBounds(920, 10, 1048, 380); FIFO.setDefaultCloseOperation(2); FIFO.getContentPane().add(jspResult1); FIFO.setVisible(true); }
    四 运行测试初始化界面如下:


    功能选择界面如下:

    运行结果界面如下:



    动态演示界面如下:

    1 评论 26 下载 2018-10-31 16:57:07 下载需要9点积分
  • 基于C语言的Linux环境的文件系统

    一 需求分析
    设计多用户文件系统,采用二级文件目录
    要有多个实用命令,应设置文件保护措施
    设计一个较实用的用户界面,方便用户使用,界面要为用户提供足够的选择信息

    二 程序设计系统框架如下图所示:

    三 程序实现3.1 关键数据结构 struct Unode //UFD{ char FileName[8]; char str[32]; char ProCode[3]; int Length; enum FileStatus Status; struct Mnode *Dir; struct Unode *Next;};struct Mnode //MFD{ char DirName[8]; struct Unode *Dir; struct Mnode *Next;}
    3.2 关键函数AddUser(char *new) //添加用户CloseFile(char *filename) // 关闭文件 DelFile(char *filename) // 删除文件DisplayFils(void) // 显示当前目录Login(char *userName) // 登录ModPro(char *code) // 修改保护码ReadFile() // 读文件 WriteFile(); // 写文件 OpenFile(char (filename)// 打开文件InitFilsSystem() // 初始化系统
    3.3 系统模块架构如下图所示:

    此系统一个字符串数组来模拟磁盘空间,程序运行时先初始化用户名构成单链表,每次插入新用户于表尾。
    磁盘空间分配表,采用链表结构,每个节点保存模拟磁盘的一个逻辑块的信息,包括块的最大长度,文件占用长度,占用标志。如果占用标志为0,即该空间可分配给文件。初始化磁盘空间分配表链表,首先把整个模拟磁盘作来一块,并置占用位为0。当有进程申请磁盘空间时,从头开始遍历,检查占用位,如果该块为可分配,则检查块大小,若块长度大于或等于申请空间大小,则把块的前一部分(等于申请大小)分配给文件,并置标志位为占用。剩下的大小作来一个新块,作来一个新节点插入到原节点的后边,标志位为可用。这样就实现了模拟磁盘的线性分配。
    3.4 算法流程图如下图所示:

    四 运行测试如下图所示:

    2 评论 14 下载 2018-10-31 16:26:54 下载需要6点积分
  • 基于Android实现的文件系统模拟

    一、使用说明1.1 项目简介在内存中开辟一个空间作为文件存储器,在其上实现一个简单的文件系统。本项目基于Android的操作系统,来模拟实现文件管理系统,并且学习Android环境下使用Java实现申请磁盘空间、分配并管理物理空间以及多级目录结构。
    1.2 项目功能
    在内存中开辟一个空间作为文件存储器,在其上实现一个简单的文件系统
    退出这个文件系统时,需要该文件系统的内容保存到磁盘上,以便下次可以将其回复到内存中来
    文件存储空间管理采取显式链接
    空闲空间管理采用位图
    文件目录采用多级目录结构,目录项目中包含:文件名、文件大小、创建日期、文件类型信息
    该文件系统提供操作:格式化、创建文件夹、删除文件夹、显示目录、更改当前目录、创建文件、打开文件、关闭文件、写文件、读文件、删除文件、复制、粘贴、查看属性、退出系统

    1.3 操作手册运行程序后,首先进入文件管理系统操作界面。

    新建文件(文件夹)并命名
    点击右上角“+”按钮可以新建文件或文件夹,并可以给该文件或文件夹命名。



    效果1
    效果2
    效果3










    读文件/写文件
    读文件操作,点击创建的文本文件(点击图标),会显示该文本文件内容。
    默认情况下文本文件为空,可以在编辑框输入文字。
    编辑框下方提供三种操作,“关闭”直接关闭文件,“保存”将当前编辑框内容追加到文本后方,“重新保存”将当前编辑框内容覆盖原文本文件。



    效果1
    效果2
    效果3










    目录框
    建立文件夹后,点击图标可以进入文件夹内,上方目录框会显示当前物理位置。
    点击左上方的“后退”按钮,可以返回上一级目录。

    复制/粘贴
    长按文件(文件夹),会提供四种操作,点击最上方的“复制”会复制该文件(文件夹)。
    之后可以在本目录下或其他目录下长按其他文件,点击操作中的“粘贴”会将该文件(文件夹)复制到该目录下。若复制的为文件夹,文件夹目录下的文件一同复制。



    效果1
    效果2









    属性
    长按文件(文件夹),会提供四种操作,点击“属性”会显示该文件(文件夹)的属性。

    删除
    长按文件(文件夹),会提供四种操作,点击“删除”会删除当前文件(文件夹)。若删除的为文件夹,文件夹目录下的所有文件一并删除。
    格式化
    点击最下方红色按键“格式化”,会将当前磁盘内所有内容删除。

    退出系统
    点击右上方的“×”可以从Android平台上完全退出当前文件管理系统。
    1.4 注意事项
    在根目录下无法点击“后退”按键进入上一层目录


    在同一目录下无法创立同一类型具有相同名称的文件(文件夹)


    在同一目录下粘贴同一类型具有相同名称的文件(文件夹)时,系统会自动在后面加上“(1)”,并且后方的数字会随着同一文件复制粘贴次数的增加而增加


    创建的文件(文件夹)名字不可以为空
    二、概述2.1 基本思路该文件操作管理项目在存储空间管理上采取的是显式链接,在空闲空间管理上采用的是位图,在文件目录上采用的是多级结构。

    显式链接:每一个PCB只需要记录着它在链接结构中的起始地址和终止地址。除终止地址外,每一个地址都会指向存储空间的下一个地址,在调用该文件时按这种方式就可以查找到该文件,通过这种方式提高对磁盘空间的利用率
    位图:文件Client.java为位图管理,通过位图可以有效的对磁盘空闲位置进行管理,用一串二进制位反映磁盘空间中的分配使用 情况, 每个物理块对应一位, 分配物理块为1,否则为0。 申请物理块时,在位示图中查找为0的位,返回对应物理块号
    多级结构:采用树型目录结构,将每一级目录作为一组存储到树形目录结构中,同一级目录下的文件和文件夹利用左右兄弟节点相互连接,为每个文件夹创立相应的孩子节点以便在该目录下创建文件(文件夹),同时生产新一级目录。

    2.2 主要文件
    MainActivity.class & activity_main.xml (主文件,即文件管理系统操作界面)
    FCB.class(目录文件控制块)
    Client.class(位图管理文件)
    Folder_item.xml(文件或文件夹视图)

    三、具体实现3.1 FCB在该项目中引用了文件管理系统中FCB的概念,即文件控制块,其中包含了每个文件(文件夹)的一些状态以及一些属性:

    该项目中比较重要的是FCB临时存储器arr,该存储器存储着当前目录下的文件(文件夹)的FCB。当更改当前目录时,会将arr内容赋值给树型目录结构,同时arr会清空;当添加文件(文件夹)时,arr会增加相应内容。
    3.2 磁盘空间申请getAvailableInternalMemorySize(this);
    通过该函数向操作系统申请一定的空间作为文件存储器,在其上实现该项目。

    3.3 将文件内容保存到磁盘上读操作,利用Android系统自带的轻量级存储器SharedPreferences将存储在其中的根节点取出,并获得其子节点。

    写操作,首先将当前页面状态进行保存,之后将根节点保存到存储器中以便下次取出。

    3.4 多级目录结构利用java构造树型多级目录结构。在打开app时先判断存储器中是否有根节点的值,若有直接取出作为当前根节点,若没有则建立新的根节点。
    根节点的子节点为第一级目录结构下的文件(文件夹),每级目录结构下的文件(文件夹)之间通过左右兄弟节点相连接,并且每个文件(文件夹)都有其相应的父节点。对于文件夹,有一组子节点可以动态添加,而普通的文件则没有。这样的树型结构实现了快速查找文件的功能。
    每次在目录文件夹下添加文件(文件夹)时,利用current_node实现。Current_node代表当前指针位置,始终指向当前文件目录的最后一个文件,添加文件(文件夹)时,会为当前节点建立左兄弟节点,并将添加的节点与其相连,同时连接到父节点。
    在每次点击文件夹进入下一级目录时,current_node会置空,而点击的文件夹会作为当前目录的父节点,所有操作都建立在该父节点的子节点上。
    3.5 复制/粘贴复制操作比较简单,只需将选中的文件(文件夹)的FCB赋值给copy_node,用于记录被复制的文件(文件夹)。
    粘贴操作分为是文件或文件夹,首先要查看当前目录下是否存在重名的文件(文件夹)。若存在,在粘贴时将其FCB内容的文件名进行修改,为其后面添加粘贴次数。若不存在,则直接将该FCB添加到当前目录的arr(FCB临时存储器)中。
    3.6 属性查看展示FCB内容,包括文件名、文件类型、创建日期、大小以及文件位置。
    3.7 删除点击删除后,将选中的文件(文件夹)从视图中删除,并标志该FCB采取过删除操作,并且将其从FCB临时存储器arr中删除,在更换目录时将arr内容更新到树型目录结构中。
    删除操作的具体操作为函数delete,从树型目录结构中删除节点,同时判断该节点左右是否存在其他节点,若存在则将左右节点相连接,或将左节点或右节点的兄弟节点置为空。
    3.8 磁盘格式化磁盘格式化相当于第一次打开该文件管理系统的操作,将所有值重新赋值,current_node、copy_node、arr置空,parent_node为新建根节点。
    3.9 更换目录在点击文件夹进入下一级目录时,会将当前目录的FCB寄存器arr内容赋值给同级的树型目录,赋值完后清空arr,并且将父节点parent_node改为点击的文件夹,当前节点current_node置空,修改目录框内容。再进行判断,判断下一级目录中是否存在已建立的文件或文件夹,若有,则将其添加到arr中并更新视图。
    在点击返回按钮进入上一级目录时,采取同样的操作,将arr内容赋值给同级的树型目录,清空arr和更新视图等,不同之处在于将parent_node改为父节点。
    3.10 新建文件(文件夹)新建操作比较简单,每次新建时会将文件(文件夹)的属性赋值给其FCB,文件名由用户输入得到,建立日期通过获得当前系统时间得到,文件类型由用户选择得到,文件大小初始值为0B。
    3.11 读文件/写文件读文件,点击文本文件时会自动弹出对话框,对话框上方字体为文本文件内容。
    如果需要写内容到文本文件中,可以在输入框输入后,点击“保存”(将输入框内容追加到文本后方)或“重新保存”(将输入框内容覆盖文本)进行写文件操作。
    四、总结这次的项目主要是学习文件管理系统知识中的只是,其中涉及的知识点包括文件物理结构的存放方式、文件控制块FCB、树型目录结构以及通过位示图对空闲空间的管理。通过这次项目不仅是对操作系统中这一方面的知识点了解更深,对使用java建立多级树、管理位图有了更多的了解。
    项目中出现了一些问题,偶尔会发生UI更新无法同步的问题,即在当前页面删去文件(文件夹)后,当第一次跳转回该界面时,有极小的概率文件(文件夹)还存在当前目录下,但第二次跳转回该界面时,被删的文件(文件夹)已经消失。通过调试,文件(文件夹)的确已被删除,发生的错误可能是由于UI无法及时同步更新。项目中面临最大的问题就是多级目录树的构造,由于java没有指针,构造多级树比较麻烦,于是我在父节点和子节点、兄弟节点之间建立双向连接,这样更便于查找。
    1 评论 28 下载 2018-10-31 16:47:45 下载需要8点积分
  • 基于C语言的Linux环境下虚拟文件系统模拟

    一 需求分析了解EXT2文件系统,设计一个类EXT2型文件系统,所设计的文件系统要具备文件系统格式化、用户登录、用户注销、显示目录内容、文件创建、文件删除、目录创建和目录删除等功能,创建的文件不要求格式和内容,但要有相应的权限控制。
    可以用一个文件或在内存中开辟一个虚拟磁盘空间来模拟文件系统的磁盘空间,要注意目录结构的设计和磁盘空间的分配与回收。程序能够在Linux环境运行并验证结果。
    二 程序设计2.1 系统流程如下图所示:

    2.2 功能设计
    判断用户命令,按照固定的格式(仿照Linux系统中的命令输入格式)输入,通过对字符串的分割,获取相应的命令,每个命令对应着一个函数,执行命令函数,从而达到用户目的。
    每个文件都对应着一个inode和一个block,并且inode指向block,如果是目录文件,那么inode指向的block中存放的是一个info链表,info链表存放的是该目录下的文件名和对应的inode号,如果是文件,那么inode指向的block中就是虚拟的文件的内容,默认创建文件是2个block。删除、创建、初始化都是对结构体进行操作。

    三 程序实现3.1 实现原则根据对EXT2文件系统的原理,再结合Linux操作系统的命令格式的模拟,实现了对EXT2文件系统的虚拟实现。
    3.2 关键函数与方法创建普通文件:
    void createCatalog(char myName[]){ int emptyInode,emptyBlock; struct info *n=(struct info *)malloc(sizeof(struct info)); struct info *m; emptyInode=findEmptyInode(); system("cls"); emptyBlock=findEmptyBlock(); //printf("\n\n%d\n\n\n%d",emptyInode,nowBlock); m_inode[emptyInode].model=1; m_inode[emptyInode].nb=1; m_inode[emptyInode].block[0]=emptyBlock; m=m_block[nowBlock].p; if(m==NULL) { m_block[nowBlock].p=(struct info *)malloc(sizeof(struct info)); m_block[nowBlock].p->next=NULL; m=m_block[nowBlock].p; } else { while(m->next) m=m->next; } strcpy(n->name,myName); n->toInode=emptyInode; n->next=NULL; m->next=n;}
    创建目录文件:
    voidcreateFile(char myName[]){ int size,emptyInode,i; struct info n=(struct info)malloc(sizeof(struct info)); struct info *m; size=2;//默认文件大小为2个block emptyInode=findEmptyInode(m_inode); //printf("\n\n%d\n\n\n%d",emptyInode,nowBlock); m_inode[emptyInode].model=0; m_inode[emptyInode].size=size; m_inode[emptyInode].nb=2; for(i=0;i<m_inode[emptyInode].nb;i++) { m_inode[emptyInode].block[i]=findEmptyBlock(m_block); } m=m_block[nowBlock].p; if(m==NULL) { m_block[nowBlock].p=(struct info*)malloc(sizeof(struct info)); m_block[nowBlock].p->next=NULL; m=m_block[nowBlock].p; } else { while(m->next) m=m->next; } strcpy(n->name,myName); n->toInode=emptyInode; n->next=NULL; m->next=n;}
    3.3 关键方法void printCatalog(int i); // 显示目录中的内容int find(char n[],int *tempBlock,char tempAccess[]); // 查找void createOrder(char contents[],int flag); // 创建命令void rmOrder(char contents[]); // 删除命令void lsOrder(char contents[]); // 显示命令
    四 运行测试测试截图如下所示:


    五 参考文献[1] 林慧琛《Red hat Linux服务器配置与应用》人民邮电出版社 2006.1
    [2] 岳 浩《Linux操作系统教程》机械工业出版社 2005.4
    [3] 刘志国《练就Linux系统高手教程》延边出版社 2006.1
    [4] 社大鹏《Red hat Linux因特网服务器》中国水利水电出版社 2004.2
    [5] 毛德操 胡希明 《Linux内核源代码情景分析》
    [6] 《Linux 内核设计与实现(第2 版)》(Robert Love著,机械工业出版社出版译著)
    1 评论 26 下载 2018-10-31 16:43:13 下载需要6点积分
  • 基于C++的一元多项式的计算

    1 问题描述将多个多项式输入并存储在内存中,然后对多项式进行加、减运算并输出结果。
    2 数据结构描述
    一元多项式的表示方式:如 f=6x^5-7x^4+3 表示为 f=6,5 -7,4 3,0
    每个多项式用单链表来存储:
    typedef struct PolyNode { float coef; // 系数 int expn; // 指数 struct PolyNode *next; // 指向下个结点的指针 }Poly;
    图示举例


    3 主要算法描述
    主要功能:对输入的一元多项式进行加减运算并输出
    程序主要模块:如下图所示


    3.1 模块一:一元多项式的建立
    结点类型为:结构体Poly
    数据流:系数、指数。
    函数名为:
    int CreatPoly(P_Poly*, int);

    3.2 模块二:两个一元多项式的加法
    数据流:两个一元多项式相加后的结果
    函数名为:
    void AddPoly(P_Poly*, P_Poly, P_Poly);


    3.3 模块三:两个一元多项式的减法
    数据流:两个一元多项式相减后的结果;
    函数名为:
    void DecPoly(P_Poly*,P_Poly,P_Poly);


    程序中的主要函数及相应功能:
    // 创建一元多项式int CreatPoly(P_Poly*, int);// 输出一元多项式void OutP_Poly(P_Poly); // 两个多项式求和void AddPoly(P_Poly*, P_Poly, P_Poly); // 两个多项式求差void DecPoly(P_Poly*, P_Poly, P_Poly);
    4 程序的调试4.1 问题一由于程序运用了输入输出流的控制符,而没有包含<iomanip>文件,所以在连接时,出了错,后来看了下面窗口的错误提示,才知道自己忘了包含该文件进去。
    4.2 问题二因为输入多项式每一项时的格式为”系数,指数”,而用cin语句不知怎么解决,后来查找资料获悉用scanf函数可以实现输入的格式控制,因此运用了scanf这一函数。
    4.3 问题三输出多项式时,要输出正负号,这是一个比较麻烦的问题。开始想到了运用输出控制符setiosflags(ios::showpos)直接输出正号。可是却发现启用了该控制符后对后面的输出也起作用,导致x后面的指数在输出时也带上了正号。左思右想,得不到解决办法,只好另寻方法。最后多项式是可以输出来了,可是每次输出完后随即弹出出错框(如下图),这个问题本人至今还想不透。

    5 程序测试多项式名称不符合时的情况(本程序规定用单个小写字母命名多项式),如:命令输出一元多项式A

    多项式不存在时的输出情况,如:命令输出一元多项式a

    两多项式相加,如:a=6x^6-10x^5+4x^2 b=-x^6+5x^5+6x^4+2x^3

    两多项式相减,如:a=-6x^7+10x^6+4x^4 b=5x^6-9x^5+5x^4+3x^3

    6 程序特色
    本程序的力求简单明了,让使用者易于掌握。因此每一个指令都有相应的提示语句,分别按照这些提示语句进行选择,就会出现相应的菜单或实现相应的功能。
    原本想加上乘法和除法的运算,可是每项互乘除要求两个链表的节点数据也相乘除,问题太多,又想不到好的解决办法,想不出具体实现的函数,因此,没有进行功能扩展。这也是本程序最大的不足之处。
    每个函数对应解决一个问题,模块分明,系统出现错误时,易于限定哪个函数还不能完美实现某个功能,以便修改并改进。在完善程序的时候,这个特点帮了我很大的忙。例如调试减法运算功能时,系统有时会出现错误,因此便锁定在相减的函数上查找不足。又如,自己对输出这一功能不是很满意,要改进的话则只需在输出函数上做改进。

    7 课程设计总结这一次的课程设计,我再次感到了程序世界的美妙。
    记得在分析完问题的要求后,对要写的程序进行了初步的模块划分。当时觉得问题看起来很简单,但是在具体实现的函数编写上遇到了很多的细节问题。在着手解决这些问题的过程中,虽然耗费了不少时间,困难重重,但付出了总会有收获,即使有一些问题自己还没有十分满意的解决掉,但在无形之中自己又增加了不少课外知识和一些以前忽略的知识点,拓宽了自己的视野,提升了自己的动手能力。
    最主要的是对单向链表的使用有了更深刻的了解和掌握,因为多项式的计算要求用单向链表来实现,所以在做课程设计之前通过网上找资料,查参考书等对单向链表的使用比以前掌握的更加到位,并且能够灵活运用,通篇几乎用的都是单向链表,这是受益的一大重点。
    参考资料[1] 数据结构教程学习指导(第3版). 李春葆. 北京: 清华大学出版社, 2009
    [2] C++程序设计. 谭浩强. 北京: 清华大学出版社, 2008
    [3] C++程序设计题解与上机指导. 谭浩强. 北京: 清华大学出版社, 2007
    [4] C++程序开发例题与习题. 张基温. 北京: 清华大学出版社, 2001
    1 评论 40 下载 2018-10-31 16:25:20 下载需要6点积分
  • 基于JAVA实现的业务员业绩管理系统

    1 需求分析1.1 问题描述为了方便用户对业务员的管理,现需开发对业务员的管理系统,系统主要解决的问题有:

    能让用户便于插入新的业务员信息
    能让用户便于删除离职的业务员信息
    能让用户便于对业务员业绩进行查看
    能让用户查看所有业务员的信息

    1.2 需求分析
    输入数据建立信息表
    查询满足要求的信息
    插入新的信息
    删除不需要的信息
    查看所有信息
    统计和排序功能
    删除后需要刷新系统
    退出系统

    2 概要设计2.1 主界面设计当点击相应的操作时(比如:0-7),通过在主程序中选择并调用对应的子方法程序以及其他方法(比如:UI类中的显示方法)中的辅助调用,实现并完成各自的功能操作(比如:添加、查找、删除、显示、、刷新、退出等)。
    系统主界面如下:

    2.2 存储结构设计依据给定的数据格式,个人信息由六个字段来组成,即编号、姓名、性别、部门、职务、工资。
    例如:



    编号
    姓名
    性别
    部门
    工资




    3
    张三

    开发部
    12000



    通过Java语言把学生的信息用集合形式连接,源程序要有适当的注释,使程序易于阅读,用文件进行数据储存。同时进行各种修改,完成信息管理等功能。
    2.3 系统功能设计依据程序的数据结构和功能,遵照“面向对象”原则,描述该程序的层次结构,在总体上包括数据的插入、添加、删除、查找、更改和数据的排序以及数据的显示等功能模块。

    输入类功能:通过输入各项数据给数据元素,来建立一个数据表
    显示类功能:输出表中所有节点的信息
    查找类功能:按照指定关键字,对相应学生信息进行查找
    删除类功能:查找到要删除学生的相应信息,并将其从表中永久的删除
    主类功能:调用以上功能类,并用监听机制选择性的调用

    3 模块设计3.1 系统子程序及功能设计new Insert();//建立信息表调用插入类new Insert();//插入新业务员信息调用插入类new Query();//查询Delete d = new Delete();//删除d.delete();QueryPay qp = new QueryPay();//按照工资排序qp.pay();new QueryAll();//按照ID排序System.exit(0);//退出ReName rn = new ReName();//改文件名字以确定删除rn.rename();
    3.2 系统功能图
    4 详细设计监听机制:监听到点击的类型执行相应的操作
    public void actionPerformed(ActionEvent e) { //监听到事件 if(e.getSource()==b1){ new Insert();//建立信息表调用插入类 } else if(e.getSource()==b2){ new Insert();//插入新业务员信息调用插入类 } else if(e.getSource()==b3){ new Query(); } else if(e.getSource()==b4){ Delete d = new Delete(); d.delete(); } else if(e.getSource()==b5){ QueryPay qp = new QueryPay(); qp.pay(); } else if(e.getSource()==b6){ new QueryAll(); } else if(e.getSource()==b){ System.exit(0);//退出 } else{ ReName rn = new ReName(); rn.rename(); } }
    主界面构造方法;
    UI(){ f = new JFrame("业务员业绩管理系统"); f.setSize(360,455);//设置大小 cp = f.getContentPane();//加载面板 cp.setLayout(new FlowLayout(1));//改成流式布局 setLayout(new FlowLayout()); label = new JLabel("欢迎使用业务员业绩管理系统"); cp.add(label); b1 = new JButton("1、 建立业务员信息表");//创建按钮 b1.setPreferredSize(new Dimension(175,25)); b1.setBounds(100,150,175,25); cp.add(b1);//添加按钮 b1.addActionListener(this);//添加监听机制 b2 = new JButton("2、 插入新业务员信息");//创建按钮 b2.setPreferredSize(new Dimension(175,25)); cp.add(b2);//添加按钮 b2.addActionListener(this);//添加监听机制 b3 = new JButton("3、查询业务员信息记录");//创建按钮 b3.setPreferredSize(new Dimension(175,25)); cp.add(b3);//添加按钮 b3.addActionListener(this);//添加监听机制 b4 = new JButton("4、 删除业务员信息");//创建按钮 b4.setPreferredSize(new Dimension(175,25)); cp.add(b4);//添加按钮 b4.addActionListener(this);//添加监听机制 b5 = new JButton("5、 业务员业绩排序");//创建按钮 b5.setPreferredSize(new Dimension(175,25)); cp.add(b5);//添加按钮 b5.addActionListener(this);//添加监听机制 b6 = new JButton("6、显示所有业务员信息");//创建按钮 b6.setPreferredSize(new Dimension(175,25)); cp.add(b6);//添加按钮 b6.addActionListener(this);//添加监听机制 b7 = new JButton("7、 刷新删除");//创建按钮 b7.setPreferredSize(new Dimension(175,25)); cp.add(b7);//添加按钮 b7.addActionListener(this);//添加监听机制 b = new JButton("0、 退出管理系统");//创建按钮 b.setPreferredSize(new Dimension(175,25)); cp.add(b);//添加按钮 b.addActionListener(this);//添加监听机制 f.setVisible(true);//显示窗体 f.setLocationRelativeTo(null);//窗体居中 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭}
    5 测试分析各功能的运行结果:
    5.1 建立信息表
    5.2 插入信息
    5.3 查询信息
    5.4 删除信息
    5.5 业绩信息
    6 工作总结只有动手了才知道自己原来这么菜,用java实现了本次的课设,但是很艰辛啊,好多东西边学边用,知识到用时方恨少。
    以后在其他课程的学习当中会记住这次的教训,也会记住学计算机的是动手学会的光看不练永远都是菜鸟一枚。
    参考文献[1] 史济民,顾春华. 软件工程——原理、方法与应用[M]. 北京:高等教育出版社,2004.
    [2] 张海藩. 软件工程导论[M]. 北京:清华大学出版社,2005.
    1 评论 34 下载 2018-10-31 16:09:15 下载需要8点积分
  • 基于C语言的模拟猜单词游戏

    一、课题内容和要求“模拟猜单词游戏”系统要求用C或C++模拟猜单词游戏。游戏包括:单词管理、玩家纪录、猜词过程、系统设置等必须完成的基本功能以及成绩计算、猜词时间限制、词库管理等选做的扩展功能。
    二、基本要求
    单词管理:程序中用来做谜题的单词必须存放在磁盘文件中
    猜词过程:

    先请用户输入猜的单词数量,可以有一个默认值随机抽取单词,对每个单词,系统根据谜底单词长度在屏幕上显示相应个数’-‘,假设谜底单词为”hello”,则在屏幕上输出”——-“玩家输入一个字母进行猜测,如果这个字母不在单词中,系统提示玩家不对;如果猜对字母,比如玩家输入了一个’l’,则在屏幕上输出”—ll-“重复3,直到玩家在规定的次数内猜出了单词或者超过次数游戏失败显示玩家每个单词猜对与猜错次数等统计信息。如果玩家猜出单词,计算成绩,如进入前五名提示玩家并记录存储到记录文件中询问玩家是否开始新一轮猜词,如果玩家选“否”,则系统退到外面的菜单
    系统设置:猜词次数可以为默认值。玩的时候,可以对其进行修改

    二、需求分析模拟猜单词游戏系统的功能框架图如下图所示。


    进入主菜单:输出菜单,用于显示若干个可选的功能选项。根据客户输入的选项来运行不同的功能,运行不同的函数
    进入游戏功能:用户进行游戏。系统随机提取单词,并提示玩家输入字母进行猜测,并匹配单词是否正确,若正确,输出正确对应的单词,否则提示错误,并提示还有几次出错机会。若游戏结束,显示游戏统计信息,然后询问是否再一次游戏
    设置功能:进入设置选项,可更改系统默认的玩家名字和默认的每一次游戏所要猜的单词数
    查看功能:进入查看选项,可查看历史玩家记录排名以及游戏版权信息
    退出功能:退出游戏

    三、概要设计3.1 主要结构体及全局变量struct player //玩家信息结构{ char name[10]; //玩家名字 double time; //玩家所用时间 double score; //玩家成绩 };typedef struct player player;char name[]="Player"; //全局变量,储存玩家姓名char word[10]; //全局变量,储存随机提取的单词int NUMBER=2; //全局变量,储存一次游戏猜单词的个数 player allPlayer[100]; //全局结构体数组,储存从文件中提取的所有玩家信息player playerTemp; //全局结构体变量,用于临时储存操作玩家的信息char tempWord[100][20]; //全局字符二维数组,用于储存玩家所猜的单词
    3.2 主要函数流程图随机提取单词函数:用于从文本中读取单词到内存中,并随机从内存中抽取单词。随机提取单词函数流程图如下图所示。

    游戏过程中单词判断函数:用于对玩家输入的字母进行判断,玩家先对一个单词进行猜测,如果玩家在规定次数内输出单词,则进行下一个单词的判断,直到所有单词都判断过为止,如果玩家把所有单词都输入正确,则转到游戏成功界面,显现玩家的成绩,并显现正确单词,否则转到失败界面,告知玩家GAME OVER,并显现正确单词。

    四、测试数据及其结果分析运行后,程序的主菜单界面如下。
    4.1 欢迎界面
    4.2 菜单界面
    4.3 游戏开始界面

    4.4 设置界面
    4.5 查看界面
    4.6 退出界面
    4.7 测试数据及其分析先进入游戏开始界面,开始第一回合,第一回合游戏的最终过程如下:

    开始第二回合时,游戏过程如下:

    最后显现成绩为:

    下面分别有由玩家姓名为Jack,Tom,Mike,Jhon,Ken的五名玩家进行游戏体验,且他们都通过了猜词测试,他们的最终成绩通过“查看”中的“排名”选项显示如下:

    如果已经完成猜单词游戏,不想继续进行,可以将选择查看直接查看排名,然后再退出。如果不想查看其他的信息的话,可以直接选择退出。
    4.8 结果分析如下
    在输入主菜单选项时如果输入的内容不是1-4之间的数字,而是其他数字或字母,系统将进行报错,提醒用户输入正确的操作内容
    如果用户在进行游戏时只猜出一个单词,则系统不进行提示用户输入成功,必须全部输入正确才进行显现成功提示
    在进行游戏玩家的成绩排名时,只有有成绩的玩家才可以进行排名,并且只有前五名的玩家的成绩才可以输出至屏幕上显现给玩家
    在玩猜单词游戏时会有三个闪屏信息提醒玩家做好游戏准备,并告知玩家一些游戏必知信息,让玩家有心理准备

    五、调试过程中的问题
    随机提取单词时,随机读取单词出现问题。因为文件指针使用很容易造成指针指向不明的情况,为避免此类问题的出现,通过放弃随机使用指针指向文件字母来读取完整的单词的随机抽取单词方法,改为先读取完所有字母到内存数组中,然后产生随机数来随机提取内存数组中的完整单词,最后成功随机提取单词。
    读入玩家信息到已建立的玩家信息记录本时,由于结构体变量定义错误导致不能读入,然后我们尝试定体结构体全局变量,这样就方变了程序中的多个函数都能够调用,并且每个函数进行调用时将改过的信息都能够输入到玩家信息记录本中,方便了用户在游戏主界面进行信息的查询。
    进入游戏界面进行游戏,最开始设置时程序逻辑上出现了问题:如果玩家第一个单词输入正确,在猜第二个单词时,有可能造成第二个单词输入正确时没有显示成功界面,直到错误次数到了规定次数才退出游戏界面,为解决这个问题,程序中定义了一个临时记录正确次数的变量tenpCorrectTimes,每猜一个单词时,就初始化为0,每猜对一个字母,就自增一,游戏中判断是否等于正在猜单词的长度,然后判断玩家是否成功猜对单词。
    玩家进入菜单界面,如果不小心敲了键盘上某个按键,这时可能出现无数次循环显示“输入错误”提示信息,为解决这类问题,程序从新设定输入类型,由最初的整形改为字符型,这样就能避免由于整形输入而输入字母时无法判断所造成的无限次输出“错误输入”提示信息,改为字符型输入就能判断所有的字符是否输入错误,从而解决了问题。
    在将玩家信息记录本中的玩家信息读取出来进行冒泡法排序时,由于一开始调用fread函数进行玩家信息的读取时,容易出现一系列错误,都是由于fread就函数的要求较为严格,一般读取二进制文件,后来老师叫我们用fscanf函数进行格式化读写,但是由于一点小细节没有注意,第文件内容只有一个结构变量内容的话,用fscanf函数进行读取,读取完之后,fp文件指针指向末尾,!feof(fp)函数判断为0,就不能将结构体变量的内容赋给结构体数组,这样就不能进行冒泡法排序,不能判断玩家的名次。后来再第一个fscanf后直接赋值,就解决只有一个玩家信息时读取失败的问题。

    六、课程设计总结做一个完整的游戏系统非常不容易,不仅要考虑游戏本身的游戏性问题,还要考虑跟这个游戏有关的一些问题,比如主菜单界面,设置问题,提示信息等等。开始做这个系统是并没有考虑这些,只考虑了游戏本身几个函数的实现,如猜词游戏中随机提取文件中的单词函数以及进入游戏的游戏主体函数。但随着游戏的不断完善,在不断排除几个主要函数在逻辑上的错误的过程中,以及在投入力量做界面优化方面时,发现做一个完整游戏所需要满足玩家对游戏体验的附带功能必不可少。通过这次游戏系统的开发,在和同学的合作中让我们受益很多。
    所谓学以致用,这次的系统开发让我知道C语言不仅仅是书上那几个示例那么简单,C语言所能做的事远远超出了我们这些初学者的想象。这次这个简单游戏,几乎用到了书上所学的知识,如一维数组、二维字符数组、各种循环、指针、文件的写入及读出等等。让我们对课本的理解更深刻。
    在具体到函数书写的时候,会碰到一些问题。除了一些语法错误,最令人头疼的应该是程序逻辑上的问题。如果逻辑上除了一丁点小错误,将导致整个函数无法正常运行,常常导致一些意外的结果。但这些逻辑上的小错误隐藏得非常深,如果不仔细耐心调试,是很难发现问题所在。这些问题常常导致我们感到不知所措,甚至导致我们产生放弃的念头,但经过我们的细心调试,终于把那些逻辑上的小错误都一一解决了。当程序运行正确时,我们在欣喜若狂的同时,也感触良多。
    这次的系统设计让我们学到了很多,除了对C语言的更深入理解之外,最大的收获是渐渐学会如何和他人合作。如今社会工作中不会别人合作是不可能的,一个人单打独斗是很难成功。唯有合作,才能双赢。
    这就是我们做系统的总结,虽不多,但很实在。
    1 评论 54 下载 2018-10-31 16:03:36 下载需要6点积分
  • 摩根项目-股票交易模拟

    注:该项目使用的 IDE 是 Visual Studio 2010,采用通讯库为 WinSock2.h,如果使用 Linux 系统进行检测则会编译失败,使用其他 IDE 有可能发生未知异常,所以我将自己电脑上运行的一部分运行状况截图。
    1 服务器端与客户端的关系架构1.1 服务端程序的主要部分,即为项目“服务器”,采用 Windows Socket 借口,使用虚拟地址“127.0.0.1”,利用一个 while 循环来实现与多个客户端连接,每次循环连接成功后都会对当前客户端开启一个新的线程,所有客户端连接成功的 socket 都储存在全局变量 m_Server 数组里。
    1.2 普通客户端用户部分,即为项目“普通客户端”,普通客户端开启两个线程,一个用来发送订单,一个用来接受订单。用户开启客户端会有指令来操作一系列交易。客户端与服务器通过 recv 函数与 send 函数来互相发送 FIX 协议信息。
    1.3 Monitor 客户端MonitorClient 用来监测每个连接的用户进行的一系列操作。
    1.4 随机客户端RandomClient 用来模拟实际的交易所,该客户端会随机发送买卖订单给服务器。
    2 主要功能类2.1 Stock 类(股票)股票类有以下几个属性:

    averagePrice(当前价格)
    start_price(开盘价格)
    id(股票代码)
    stock_name(股票名称)
    end_price(闭盘价格)
    max_price(最高价格)
    min_price(最低价格)

    成员函数:

    每个属性对应的获取接口
    updatePrice(更新最高价格与最低价格)

    2.2 Order 类(订单)关于 Order 对象有以下几个属性:

    Order_id(每个订单独有,由系统自动生成)
    stock_name 股票名称
    amount (交易数量)
    side(买方卖方)
    avg_price(当前平均交易价格)
    give_price(订单产生时出价)
    execute_amount(已经交易的数量)
    infomation(具体的交易情况)

    成员函数:

    各个属性的获取接口
    writeResult(string opposite_name, int ex_amount, double ex_price) 该函数作用是将交易双方的一系列交易信息(交易数量、价格)写入对应的 股票 record.txt 中

    2.3 FixMessage 类(消息类)关于 FixMessage 类有以下属性:

    side(买方卖方,tag=“54”)
    average_price(平均价格,tag=“6”)
    price(价格,tag=“44”)
    filled_amount(已经交易数量,tag=“14”)
    order_id(订单号,tag=“11”)
    user_name(用户名,tag=“49”)
    open_amount(剩余未交易数量,tag=“151”)
    amount(总数,tag=“38”)
    stock_name(股票名称,tag=“1”)
    order_type(订单消息种类(新订单、取消、拒绝),tag=“35”)
    execution type(执行种类,tag=“150”)
    order_status(订单状态(新订单,部分交易,全部交易,取消), tag=“39”)

    成员函数:

    各个属性的获取接口
    在构造函数中对获取的字符串进行解析,用“;”分割出各个 tag

    3 关于匹配机制在服务器端程序中构造一个子线程共享的 Order 队列,对于每一个线程提出的要求,都要去 Order 队列里进行匹配,所以 Order 队列应对子线程保持互斥。这里使用 queue_section 全局关键段来达到互斥,给 orderList“上锁”。
    下列是全局的订单队列:

    buyOrderList:买方订单,按照价格由高到低排序,出价高的优先进行交易
    SaleOrderList:卖方订单,按照价格由低到高排序,要价低的优先进行交易
    endBuyOrder:已经结束或被取消的买方订单
    endSaleOrder:已经结束或被取消的卖方订单

    Order 进入后,先辨别是买方 Order 还是卖方 Order 进行分流,其次判断价格是否在市场内,不在的话插入队列结束,在的话直接进行匹配完成交易。 匹配细节:优先匹配最令客户满意的 Order,再进行数量匹配,出现下列三种情况:

    己方订单数量大于对方订单数量,则对方订单全部交易,己方继续与队列中下一个订单进行比较,循环直到不能再交易或全部交易。不能交易时如果未交易完,则放入队列 buyOrderList 或 SaleOrderList
    己方订单数量等于对方订单数量,双方均全部交易
    己方订单数量小于对方订单数量,己方全部交易,对方部分交易不出队列,直接结束

    用户发出取消操作,检查 buyOrderList、SaleOrderList,如果发现要取消的订单 , 则 将其 放 入 endBuyOrder 或 endSaleOrder , 如 果 在 endBuyOrder 、endSaleOrder 中找到该订单,则拒绝取消操作,因为该订单已被交易完毕。
    设置一个用户名密码的文件,根据是否存在来判定登陆成功、设置一个监视管 理账号用户名为“MonitorClient”,当服务器识别出这个用户时,会将生成的 Socket,储存在全局变量 monitor_client,登录后的交互界面如下图所示。

    从 share_information 中逐个读取股票信息,并储存在全局变量 share_map 中。

    每当有一个操作发生,如果上文提到的全局变量 monitor_client 存在,即已开启 Monitor Client,则会向该 Monitor 发送交易信息,Monitor 每接到一笔交易信息,就会将其解析判断转化为可读交易信息打印。

    关于交易的一系列规范限制

    交易价格不能超过该股票参考价格的 120%(max_price),不能低于参考价格的 80%(min_price)
    交易时间必须在系统时间上午九点半与十一点半之间,如果不在则不能发送信息,如果需要发送信息请将 Client line43-line47&&line71-line75 注释掉


    买卖股票

    取消订单

    查询现有订单
    1 评论 14 下载 2018-10-31 15:44:07 下载需要8点积分
显示 990 到 1005 ,共 15 条
eject