目录
编辑
题目:
图例:
分析:
解法:
解法1:
解法2:
解法的对比:
解法2:
注意事项:
图例:
代码演示:
代码分析:
代码缺点:
重复代码带来的问题比较多的:
缺点分析:
优化:
注意事项:
题目:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有
节点组成的。
图例:
分析:
如上图所示,本质其实就是比较节点和节点直接的大小,然后进行排序,小的在前,大的在后,需要使用插入节点的方法。
解法:
解法1:
- 在原链表基础上进行修改,会使用到在指定位置之前插入数据。
解法2:
- 创建一个新的空链表,遍历两个链表,进行新链表的尾插。
链表——单链表的简单介绍-CSDN博客https://blog.csdn.net/2301_76445610/article/details/133811446?spm=1001.2014.3001.5501
解法的对比:
- 无论是解法1和解法2都离不开本质,但不同的是解法1需要的插入方式有些麻烦,因为需要用到指定位置插入节点。
- 而解法2则是在比较完后,小的节点直接修改方向,指向新的链表中,用到的是尾插,相比指定位置插入数据少了一步。
- 对此我们使用解法2。
解法2:
- 分别定义两个指针指向两个链表的头节点,然后开始进行遍历比较,比较结果小的放到新链表中。
- 然后在使用两个指针当作新链表的头指针和尾指针,一开始两个指针是相同的,但伴随着比较后第一个节点的到来,尾指针开始进行挪动,头指针不变动。
注意事项:
- 注意,要先判断两个需要比较合并的链表是否为空,当某一方链表遍历结束,则停止比较,然后把没停的那一个全部按顺序尾插到新链表中。
图例:
- 谁指向的数值小,谁的指针移动 。
代码演示:
代码分析:
- 如果cur1指向的数值小于cur2指向的数值,则cur1指向的数值所存在的节点进行尾插,尾插到新链表中 ,且cur1这个指针挪到下一个节点位置。
- 反之也是如此。
- 且因为是有序的链表,当某一个链表走完后,另一个链表还剩着,那么直接将新链表最后一个节点的指向改成剩下的旧链表中的最前面一个节点
- 基于链表的特征,一个节点内存储着下一个节点的地址,所以只要把剩下的旧链表中的最前面节点交给新链表最后一个节点内部的指针(newTail->next)
- 因此还需要判断cur1和cur2是否为空。
代码缺点:
需要考虑信链表的头结点为空或者非空,所以导致这里的重复代码比较多
重复代码带来的问题比较多的:
- 降低程序员的开发效率
- 代码的可读性非常差
- 代码的维护性非常差
缺点分析:
- 解决当前代码问题的关键是消除判断链表的第一个节点是否存在。
- 也就是第一个节点必须要确保存在且无需判断,所以这里使用带头的单链表。
- 而带头的单链表自带一个节点。
- 但这个节点中的数据是不可使用不可更改的。
- 所以我们直接创建一个带头的单链表作为接收比较之后内部数据较小的节点。
优化:
使用开辟空间将代码变成带头的单链表
- 判断第一个节点是否存在的原因是为了定位链表,而定位链表就是从第一个节点开始的,而带头链表自带第一个节点。
注意事项:
- 注意这里可以不判断malloc是否开辟成功。
- 原先判断新链表是否是空和非空状态消失了。
- 因为一开始就是非空的存在,所以不需要使用newHead = newTail = cur2;和newHead = newTail = cur1;进行定位,直接一开始两个指针就指向新链表第二个节点的位置。(带头的第一个节点是不能存储数据的)
- 同时,我们也要注意,最后返回的时候,需要从链表的第二个位置开始返回,因为带头链表的第一个节点是没有数据存在的。
- 但是我们怕释放后找不到第二个节点,于是我们先用临时遍历来存储第二个节点的地址,在把头节点进行释放。