1.本周学习总结

1.1思维导图

1.2.对线性表的认识及学习体会

   可能上学期末没有把链表的基础打好吧,这学期学习链表的进一步操作有些吃力,特别是单链表逆转这一类的题目,如果没有看网上的代码,即使知道解题的思路,也不一定能打出来,不过庆幸的时,通过敲pta也对链表的结构有了一点的熟悉,也学到了一些时间复杂度低的一些算法,比如关于一些排序的问题,在上学期,我们学了冒泡排序和选择排序等几种简单的排序方法,但时间复杂度为O(n2),运行起来效率较低,但这学期学的二路归并算法,一边排序一边重构,比起以前学的效率高了不少。
     虽然链表有点难,但是顺序表还是比较容易理解的,可能归功于上学期学的数组和结构体比较简单,操作起来比较顺手,而且有些方法是老师在上学期讲过,比如pta中的顺序表删除重复元素这道题,就可以用哈希算法来写,时间复杂度低,效率高。所有以前学的都可以运用到顺序表中,打好基础是关键啊。

2.PTA实验作业

2.1.题目1:6.3 顺序表删除重复元素

2.1.1设计思路(伪代码)

void CreateSqList(List &L,int a[],int n)
{
         动态申请内存;
         将数组a[n]赋入线性表中;
}
void DelSameNode(List &L)
{
         动态申请一个静态数组flag用来记录数据是否重复;
         将顺序表中的数据赋入data数组;
         //找出数组中相同的两个数数,并把后一个 数所对应的flag标记改为1;
         for  i=0 to L->length
               for  j=i+1 to L->length
                     if  data[i]=data[j] then
                         flag[j]=1;
                end for
		 end for         
          //重构数组
         for i=0 to L->length
                if flag[i]==0 then
                L->data[k++]=data[i];
         end for 
         L->length=k;
}
void DispSqList(List L)
{
        输出链表;
}


2.1.2代码截图

2.1.3本题PTA提交列表说明。

  • 在第一次时没有注意到数据长度,两个循环条件都是i小于length,导致顺序表发生越界;
  • 修改了循环条件之后,我没有考虑到全部都是重复的数据该怎么删,我只在循环里面记录改减去的数组长度,却没想到如果都是一样的数据,会把顺序表删没掉,后来用了一个k,既能用于重构,也能记录重构完的长度。
  • 后来老师又讲了一种做法,哈希算法,时间复杂度只为O(n),比我这种方法好太多了。

2.2.题目2:6.9有序链表合并

2.2.1设计思路(伪代码)

void MergeList(LinkList &L1,LinkList L2)
{
        如果L1和L2两条链为空,跳出函数;
        定义 节点p1=L1->next,节点p2=L2->next;
        定义 节点r=L1;
        while p1!=NULL&&p2!=NULL do
         //如果p1节点里的数据大于p2节点的数据,同尾插法将p1插入r链中
               if p1->data<p2->data then
                       s->data=p1->data;
                       r->next=s;
                        r=s;
                        p1=p1->next;//指针后移
           //如果p2节点里的数据大于p1节点的数据,同尾插法将p2插入r链中
               if p1->data>p2->data then
                       s->data=p2->data;
                        r->next=s;
                        r=s;
                        p2=p2->next;//指针后移
           //如果p2节点里的数据等于p1节点的数据,将非空链指针后移
                 if p1->data=p2->data then
                         if p1!==NULL then p1=p1->next;
                         else                        p2=p2->next;
           end while   
           //如果p1链长于p2链,将p1链多于插入r链中
           while  p1!=NULL then   
                        s->data=p1->data;
                        r->next=s;
                        r=s;
                        p1=p1->next;//指针后移 
           end while
           //如果p2链长于p1链,将p2链多于插入r链中
           while  p2!=NULL then   
                        s->data=p2->data;
                        r->next=s;
                        r=s;
                        p2=p2->next;//指针后移 
             end while
}


2.2.2代码截图

2.2.3本题PTA提交列表说明。

  • 前几次都是运行超时,没有考虑到如果两个链表内有相同数据该怎么办,后来使用了很多方法,都没有完全删干净,最后将数据相同的两个节点之一后移就行了;
  • 还有一些段错误之类的小错误,都是由于自己的粗心犯下的,后面慢慢调试都出来了。

2.3.题目3:6.7单链表逆置

2.3.1设计思路(伪代码)

void ReverseList(LinkList &L)
{
        定义两个节点p和q;
        p指向L链的首节点;
        把L链的首节点置为空;//在进行下面的循环后,这个节点就变成了尾节点
        while p!=NULL then
                   q=p;          //将p节点赋给q节点
                   p=p->next;//p节点后移
                   q->next=L->next;
                   L->next=q;               //用头插法将L链转置
         end while;
        
}

2.3.2代码截图

2.3.3本题PTA提交列表说明。

  • 没有将L链后的一个节点置为空,导致会无限循环下去;
  • 没有将p节点指向L的后继节点,导致答案会发生错误;

3、阅读代码

3.1 题目

单链表实现约瑟夫环(JosephCircle)
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。

3.2 解题思路

我们在环中定义指针cur,每次指针走k次后删除当前指针所指位置的结点,然后继续向后走k次,接着删除当前所指结点,执行循环,直到环中只剩下一个结点(即cur->next == cur),那么最后的这个结点就是我们要找的结点,返回它的地址

3.3 代码截图

3.4 学习体会

  • 通过这道单链表的题,我又学习到单链表的一种新的结构--环,环跟循环链表有点类型,可以说环包括了循环链表,题目要求在循环链表内隔几个节点删一个节点,且求出删除后的链表所剩的最后一个节点,如果我来写,我肯定写不出来,给出的解法有点微妙,只向计算机申请了两个的内存空间,空间复杂度较低,且只用了两个循环,时间复杂度也较低。代码也只有寥寥几行,可读性较高,也许是敲了pta吧,感觉自己的代码写得过于冗长,没有网上代码来的简练。