1.1 思维导图
1.2 本章学习体会及代码量学习体会
1.2.1 学习体会
1.以前我一直都只把指针当作一个固定的地址来使用,没有想过对指针进行运算,经过这周的学习使我对指针有了更深刻的认识。
2.在对指针进行初始化的时候可以同时进行赋值,如下
int a[10];
int *p=a;
3.使用指针进行大数据的传递可以明显地提高效率,因为传递指针传递的是地址,相对于大数据来说每次传递的字节更少。
4.将数组存储在局部变量里的时候,局部变量的累积大小有限,不能超过某一限制,而将数组存储在全局变量的时候,大小比在局部变量大得多,也可以使用new函数,或者malloc函数对指针进行动态内存分配,都可以获得较大的数组。
1.2.2 代码累计
2.PTA总分
2.1截图 PTA中的排名得分
2.2 我的总分:
PTA总分:125 分
3.PTA实验作业
3.1 PTA题目1
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。
输入格式:
测试输入包含一个测试用例,在一行内给出总长度不超过500 000的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用若干个空格分开。
输出格式:
每个测试用例的输出占一行,输出倒序后的句子,并且保证单词间只有1个空格。
输入样例
Hello World Here I Come
输出样例
Come I Here World Hello
3.1.1算法分析
算法一:
定义字符型数组 a[511111]
计数 count = 0
flag数组 static int flag[511111] //用来表示该位置的字母是否为单词的首字母
int startIndex = 0 //用来标记第一个单词的第一个字母的位置
int stopIndex = strlen(a) - 1 //用来标记最后一个单词的最后一个字母的位置
输入字符串 a
接下来先将头尾的空格滤去:
|while a[startIndex] == ' ' do
| startIndex++ //将前面的空格滤去
|end while
|while a[stopIndex] == ' ' do
| stopIndex-- //将后面的空格滤去
| end while
末尾补零,否则过会用地址直接输出字符串会连空格也输出
a[stopIndex + 1] = '\0' //末尾补'\0' 使他成为完整的字符串
接下来开始判断找出每个单词的首字母,判断条件为空格后面是否是字母
flag[startIndex] = 1 //第一个单词情况比较特殊,直接手动判定
| for int i = startIndex to stopIndex - 1 do
|
| |if a[i+1]是单词的第一个字母 do
| | 将 flag[i + 1] 标记赋值为 1
| | count++
| |end if
|
| |if a[i]是空格 do
| | a[i] = '\0' //后面输出时遇到'\0'就会停止
| |end if
|
|end for
最后进行输出
| for int i = stopIndex to startIndex
|
| |if flag[i] 等于 1 do
| |
| | 对该 a+i 的地址以 %s 字符串形式输出
| | count--
| | |if a+i 不是最后一个单词 do
| | |
| | | printf(" ")
| | |
| | |end if
| |
| |end if
|
|end for
算法二:
存储字符串 a[500010]
输入字符串 a
用函数记录字符串长度 len
起始地址 start = 0
对空格掐头去尾
|while a[len - 1] 是空格 do
| len--
|end while
|len--
|while a[start] 是空格 do
| start++
|end while
令 stopIndex = len
判断是否要输出的 flag = 1
for int i = len to start do
|
| if a[i] 是单词首字母 do
| |
| | 用 flag 判断法判断是否输出空格
| | for int j = i to stopIndex do putchar(a[j])//将单词字母一个个输出
| |
| if 如果a[i]是单词末尾的空格 do stopIndex = i - 1 //用stopIndex指向单词末尾
|end for
3.1.2 代码截图
3.1.3 PTA提交列表及说明
苦难是人生的老师,通过苦难,走向欢乐。 ——贝多芬
如果给我的时间趋近于无穷,我就能修复任何bug。 ——谢晓淞
Q:以是否为大写字母来判断是否为首字母,最后一个点总是过不去??
A:可能测试数据或者我的理解有问题,换用空格判断法就能过了
4.大作业
4.1 改造函数介绍
1.void ExpCreator(char exp, char gameClass)
- 算法分析
初始化exp全为'\0'
当等级为1时numAmount为2,其他全为3//记录有多少个数
int circuTimes = *gameClass - '0'//circuTimes表示循环次数,也表示数的位数
loc = 0 //数组的起始位置
for i = 0 to numAmount - 1 do
| //对exp数组的数字位进行赋值
| for j = 0 to circuTimes - 1 do
| |
| | exp[loc++] = rand() % 10 + '0';
| |
| |end for
| //表达式末尾加上等号
| if i == numAmount - 1 do
| | exp[loc++] = '='
| |//否则就是换成运算符
| else
| |
| | exp[loc] = rand() % 4;
| | if (exp[loc] == 0) exp[loc++] = '+';
| | else if (exp[loc] == 1) exp[loc++] = '-';
| | else if (exp[loc] == 2) exp[loc++] = '*';
| | else exp[loc++] = '/';
| |
| |end if
|
|end for
//补尾巴
exp[loc] = '\0';
使用IsExp判断是否合法
- 代码截图
2.int ComputeExp(char *exp)
- 算法分析
//提取数字和运算符
定义 numIndex = 0, OpeIndex = 0 来记位
初始化整型数字组 number[4]
初始化运算符组 Operator[3]
numberTemp = 0 用来暂时存储数值结果
for i = 0 to exp[i]不为空 do
|
| //遇到数字
| if exp[i]是数字 do numberTemp = numberTemp * 10 + exp[i] - '0'
| else do//遇到运算符
| |
| | number[numIndex++] = numberTemp //切换下一个数
| | Operator[OpeIndex++] = exp[i] //切换下一个运算符
| | numberTemp = 0 //初始化
| |
| |end if
|
|end for
//计算
//先判断第二个运算符优先级
if Operator[1] == '*' || Operator[1] == '/' do
|
| if Operator[1] == '*'do number[1] = number[1] * number[2]
| else do number[1] = number[1] / number[2]
| switch (Operator[0])
| |
| |case '+': number[0] = number[0] + number[1]
| |case '-': number[0] = number[0] - number[1]
| |case '*': number[0] = number[0] * number[1]
| |case '/': number[0] = number[0] / number[1]
| |
| |end switch
|
else//第二个运算符不是高级,直接顺序运算
|
| switch (Operator[0])
| |
| |case '+': number[0] = number[0] + number[1]
| |case '-': number[0] = number[0] - number[1]
| |case '*': number[0] = number[0] * number[1]
| |case '/': number[0] = number[0] / number[1]
| |
| |end switch
|
| switch (Operator[1])
| |
| |case '+': number[0] = number[0] + number[2]
| |case '-': number[0] = number[0] - number[2]
| |case '*': number[0] = number[0] * number[2]
| |case '/': number[0] = number[0] / number[2]
| |
| |end switch
|
|end for
return number[0];
- 代码截图
3.void IsExp(char exp, char gameClass)
- 算法分析
初始化int型 number[4] = { 0,0,0,0 }
初始化字符型 Operator[3] = { '\0','\0','\0' }
int m = 0, n = 0 //用于切换数与字符
int i;
//对内容提取
for i = 0 to exp[i]=='\0'
|
| if exp[i]是数字字符 do
| | number[m] = number[m] * 10 + exp[i] - '0'
| |
| else
| |{
| | Operator[n] = exp[i];
| | n++//切换下一个字符
| | m++//切换下一个数字
| |
| |end if
| |
|end for
//判断非法情况
for i = 0 to n - 1 do
|
| if Operator[i] == '/' do
| |
| | while number[i+1] 非法 do
| | |
| | | 对gameClass的不同情况重新生成number[i+1]
| | |
| | |end while
| |
| |end if
|
|end for
初始化exp数组
char temp[4] = { '\0','\0','\0','\0' }
char opeTemp[2] = { '\0','\0' }
for i = 0 to m - 1 do
|
| 将数字和字符分别存在temp和opeTemp中
| strcat(exp, temp)//接上数字
| strcat(exp, opeTemp)//接上字符
|
|end for
- 代码截图
4.3 与原有函数代码比较
关于第一个函数的改造
改造前:原本的函数是使用随机函数直接获取一个数存到数组里面,在此之前还得使用条件语句进行判断要生存的是几位数,因此令代码看起来很繁琐,很头秃。一开始也很天真,曾想过用pow函数加上循环来从高位到地位获取结果存到数组,完全不知道itoa这种函数的存在。而且生成的表达式的计算结果很不友好,用户体验太差了。
改造后:因为对表达式的存储改成了字符串,因此可以对每一位包括运算符进行处理,所以我采用了一个个输入的办法,一个是可以使用for循环加while嵌套进行处理,还有就是简化代码样式,更加简洁,看着不会那么头秃。并且在最后会使用IsExp函数判断是否非法又或者有小数结果,保护用户幼小的心灵。
关于第二个函数的改造
改造前:原来的计算函数是以全局变量传递的,可以直接对数据调用,但是不利于函数的移植,分享性不是很强,并且对于计算的结果拿出去后还得用差值的办法判断用户给的答案是否正确。
改造后:得益于矫正函数,新一代的计算函数可以直接计算整型变量,不需要用double类型的变量来传递结果,且如今的新一代计算函数采用指针传递,一方面传递的时候只需要传递一个地址,在传递效率上有有不错的改进,另一方面由于少了全局变量,使得这个函数可以移植到别的程序上使用,也使得程序容易维护。
关于第三个函数的改造
第三个函数是新增的函数,因为比较差值判断答案的方法实在不官方,且程序中存在的除数为0的bug也没有得到解决,因此独立出一个IsExp函数,对于传入的数据进行拆分分析,看的到数据是否非法,如果是的话,就对数据修正。一开始想着如果数据不合法直接打回ExpCreator重造,但经过不断实验发现,这样改造的话,得到除法算式的概率会大大降低,因此后面改为找到非法数据,只对数进行修改,运算符则保持不变,以此保证四种运算符出现的概率。
4.4 改进大作业总结
1.将所有的全局变量都改为了指针,深刻学习了指针的用法,体会到全局变量的危害,也感受到指针的灵魂之处所在。
2.深刻吸取上次大作业的教训,熟悉了fflush的用法,对函数进行了输入上的改造,借此大大增强了代码的健壮性,减少了很多输入导致的bug的产生。
3.在这次的大作业中,我还在结束时加入了排名统计系统,虽然从代码上看对文件函数应用还是过于青涩,用的方法也是有些旁门左道,但是功能还是有实现的呀,不过实现归实现,下次正式进行文件大作业时将对这一部分进行正式化修改。。