合并两个有序单链表
思想:循环遍历两个链表,将小的值依次插入(此处用尾插哦)新的链表中。
为了防止思想短路,贴个图便于分析:
1. 普通循环实现
思路:对比数组来看,如果此题要求是将两个有序数组合并,那你第一步肯定是新建一个大小为两个数组大小之和的空数组,然后循环往新数组中添加数据。
添加的过程就是插入的过程,所以我们需要对链表定义一个尾插法的函数。
private static class Node {
String data;
Node next;
public Node(String data) {
this.data = data;
}
//尾插
void addLast(Node node) {
Node old = this;
while (old.next != null) {
old = old.next;
}
old.next = node;
}
}
接下来的事情就简单了
- 定义新的链表
- 循环比较两个列表,小的值用尾插法插入到新定义的链表中
- 然后就是一些善后工作
public static Node mergeSortedNode(Node node1, Node node2) {
Node renode = new Node("");//定义新的链表
while (node1 != null) {
Node old = node2;//此处需要赋值给新的链表来循环
while (old != null) {
if (Integer.parseInt(node1.data) >= Integer.parseInt(old.data)) {
Node node = new Node(old.data);
renode.addLast(node);
node2 = node2.next;//node2后移一位
}
old = old.next;
}
Node node = new Node(node1.data);
renode.addLast(node);
node1 = node1.next;
}
if (node2 != null) {
renode.addLast(node2);
}
return renode.next;//注意这里,由于新定义的链表第一个节点没有用(并非传参进来的链表内容,二十自己凭空创造的),故而最终将这个节点排除!
}
以上是以新增方法addLast()的思想来实现。
如果不新增方法直接该如果操作呢?
public static Node mergeSortedNode1(Node node1, Node node2) {
Node result = null;
Node k = null;
while (node1 != null) {
Node item = node2;
while (item != null) {
if (Integer.parseInt(item.data) <= Integer.parseInt(node1.data)) {
if (result == null) {
result = item;
k = result;
} else {
result.next = item;
result = result.next;
}
node2 = node2.next;
}
item = item.next;
}
if (result == null) {
result = node1;
k = result;
} else {
result.next = node1;
result = result.next;
}
node1 = node1.next;
}
if (node2 != null) {
result.next = node2;
}
return k;
}
本来打算定义result直接返回,最后发现每次都得移动result;即result=result.next
最终结果肯定是最后一个节点,所以定义一个节点k来保存新的结构。
以上实现均是以其中一个节点为依据,将此节点循环至尾节点,循环结束后如果另一个链表没有移动至尾节点,将剩余内容直接追加至后面。接下来将两个链表同时遍历:
public static Node mergeSortedNode2(Node node1, Node node2) {
Node head = null;
Node last = null;
while (node1 != null && node2 != null) {
if (Integer.parseInt(node1.data) <= Integer.parseInt(node2.data)) {
if (head == null) {
head = node1;
} else {
last.next = node1;
}
last = node1;
node1 = node1.next;
} else {
if (head == null) {
head = node2;
} else {
last.next = node2;
}
last = node2;
node2 = node2.next;
}
}
if (node1 != null) {
last.next = node1;
} else {
last.next = node2;
}
return head;
}
此种方法就需要判断到底哪个链表没有移动至尾节点
if (node1 != null) {
last.next = node1;
} else {
last.next = node2;
}
2.迭代实现
最后再来看最后一种简洁实现,迭代实现:
public static Node mergeSortedNode3(Node node1, Node node2) {
if (node1 == null) {
return node2;
}
if (node2 == null) {
return node1;
}
Node head = null;
if (Integer.parseInt(node1.data) <= Integer.parseInt(node2.data)) {
head = node1;
head.next = mergeSortedNode3(head.next, node2);
} else {
head = node2;
head.next = mergeSortedNode3(node1, head.next);
}
return head;
}
迭代的思想在于
假设 分步 细化
- 假设mergeSortedNode3的作用就是将给定的两个链表合并你想要的样子,然后你需要就是给方法传参。
- 首次进来后根据大小判断好之后,将head赋予初值:
head = node1
- 然后下一个值就是通过假设的已经成立的方法将下一个值填充好:
head.next = mergeSortedNode3(head.next, node2)
- 最后添加终止条件!
没看错,结束了,然后再带个值验证一下!
其实迭代的思想就是分步,写出细分后的具体一步的实现内容,然后迭代。最后添加终止条件。
本例中的迭代终止条件就是链表为空,正如开头判断那样。