一、链表节点
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
}
二、循环解法
思想和归并排序有点像,注意指针操作。
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode header = null; //header作为合并后的新链表的头节点
ListNode temp = null; //temp用来做新链表的操作指针,来链接新的节点
while (list1 != null && list2 != null) {
if (list1.val < list2.val) { //比较两个链表当前节点的大小,选择更小的插入新的链表末尾
if (header == null) { // 如果新链表是空的,就作为新链表的头节点
temp = list1;
header = temp;
} else { //如果新链表不为null,就链接到新链表的末尾,末尾指针用temp来维护
temp.next = list1;
temp = temp.next;
}
list1 = list1.next; //把更小的那个节点链接到新链表上之后,需要维护一下旧链表的指针让它移动到下一个待比较的节点
//我们没有创建新的节点去构造新的链表,而是直接修改旧链表的指针,这样会不会对旧链表产生影响,比如丢失指针,指针错乱等问题?
//经过分析发现,可能造成指针错乱等问题的是 temp.next = list 这句,因为它修改了旧链表next指针,仔细思考就会发现
//它动的不是当前元素的next,而是上一个元素的next,并不会影响当前元素查找下个元素
//顺带说一下指针,比如有A和B,同时指向List1这个节点,如果仅仅改变A的指向,比如A改为指向List2,这并不会影响B和List1
//如果改变A.next那B和List1的next也会改变,总结成书面语言叫啥来着我给忘了,如果长时间不接触指针突然想到这个点还真让我别扭了一下
} else {
if (header == null) {
temp = list2;
header = temp;
} else {
temp.next = list2;
temp = temp.next;
}
list2 = list2.next;
}
}
if (list1 == null) { //如果其中一个链表遍历完了,把另一个链表剩下的节点直接放到新链表的后面,要注意开始其中一个链表为null的情况
if (header == null) {
header = list2;
} else {
temp.next = list2;
}
} else {
if (header == null) {
header = list1;
} else {
temp.next = list1;
}
}
return header;
}
三、递归解法
public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (list1 == null) return list2;
if (list2 == null) return list1;
ListNode headerAndTemp = null; //第一次调用,存储的是新链表头节点
if (list1.val < list2.val) {
headerAndTemp = list1;
headerAndTemp.next = mergeTwoLists(list1.next,list2); //每次都是返回更小的那个,然后通过headerAndTemp.next来维护新链表
}else {
headerAndTemp = list2;
headerAndTemp.next = mergeTwoLists(list1,list2.next);
}
return headerAndTemp; // 最后一次返回的是,第一次调用,即返回的是第一次存储的头节点
}