一、PTA实验作业
1.题目1:7-1 最长连续递增子序列
2. 设计思路
MaxriseSqList(L); //寻找最长连续递增子序列并输出
定义变量maxbegin,max分别表示最长连续递增子序列的起始位置和长度
定义变量i和count分别表示序列中的位置和在遍历过程中某次连续递增子序列的长度
将以上变量全部初始化为0
for i=0 to L->length-2
if(后一个数大于前一个数)
count++
else {
if(count<max)count清空为0
else(count>max){ 更改max和maxbegin;count清空为0 }
}
end for
if(cout>max){ 更改max和maxbegin;}
for i=maxbegin+1 to maxbegin+max
输出L->data[i]
end for
3.代码截图
4.PTA提交列表及说明。
- Q1:一开始在devc的运行结果就不对
- A1:(1)maxbegin一开始没有赋初值(2)输出的循环条件粗心地写成了maxbegin+count,而正确的写法应该是maxbegin+max,要知道count大部分情况下是不等于max
- Q2:n取上限的时候段错误
- A2:没有认真审题导致data数组下标maxsize设得太小了
- Q3:随机数n取最大值的时候错误
- A3:这个错误还是花了比较长时间去找的,当时第一反应是maxsize还是太小了的问题。但是其实是错在解题过程中逻辑不够严谨的问题,忘记考虑如果这个序列从中间某个数开始一直到最后一个都是上升的话,那么就不会进入这个循环的else分支,
那就没法处理max和maxbegin的值,也就是说max和maxbegin还是保持原来的值等于0,那就不成立那个输出循环条件就没法输出正确内容了,所以针对这种情况就在遍历完以后进行count和max的判断,如果count大于max的话就改变max和maxbegin。By the way. PTA的提示真的太清晰了(逃..)
1.题目2:7-2 一元多项式的乘法与加法运算
2. 设计思路
void add(LinkList ha,LinkList hb,LinkList &hc) //求两个多项式相加
定义pa,pb分别指向链表ha,hb的首结点,定义r指向hc,定义s指向新结点
while(pa!=NULL&&pb!=NULL){
动态申请s结点空间
if(pa的指数等于pb的指数){ s的系数等于pa和pb系数之和,if(s的系数不为0){s的指数等于pa的指数,尾插法把结点s插入hc中} if(s的系数为0){ 释放结点s } pa,pb都后移 }
if(pa的指数大于pb的指数){ s的系数指数分别等于pa的系数指数,利用尾插法把结点s插入hc中,pa后移 }
if(pb的指数大于pa的指数){ s的系数指数分别等于pb的系数指数,利用尾插法把结点s插入hc中,pb后移 }
}
while(pa!=NULL){ 动态申请s结点空间,s的系数指数分别等于pa的系数指数,利用尾插法把结点s插入hc中,pa后移}
while(pb!=NULL){ 动态申请s结点空间,s的系数指数分别等于pb的系数指数,利用尾插法把结点s插入hc中,pb后移 }
}
void mulply(LinkList ha,LinkList hb,LinkList &hc) //求两个多项式的乘积 ,且结果单链表元素递减排序,且合并同类项
定义pa,pb分别指向链表ha,hb的首结点,定义r指向hc,定义s指向新结点,定义pre指向要hc中要插入位置的前驱
for(pa=ha->next;pa!=NULL;pa=pa->next)
for(pb=hb->next;pb!=NULL;pb=pb->next){
动态申请s结点空间,s的系数为papb系数乘积,s的指数为papb指数相加,
if(pa为ha的首结点){利用尾插法把s插入hc中}
else{
pre为hc的首结点,利用while(pre->next!=NULL&&pre->next->expn>=s->expn)找到s要插入的位置的前驱结点pre,
if(pre为hc的尾指针){如果pre的指数等于s的指数,直接把pre的系数改成两者系数相加,如果不等于的话,利用尾插法把s插入hc的末尾 }
if(pre不是hc的尾指针){如果pre的指数等于s的指数,直接把pre的系数改成两者系数相加,如果不等于的话,利用中间插入方式把s插到pre后面 }
}
3.代码截图
4.PTA提交列表及说明。
- Q1:
乘积结果出现错误,可以发现插入是正确的,但是乘积结果指数比较小的话尾插没成功....也就是没有进入如图所示的那题的if分支中然后我用printf来验证发现它真的没有进入那个分支中... - A1:这个错误真的找得非常久也非常让人绝望,而且在大佬的vs中竟然会爆段错误,后来分析得知第一个ha节点乘以hb后,最后个节点没指向NULL,而我的DevC没有错是因为恰好最后节点的next值为0(NULL其实就是0). vs会报错是因为next是0xCDCDCDCD. 本质还是有问题的。具体看细节才发现r->next = NULL放错地方了,应该是和前面那个}换一下,也就是内循环末尾放r->next = NULL;,不是全部结束后放,也正是这个原因导致vs段错误。一直记得在最最后要加上r->next = NULL,但是忘记分析具体的最后应该在哪里。
- Q2:pre = hc->next应该改成pre = hc
- A2:这个是自己抖机灵的错,因为我一开始觉得那个两个序列都是递减排序,所以a序列中的第一项和b序列的第一项乘积一定是最大值,所以我就想说从第二项开始找更节省时间,然而忘记要考虑异常情况,比如合并同类项的时候,如果系数为0,那么这节点就不要了。如果ha是0 6 5 3,第一节点乘hb后,这些节点全作废,那hc就直接指向NULL了。此时pre=hc->next,后面是无法判断pre->next的,因为无法NULL->next,会报段错误的。这时空头节点的好处就来了,因为可以pre=hc
- Q3:忘记考虑相加后系数为0的情况
- A3:在相加后添加if语句去判断s的系数是否为0,为0的话直接释放结点s,无需进行插入等操作
1.题目3:7-4(选做) 一元多项式求导
2. 设计思路
void Derivation(LinkList ha,LinkList &L) //对ha里的多项式求导并存放在L
动态申请头结点L空间
定义指针pa=ha->next,s,r指向头结点L
while(pa!=NULL){
动态申请结点s空间
if(pa指向的结点的指数为0){ s的系数和指数为0 }
else { s的系数等于pa所指的结点的系数与指数相乘,指数等于pa所指的结点的指数减1 }
利用尾插法把s加入到链表L中
pa=pa->next
}
3.代码截图
4.PTA提交列表及说明。
-
Q:系数和指数取上限的测试点错误
-
A:因为ha在创建的过程中是直接边取边创建并不存在设max的问题,一开始是挺懵的,于是去devc试了取上限的情况输出
觉得可奇怪了怎么就自己变成这种形式输出。然后以为是float的大小范围不够(但是印象里记得是够的)还是试了一下改成范围更广的double型,发现输出了一样的结果。然后大佬请教了一下才知道要把float改成int型,这样子才能输出正常整数形式...
二、截图本周题目集的PTA最后排名
1.顺序表PTA排名
1.顺序表PTA排名
2.链表PTA排名
3.我的总分:
270
三、本周学习总结
1.谈谈你本周数据结构学习时间是如何安排,对自己安排满意么,若不满意,打算做什么改变?
- 学习时间安排:在晚自习的时候有看数据结构的书,主要是看课本中链表的一些常用的函数是怎么写的
- 编程时间安排:主要是没有晚自习的时候在寝室或者图书馆有打代码
- 交流方式:因为跟上学期时间间隔有点远寒假又浪了一个寒假,所以对链表变得可陌生了,而且看懂和自己敲出来还是有很大的距离,所以在刚刚开始打链表的时候总是出现很多问题,有在QQ上问自己班的同学也有问别班的同学或者是问特别厉害的一个大神,总之几乎都是以线上的方式问问题。
2.谈谈你对线性表的认识?
- 线性表的定义:由零个或多个数据元素组成的有限序列。
- 线性表的类型:1.线性表的顺序表示–顺序表 2.线性表的链式表示–链表
- 线性表的特点:
1.元素之间都是有个先来后到的关系,对顺序表来说是通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,对链表来说是通过每个结点的指针域将线性表的n个结点按其逻辑顺序链接在一起
2.若元素存在多个,则第一个元素无前驱,而最后一个元素无后继,其他元素都有且只有一个前驱和后继。(前驱:排在当前位置之前的元素;后继:排在当前位置之后的元素。)
3.顺序表中元素的个数n(n>=0)定义为线性表的长度,当n=0时,称为空表。而对于链表来说,若头结点指向NULL说明该线性表为空。
3.阅读代码
/*
求一亿个数里面最小的10个数
首先建立节点个数为10的最小堆,然后考虑每一个新的值,让他和堆顶比较,比堆顶大的元素直接抛弃,如果比堆顶小的数字,让他替换堆顶,然后调整堆。
*/
public class MaxTenNumber {
public static void main(String[] args) {
/*第一个元素0不参与,只是用于占位置,这样的话,只要array[k]>array[2k] && array[k]>array[2k+1]那就是最大堆了, 此外,这里暂时用20个数代替1亿个*/
int[] array={0,1,2,3,4,7,8,9,10,11,12,13,14,15,16,17,18,19,20,6,5};
//建立建立节点个数为10的最大堆
for(int i=10/2;i>=1;i--){
adjustHeap(array, i, 10);
}
//System.out.println(Arrays.toString(array));
for(int i=11;i<array.length;i++){
//如果这个元素小于堆顶,和堆顶交换,然后重新调整堆
if(array[i]<array[1]){
swap(array, i, 1);
adjustHeap(array, 1, 10);
}
}
System.out.println(Arrays.toString(array));
System.out.println("最小的10个数字为:");
for(int i=1;i<=10;i++){
System.out.print(array[i]+" ");
}
}
/*交换*/
private static void swap(int[] array, int i, int j) {
int tem=array[i];
array[i]=array[j];
array[j]=tem;
}
/*调整这堆数据变成最小的数据堆*/
static void adjustHeap(int[] array,int head,int tail){
int root=array[head];
int i=2*head;
while(i<=tail){
int max=array[i];
if(i+1<=tail)
if(array[i+1]>array[i]){
max=array[i+1];
i++;
}
if(root>max)
//别手抖写成了return;
break;
else{
array[i/2]=array[i];
}
i*=2;
}
array[i/2]=root;
}
}
- 思考:对于这种题目,最普遍的想法是先对这一亿个数进行排序(显然当数据很大的时候这是不可行的),然后再选取序列中的前10个数,即为最后的答案,但是当数据很大的时候其时间复杂度太大了,故最好的方法是建立一个最小堆。
- 时间复杂度: 设从N个数中找M个最小数 ,每次重新恢复堆的时间复杂都为O(logM),最多一共进行了(N-M)次恢复堆操作,故时间复杂度为O(NlogM)。
4.代码Git提交记录截图
git上传代码过程中遇到的问题:
- Q1:在运行过程中遇到用户名和密码登录时用错了用户名
- A1:注意用户名不是姓名也不是你的项目名称,而是注册的时候起的昵称
- Q2:push失败
- A2:根据提示和翻译以及百度得知:本地没有update到最新版本的项目(git上有README.md文件没下载下来)本地直接push所以会出错。解决方法就是:输入命令 $ git pull --rebase origin master 然后就可以把github上最新的文件下载下来了,即README.md文件。.接着再去git push origin master 即可成功把本地的文件都上传到github上面去了。此时再去github网站上也就可以看到对应文件了
- Last but not least, 此处要手动@梦冰感谢梦冰同学的耐心教导~~