第二次寒假作业
这个作业属于哪个课程 | <班级的链接> |
---|---|
这个作业要求在哪里 | <作业要求的链接> |
这个作业的目标 | 模拟路由数据处理 |
作业正文 | 如下 |
其他参考文献 | csdn yyds! |
写在前面
因为在学习过程中注重理解知识和改进程序,对学习过程的记录较少
自学摸索来完成作业的感觉,这么说吧!人已经快疯掉了,但是也蛮有成就感,即使我的暴力解法需要三十几秒的运行时间,我再改进改进吧。
从最开始的一脸懵,开始慢慢学着配置vscode,编译运行、debug,而且没有开汉化包,以为能提升英语能力,但似乎没有啥效果哈哈哈,然后学着操作git,学习计算机网络五元组数据的知识,要搞明白他们是啥,还得搞明白他们之间应该如何相互转换、如何匹配,还有c++的一些知识,但是感觉如果把类、对象、STL那些先弄明白,我作业可能是做不完了,所以最后只采用c++部分基础语法知识和库函数进行程序的编写。
这段时间以来,我边玩边学,不然头都要秃掉啦!庆幸的是我昨晚得出了正确的匹配结果了,超级激动,但是他的巨无霸运行时间也给我留下了艰巨的任务...
分析学习的内容
该部分移步至另一篇博文观看—>戳这里
程序设计思路
总体程序设计思路戳这(包含关键代码、伪代码和完整代码)
这里是我的GitHub仓库地址—>戳这里
测试结果
这里使用vsc自带的比较功能,附下图(两个文件若有不同的地方会以红色高亮)
out.txt是我程序运行得出的结果;ans1.txt是作业给出的标准答案
运行时间测试的话是用clock函数先算出经历的cpu时钟的单位数,再除以每秒CPU时钟周期数常量CLOCKS_PER_SEC
算出具体的秒数,如下图。
困难和学习过程
说到困难,那可太多啦!我简直天天住在csdn!
前期一些知识学习过程,请这边走!
对于后期的学习过程我将其与困难放一起写
下面是对于一些问题的描述和解决方法,希望能帮到大家,在csdn茫茫大海找解决方案实在太难受啦!
-
关于VScode的环境配置和无法debug的问题
- 环境配置只需要参考相关csdn博文即可
- 对于无法debug的断点无效问题
- csdn上很多写说要改launch.json和tasks.json的内容
- 但其实只要将你的文件路径中的中文改成英文即可
- 除此之外,很多情况下不管是code runner崩掉还是无法debug,重启VScode是一个非常方便的选择,可能是因为我找不出他崩掉的原因(死循环等等)
-
关于多次重定向文件IO流,第二次及以上的重定向无效的问题
- 查阅无数csdn博文发现:多次重定向后,cin的状态其实没有改变,需要在freopen语句前加一句
cin.clear();
,清空cin缓冲区,也会改变cin的状态,这样子多次重定向就都能用了
- 查阅无数csdn博文发现:多次重定向后,cin的状态其实没有改变,需要在freopen语句前加一句
-
关于流同步和重定向的矛盾问题
- 刚开始为了加快cin和cout的IO速度,关掉了流同步,导致重定向无法使用,这是在逐步猜想和采取提取部分代码进行单元测试后才发现的
-
还有关于
while(cin>>a>>b){...}
此类循环的结束条件的判断- 在文件IO中,例如a是int型,而文件中光标后非int,则该while语句就会直接跳过,不予执行,以及文件中的空格和制表符不会作为一个char类型读入,这两个问题导致我多次不能正常读取数据包和规则集内容
-
关于再次重定向打开数据包文件后,每次光标都会回到文件首,无法依次读取所有的数据信息的问题
- 所以采用如下方法解决:
- 定义文件类型指针指向重定向流
FILE \*p=freopen("input.txt","r",stdin);
和定义文件内部指针fpos_t fp;
- 每次读取完数据后,使用函数
fgetpos(p,&fp);
获取此时光标位置 - 每次将要读取数据时,使用函数
fsetpos(p,&fp);
来将光标恢复至上一次结束的地方,再继续读入数据
-
关于IP地址和协议的进制转换的困难
- 使用非标准函数ltoa()
- 手写一个进制转换的函数(注意:转换成二进制的时候,如果其数字太小,则其二进制位数会少于8位,所以应该手写将其补全,避免匹配出错)
-
关于使用命令行运行程序以及加载数据包、规则集文件进行文件IO
- 我写完程序才发现,我写的与作业想要的,彻彻底底是背道而驰了
- 作业要求的应该是在程序中仍然使用标准输入,对于文件IO则通过cmd的命令来操作
- 而我则是使用freopen在程序内将读写直接重定向到目标文件,然而这有个很麻烦的问题,就是如果数据包文件太多的话,我只有两种方法:
- 第一种:将代码复制n遍,对于每次复制的代码只改动freopen的文件名参数,但是这样子代码重复率非常非常高,显得很傻而且效率低下
- 第二种:将代码编译出.exe文件后改变freopen的文件名参数,然后再继续编译.exe文件,之后使用cmd依次执行所有的.exe文件,问题是这样子也非常的呆,很不方便
- 对于第二种方法,其实是可以使用Makefile的方法,将所有的cmd命令存在一个文件中,然后再利用Makefile文件对其进行解析,让它替我们去执行程序!!但是这个我没学我不会呀!!还得学Makefile的新语言,不切实际!
-
关于所有规则都不匹配输出
-1
的情况- 原本我使用的是等
while(cin>>x){...}
读入EOF来作为判断依据,结果也不知道为啥,它没办法读到EOF - 接着,我使用了feof()函数来判断,但是还是没能判断出文件末,实在也找不到原因在哪
- 最后我利用了
while(cin>>x){...}
遇到不正确类型的字符不会进入循环的特点和利用变量cnt
对已读规则进行计数,并在rule1.txt文件中发现规则数是918,就用cnt和918的大小关系来判断是否读到文件末
- 原本我使用的是等
-
对于
cin>>x>>x;
不能连续读入同一个变量的问题- 这个原因是啥我也不太清楚,但是反正
cin>>x>>x;
这样子不能根据需求读入x的值 - 需要改成
cin>>x,cin>>x;
或者是取不同变量名cin>>x>>y;
- 这个原因是啥我也不太清楚,但是反正
-
对于字符数组复制和拼接操作很麻烦的问题
- 这边建议使用C++的
string
来定义,其也可以作为数组来使用,而且其能够利用加法运算进行字符串拼接等,确实方便很多 - 但是就是有些类似ltoa的函数其传入参数必须是字符数组,可能会导致无法使用某些函数
- 这边建议使用C++的
-
对于文件头的定义的小建议
- 我是直接贴C++万能头
#include<bits/stdc++.h>
确实方便很多,不用写一整排的文件头
- 我是直接贴C++万能头
优化
目前的优化思路:
- 在IP地址的匹配过程中,我原本采取的是将数据包和规则集的IP地址块都转换成二进制数,然后对前n位的网络前缀用for循环进行逐位比较,以返回值0/1判断结果
- 改进:先得出规则集的IP地址块的最小和最大地址,将其转换成十进制数,直接判断数据包的IP地址是否处在其区间范围内,这样可以省去每一次的for循环,减小程序的时间复杂度至O(n^2),则有望将运行时间减少至1秒内(别人好像就是这样的)。
结
谢谢你看到了最后!如果以上内容对你有帮助,请自取;若有一些好的建议或者优化方法,或者发现了什么错误,请向我指正!特别谢谢啦!