暴力法的时间复杂度为O(n²)
不要忽略有序性
思路:因为是有序的顺序表,所以重复的元素一定是连在一起的。那我们就使用两个指针,一个指针指向当前不重复有序表的最后一个元素,另一个会从头到尾遍历整个有序表,称为工作指针。
我们让工作指针往后移,如果与当前有序表最后一个元素相同,则工作指针需要继续后移,直到出现一个不重复的元素。然后我们将该元素放在当前有序表的后一个位置即可。代码如下:
重点在于使用双指针
经典归并
基础知识
前驱英文:prior
静态链表:
这题很难,为什么不会断链呢?
事实上是因假如当前节点无需删除,那就将L的下一个结点传进去,并且传的是引用!!!因为我传的是引用,所以当我在随后调用的递归子函数中,如果该节点是x我们就要删除,怎么删除呢?我们只需要直接将L往后移一个位置!!
因为此时是引用,在子函数中我看似是只把自己往后移动了一位,但是这个子链表也相当于缩短了一截。而另一方面,对于父函数来说,父函数传给子函数的是引用:
子函数将自己后移,做的事情是把父亲的L->next也往后移动了一个位置!!!
删除结点时不要忘记要使用free将其free掉哦
顺带补充一下递归函数通过递归的方式实现正向输出的方法
反向输出的代码如下:
注意不要忘记,调用下一个结点时要考虑其是否为空才行
反转链表:
反转链表,比如需要将第一个结点指向第二个节点的方向逆转,让当前即cur结点指向前一个结点。
但是如果直接逆转了,就少了往后面结点走的路,需要一个next结点保留后续的结点。
所以需要多一个结点存储后续的next结点。
当
所以初始时:
让cur指向第一个结点,让next指向第二个节点,然后让pre指向空处
首先将当前结点反转,让其指向pre。
做完上述操作后,然后此时我们不要着急让next结点往回指,如果往回指了则next结点往后的路又断掉了。而且我们要保持一轮循环只做一次事。
当结点修改完毕后,我们让所有的三个结点往后移动一个位置。
最终代码如下:
有两个细节点需要注意!一个是要对初始结点进行判空!
还有就是最后一步,循环完毕时,最后一个结点是没有指向前一个结点的,因此不能忘记这一步操作!!
(暂时不会,先跳)
链表很多操作都不方便,但是插入操作比较方便,于是可以考虑用插入排序实现。
链表有一个头结点,我们初始化时也为其保留一个结点,也就是图上的a1,然后我们依次遍历a2及其后面的结点,将其在合适的位置插入
初始化工作:Listnode* p=head->next->next; 为a2赋值p
Listnode *r=p->next; 为a3赋值r
head->next->next=nullptr;即让a1指向nullptr
随后我们在已有的链表L往后遍历,找到第一个比a2大的数,然后在其前一个结点插入即可
找第一个比a2大的数通过while循环实现,while(结点的数都比a2小)则继续往后,
由于插入要在前一个结点插入,因此比较数据时是用当前结点的后面一个结点比较
这样就会在比a2大的结点的前一个地方停下来。
所以循环条件如下:
当这个循环完毕时
接下来进行插入操作即可
插入操作即:
插入操作完毕后继续遍历未找完的结点,即让p和r都往后走:
p=r
r=r->next
当找完了所有未排序的结点,即p为空时结束,故完整代码如下:
注意一点:创建链表插入结点使用尾插法时,不要忘记在结尾插入节点后,要将结尾重新调整为尾部!
并且还要注意一点,虽然链表B是新建了一个结点没错,但是对于链表A我们不是新建,而是在原来的链表基础上直接进行修改!
对于这种题我们需要使用三个指针,一个是ra、rb指针,分别代表A链表和B链表的尾部,每次在尾部插入结点,插入后再将ra、rb往后移动。
还有一个指针是工作指针,负责每次往后移动一位代表当前指针。
最后不要忘记要把a和b的指针置空哦
采用尾插法
本题所需注意细节点较多!是个重要的题!
头插法与尾插法不同在于,尾插法很简单,只需要让尾结点指向该节点即可
但是头插法较为麻烦,需要让该当前工作结点指向B表中已有的结点
普通尾插法直接后移即p=p->next可,但使用头插法需要会改变当前结点的后继结点,因此此时需要提前将p->next用q储存起来,然后工作节点p后移的操作改为p=q
其实就是设定两个指针,分别指向两个链表,然后每次将两个结点中较小的值选出来,以递增的顺序找出节点即可。
然后使用头插法就可以使其变为逆序,即降序排列了。
由于我们没有新建一个链表,而是在原来的l1的基础上去改箭头,所以我们需要一个多的指针去存储l1当前工作指针的下一个指针。
即每次循环前可以设定代码:
r =p->next
(首先需要让l1头置空,然后把工作指针p1放在l1头节点的后面那个有用的结点即值为的结点。
如图所示:
接下来我们比较两个工作指针p1和p2的值,假如p1的值小,那么我们就要把1插入到l1的头部的第一个位置。
所以:我们将p1的next指向l1的后续结点,再让l1的next指向p1:如图所示
P1->next=l1->next
L1->next=p1
然后这样p1就结束了他的工作,此时p1结点已经和上述链表断链,所以使用p=r赋值来获取新的工作结点。
并让r也后移一位
代码:p1=r ,r=r->next
(如果是用l2的数据怎么办?其实此时r既可以暂存第一个工作指针的后续指针,也可以暂存第二个工作指针的后续指针,或者可以各有一个指针来缓存)
然后由于链表不等长,所以当某个链表为空后,继续将该链表的剩余结点依次插入即可。
通过这一行if(pa)pb=pa
的代码可以将pa设定为剩下的那一条链表
然后接下来依次插入即可
由于需要循环完一遍才知道哪个数据最小
而查找也需要从前往后查找一次,如果按照我原本的思想先找最小的,然后再从头遍历去查找该节点所在位置就很麻烦。
所以可以中途把最小值所在的结点也记录下来,这样就无需再查找一次。
此外为了删除该节点,需要我们不止要记录该最小值结点,还要记录最小值结点的前置结点,即minPre。
而为了记录最小值结点的前置结点,我们还需要一个结点,专门作为当前工作结点的前一个结点,工作结点后移一步的过程中,要保持该前置结点是工作结点的前一个结点。