1.本周学习总结
1.1思维导图
1.2.谈谈你对线性表的认识及学习体会。
对于线性表的操作过程有有多问题可以探究,在很多的题目里有的甚至会对操作的时间进行规定,这就非常考究算法的效率。根据不同的情况对排序方法或者是对链表或顺序表的选择,可以节省其运行时间。而算法又是比较有难度的一部分,对初次认识一种算法的人仍需时间去理解,可以说这就是人与计算机不可兼得的一方面。
对于链表的操作,时刻都要考虑指向非法区域的情况,这也是我经常不自觉要忽略的一点。
2.PTA实验作业
2.1题目1:
设计函数分别求两个一元多项式的乘积与和。
输入格式:
输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
输出格式:
输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。
2.1.1设计思路
对于这道题目我尝试了两种解决方法:
数组法:
这种方法对时间和空间的消耗都是魔鬼,但是对程序员却是十分友好,这也是我一开始使用这种方法的原因。
简而言之,十分暴力。
设计思想:构造一个尽量大的数据,并且使用static使得所有初值均为0,这样就能判断每一项是不是存在。然后将加法和乘法的每一项结果都存进以指数为下标的数组里。要输出的时候就遍历全部数组,非0就输出。很暴力呢
!--以下伪代码都将采用python缩进表示语句块的方法--<
定义存储多项式的数组a[MAX],b[MAX]
以及用来存储的数组plus[MAX],Mult[MAX]
//对于所有数组都用静态,这样他们就都是0了,方便判断是否为空
//还有就是数组下标就代表有几次方,其内容就是系数
//下面开始对结果计算的操作:
//乘法:
for i = 0 to MAX-1:
if a[i]:
for j = 0 to MAX-1:
if b[i]:
Mult[i + j] += a[i] * b[j] //系数相乘,指数相加
//加法
for i = 0 to MAX-1
if a[i] or b[j]:
plus[i] += (a[i] + b[i])
//如上便完成了操作过程
接下来是链表法:
//代码这东西,不是电脑难受,就是我难受(小声嘀咕)
设计思想:初始化一个新元素elem,然后同样地将每次计算加法或者乘法的结果存入elem,再利用一个Insert函数将elem插入到结果链表中。
//先丢出结构体
typedef struct LNode {
int coe;
int index;
LNode * next;
}*LinkList;
//常规的建表输出表就不贴啦
//我先设计了两个初级函数,用于计算每一项的结果,并调用Insert函数插入结果链表中:
void Multply(LinkList L1, LinkList L2, LinkList result)
LinkList p = L1, q
while p->next://遍历
初始化q为L2
while q->next://遍历
为elem分配空间,然后将p,q节点的计算结果存储到elem
if elem->coe == 0:
elem->index = 0
p = p->next
void Add(LinkList L1, LinkList L2, LinkList result)
//Add函数也比较简单,把每个链表的节点丢给Insert函数就好啦
//这两个函数的大致功能类似,只不过是一个节点中转站
//接下来是Insert函数,其大致思想就是利用输入数据的指数递减的特点,尝试查找比elem指数小的节点
void Insert(LinkList elem, LinkList &result)
while p->next:
if p->next->index == elem->index://说明找到
将elem的系数与当前p->next相加
delete elem
return; //return 很重要
else if p->next->index < elem->index://找过头了还是没有找到
将elem插入在当前p->next的前面
return;
p = p->next
//经过上述循环仍没找到说明应该插在末尾
插在末尾
2.1.2代码截图
数组实现:
链表实现:
2.1.3本题PTA提交列表说明
WA1:忘记考虑系数为0时指数不为0的情况
Solution:在Insert之前加个if语句判断就好了
WA2:我以为题目的“0 0”情况是有系数为0的就用合并输出。。
Solution:去和之前写的数组法对比了一下差别,再回过头来看看题目才发现
2.2题目2:
已知两个递增链表序列L1与L2,2个链表都是带头结点链表。设计函数实现L1,L2的合并,合并的链表仍然递增有序,头结点为L1的头结点。 合并后需要去除重复元素。
* 输入格式: 输入分两行,先输入数据项个数,再输入数据项,数字用空格间隔。
* 输出格式: 在一行中输出合并后新的递增链表,数字间用空格分开,结尾不能有多余空格;
你需要实现的函数为:
void MergeList(LinkList &L1,LinkList L2);//合并链表
2.2.1设计思路
这题不算难,但是手上有一个有趣的解法就拿出来分享一下,其大致原理如图
设计思想:比较L1和L2头元素的大小,将两者之中最小的元素拆下来使用尾插法插入结果链表,并且让拆过的链表头指向下一节点。
void MergeList(LinkList &L1, LinkList L2)
新建一个结果链表L3
head = L3
while L1 or L2:
if L1->data == head->data:
L1=L1->next
else if L2同上:
else:
使head->next指向L1, L2中的最小值节点
并使该节点指向它的下一个
head->next = NULL
L1 = L3
2.2.2代码截图
2.2.3本题PTA提交列表说明
WA1:写这题时也不知怎么了,感觉脑子突然不在线了,出现很多低级错误,比如定义了结果链表L3,但是都没用过就给人家L1=L3,太智障了我。。
Solution:让脑子冷静一下。。。
WA2:发现有的重复数据还是没有过滤掉
Solution:设置断点调试,最后发现是只考虑了L1,L2有共同元素却没有考虑单个链表中重复的情况。
2.3题目3:
本题要求实现一个函数,将给定单向链表逆置,即表头置为表尾,表尾置为表头。链表为带头结点链表。请实现逆转函数。
输入说明:
第一个数输入单链表结点个数n,后面输入n个正整数。
输出说明:
输出逆转后的单链表内容,数和数之间空格隔开,尾部不能有空格。若链表为空,输出 空链表!
2.3.1设计思路
设计思想:感觉就像桥梁施工队一样,为了防止后面的桥梁坍塌,必须把后面的吊住,这就是操作变量after的功能,利用before和p实现两个节点之间的逆转,原先是before下一个指向p,修改成p下一个指向before。
void ReverseList(LinkList &L)
p = L->next;
定义操作变量before = NULL,after
while p:
//移动after的位置
after = p->next
//先改变p的指向
p->next
移动before和p
L->next = before
这个感觉实在是太抽象了,伪代码不太好表达,所以用PPT做了个动画,应该会比较好懂
元素解释:红色代表操作变量,黄色代表链表的每一个节点,蓝色代表指针指向
2.3.2代码截图
2.3.3本题PTA提交列表说明
WA1:可能是太累了,一直没给L头节点,然后输出函数也是写的没头节点,一直在纳闷。
Solution:经历太多失败恍然大悟
3.阅读代码
3.1 题目
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
3.2 解题思路
多种思路:
1.快慢指针法
(这里就直接照搬题解了)
思路想象一下,两名运动员以不同的速度在环形赛道上跑步会发生什么?
通过使用具有 不同速度 的快、慢两个指针遍历链表,空间复杂度可以被降低至 O(1)O(1)O(1)。慢指针每次移动一步,而快指针每次移动两步。
如果列表中不存在环,最终快指针将会最先到达尾部,此时我们可以返回 false。
2.无限循环法(自命名)
这种解法会破坏链表,大致思路就是每走一步就然后让每个节点自己指自己,这样如果存在环势必会遇到一个自攻自受的节点,这就是答案了
3.3 代码截图
1.快慢指针法
2.无限循环法
3.4 学习体会
感觉经常逛一逛这些网站还是挺有意思的,能看见各种不同的奇葩思路,也非常适合用来对新学习的语言进行练手,因为它支持很多种编译器,牛逼