一. 链表
大学本科阶段就对链表比较头疼,没有理解透彻,做题目的时候就比较吃力,链表有很多类型,单链表、双链表、循环链表和双向链表等,操作也有很多,插入、删除和排序等,其实只要理解了节点的数据结构,问题就迎刃而解了。节点由数据和指针(next)构成,在对节点操作的过程中,会有一个虚拟的指针(并不是节点中的next)指向节点。
二. 题目
分析:
- 两个有序链表,结点都是由一个数据和一个next指针构成。可以先创建一个空结点 pre,因为当完成两个链表后,preHead的指针next指向null,所以需要在最开始预设头结点preHead,单纯的对象赋值,指向pre空结点。
- 设定循环条件:两个列表指针next指向都不为null。分别比较L1和L2结点中的数据,pre指针next指针指向较小的结点,L1虚拟指针前移,pre虚拟指针前移,直至循环跳出
- 最后某个列表已经循环结束,另一个列表未循环完,但是有序的。所以直接将未循环的列表接到pre列表末尾
代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//因为 pre 在算法结束时不再指向链表的头部,所以一开始需要有个虚拟头结点 preHead 保留对链表头部的引用
// preHead 指向 pre (不是next指针,单纯的对象赋值)
ListNode preHead = new ListNode();
ListNode pre = preHead;
//只要链表指针为null,就退出循环
while(l1 != null && l2 != null)
{
if(l1.val < l2.val)
{
pre.next = l1; //pre指向l1
l1 = l1.next; //l1指针后移
pre = pre.next; //pre指针后移
}
else
{
pre.next = l2; //pre指向l2
l2 = l2.next; //l2指针后移
pre = pre.next; //pre指针后移
}
}
// 任一为空,直接连接另一条链表
if(l1 == null)
{
pre.next = l2;
}
else
{
pre.next = l1;
}
// pre此时的指针指向末尾null,预设的头指针preHead 指向pre
return preHead.next;
}
}