DS博客作业02--线性表

1.本周学习总结

1.1思维导图

1475011-20190331191257772-219374619.png

1.2谈谈你对线性表的认识和学习体会

学线性表这一章的时候,我感觉吧就像是在学加上了结构体可以变化长度的数组和链表 。感觉就是应该和上学期的数组和链表差不多,结果做起PTA的时候,一堆堆的错误。然后上级考的时候,一遍遍的段错误到绝望……然后就感觉自己跟上学期比起来松懈了不少,最基本的代码问题又开始

2.PTA实验作业

2.1题目1:6-3 jmu-ds- 顺序表删除重复元素

设计一个算法,从顺序表中删除重复的元素,并使剩余元素间的相对次序保存不变。
 - 输入格式: 第一行输入顺序表长度。 第二行输入顺序表数据元素。中间空格隔开。
 - 输出格式:数据之间空格隔开,最后一项尾部不带空格。
 - 输出删除重复元素后的顺序表。

2.1.1设计思路(伪代码)

因为顺序表中的数均为正数,构造一个哈希数组赋初值为0,遍历顺序表,将L->data[i]的值作为哈希数组的下标统计顺序表中各个数出现的次数,将哈希数组值为一的数存入重构顺序表中。
  • 伪代码
定义整型变量i、j=0,i为原顺序表的下标,j为重构顺序表的下标
定义整型哈希数组hash[100],并赋初值为0
遍历顺序表
    将L->data[i]作为哈希数组的下标,统计其出现的次数
    if L->data[i]出现的次数为一次 then
        将L->data[i]的值赋给L->data[j++]  //重构顺序表
将j的值作为顺序表长度赋给L->length

2.1.2代码截图

  • void CreateSqList(List &L,int a[],int n); //创建顺序表
    1475011-20190331191419016-749413759.png

  • void DispSqList(List L);//输出顺序表
    1475011-20190331191435676-728661179.png

  • void DelSameNode(List &L) ;//删除顺序表重复元素
    1475011-20190331191451321-795313736.png

2.1.3本题PTA提交列表说明

1475011-20190331194744878-683912348.png

Q1:一开始部分正确是因为忽略了空表及全部删除后的输出,然后又认真的看了一下题目,在输出的函数部分用if语句分出空顺序表的情况;
Q2:后来两个间隔长时间的答案正确的提交改进了算法,将时间复杂度为O(n3)改进成了O(n);
A2:一开始做这道题的时候用的是笨办法,用两层for循环查找重复元素,找到后再来一层循环将顺序表往前挪,虽然做法简单易懂,但是时间复杂度特别高,当时抱着做出结果就好的心态,做完就没去管它了。隔了两周多吧,老师上课提到这道题,经过这两周的学习,我又想到了只用两层循环的重构做法,然后老师说可以用哈希数组来做,只要一层循环就能搞定,当时在课上我就自己试着做了一遍。

2.2题目2:6-8 jmu-ds-链表倒数第m个数

已知一个带有表头节点的单链表,查找链表中倒数第m个位置上的节点。
 - 输入要求:先输入链表结点个数,再输入链表数据,再输入m表示倒数第m个位置。
 - 输出要求,若能找到则输出相应位置,要是输入无效位置,则输出-1。

2.2.1设计思路(伪代码)

利用两个LinkList型指针p,ptr,将p移到第m个位置,让ptr从指向头结点的位置与p同时往下指,当p指向尾结点时,ptr的位置即为倒数第m个数的位置。
  • 伪代码
定义LinkList型指针p,ptr,两个指针均指向头结点,ptr表示指向倒数第m个位置的指针
if 头结点为空 或者 m取小等于0的无效位置 then
    返回 -1
while 指针p不为空 且 m的值不为0 do
    指针p往下移
if m的值大于0 then //即L的长度小于m 
    返回 -1
else
    while 指针p不为空 do
        指针p与指针ptr同时向下移动
    返回 ptr->data的值
end if

2.2.2代码截图

1475011-20190331210232561-2140969639.png

2.2.3本题PTA提交列表说明

1475011-20190331210249136-918048715.png

Q1:当时做的时候,是在帮同学改过这题代码的情况下做的,所以无效位置条件的测试点都过了,但是我没想到的是有效位置上出了错
A1:我当时看了一遍又一遍,觉得自己的代码没什么毛病啊,(当时因为题目的各种函数细节不表,懒得自己打出来去dev调试),后面又静下心来慢慢看那,发现我else里头while语句的条件写错了,写成了p->next,这样一来ptr所指向的位置就变成了倒数第m+1个
Q2:当时做这道题的时候不仅是在帮同学改完代码的基础上,更是在老师上课讲完了相关例题之后写的,总觉得没有了自己的思考,下回PTA的作业还是不要拖着了(哭唧唧)

2.3题目3:6-10 jmu-ds-有序链表的插入删除

链表L是一个有序的带头结点链表,实现有序链表插入删除操作。

2.3.1设计思路(伪代码)

插入函数:找到比输入数据大的结点,将数据插入该结点的前面
删除函数:找到所输入的数据,并将该结点释放删除,若找不到则输出X找不到!
  • 伪代码
插入函数:
    定义LinkList型的变量p、ptr,为p申请空间,将e赋值给p->data,令ptr等于L
    while ptr->next不为空 then  //保存前驱结点,方便插入操作
        if ptr->next->data的值大于e then
            将指针p插入在ptr指针后
            返回空值
        end if
        ptr指针往后移
    end while
    将指针p插入在ptr指针后

删除函数:
    定义LinkList类型的指针 ptr、q,令ptr等于L保存前结点
    if 头结点为空 then
        return
    while ptr->next 不为空 do
        if ptr->next->data的值与e相等 then
            利用指针q删除该结点,释放q
            return
        end if
    ptr指针往后移
    end while
    输出X找不到!  //当输入数据找不到时才会执行该语句

2.3.2代码截图

  • void ListInsert(LinkList &L,ElemType e);//有序链表插入元素e
    1475011-20190331211215134-570893432.png

  • void ListDelete(LinkList &L,ElemType e);//链表删除元素e
    1475011-20190331211300940-1790431964.png

2.3.3本题PTA提交列表说明

1475011-20190331211315324-829613494.png

Q1:这题做完后再看,真的是超简单,但是吧当时不知道在想什么,信心满满的做完,结果编译错误……看了眼PTA的错误提醒,好吧,把指针跟数据进行比较,我也是没谁了
Q2:改完想着好了这题做完了,结果来了个运行超时……(吐血)
A2:检查了两遍,没毛病啊,再提交一下,运行超时……然后问了下同学,一语惊醒梦中人:你指针都没移动。好的吧我的错,继续改。
Q3:改完以后想着这回总该对了吧,结果如上图所见,答案错误
A3:如同上一题一样的原因,没用dev调试,看了n边的代码,始终找不出错误,最后认命的手动补充细节不表的函数,过程中又出现了问题,因为建链的时候忘记让尾结点等于NULL,结果输出的时候陷入了死循环。改完后,在调试过程中发现插入函数在尾部插入的情况不能实现,再瞅了眼代码,好吧,还真没考虑到在末尾插入的情况,终于,答案正确了。
 - 写这题呢不是因为难,不会做,而是发现自己又开始犯起了基本的错误,指针跟数据都能比较起来,不知道为啥做这道题的时候,逻辑思维乱乱的,各种出错。当然还有,不要因为题目给的代码细节不表懒得自己写,就不去用dev调试,你以为不表的函数你都会,但是可能也会有不懂的地方。

3.阅读代码

3.1题目:链表的中间结点

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
  • 示例1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
  • 示例2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

提示: 给定链表的结点数介于 1 和 100 之间。

3.2解题思路

解法一:输出到数组

  • 解题思路
按顺序将每个结点放入数组 A 中。然后中间结点就是 A[A.Length/2],因为我们可以通过索引检索每个结点。
时间复杂度:O(N),其中 N 是给定列表中的结点数目。
空间复杂度:O(N),A 用去的空间
  • 伪代码
1.定义一个数组A
2.利用while遍历链表并将链表赋值给数组
3.返回数组A[n/2]的值

解法二:快慢指针法

  • 解题思路
当用慢指针 slow 遍历列表时,让另一个指针 fast 的速度是它的两倍。当 fast 到达列表的末尾时,slow 必然位于中间。
时间复杂度:O(N),其中 N 是给定列表的结点数目
空间复杂度:O(1),slow 和 fast 用去的空间。
  • 伪代码
定义两个ListNode类型的指针变量slow、fast,且两个指针变量均指向head
while fast指针不为空 且 fast->next指针不为空 do
   slow指针往下移一位
   fast指针往下移两位
end while
返回slow指针的值

3.3代码截图

  • 解法一
    1475011-20190406140537676-78794546.jpg
  • 解法二
    1475011-20190406140604239-196603629.jpg

3.4学习体会

这道题其实超级简单,选择这道题的原因是这套题配的解题思路。
看到这道题的时候,我的想法就是:遍历一边链表,然后记下链表的长度,再用一个循环来使指针指向中间的位置。虽然跟上述两种做法的时间复杂度一样,都是O(n),但是,却用了两次循环,而且感觉自己的做法特别的笨。然后看到解法一的解题思路时,我在想为什么还要用数组,跟我的想法不是差不多,却还要在定义新的临时变量,结果看完代码…好吧,是我的思路不对,存进数组后直接输出就好了,根本不用再次遍历。然后看到解法二的时候,心里的想法:真的是妙啊,连新的临时变量都用不上了,然后就想到了链表倒数第k个数的那道题,有异曲同工之妙。
所以记下这道题,一是给自己一个新的逻辑思维跟解题思路,更是提醒自己举一反三,不要新的思路解法学了,却运用不到其他类似的题目上。

转载于:https://www.cnblogs.com/Lay-549/p/10629623.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值