基于链表的归并
归并的思想还是很简单的,要完成一个归并,还是需要一个归并框架
重新来总结一遍归并的过程
描述为:通过递归将一长串数据二分到原子级,然后排序,合并
基于这样的原理,我们可以对链表的归并先做一个初步的归并框架
public ListNode sort(ListNode node){
//将其分成两段
ListNode mid = divideDoubleSegment(node);
//对左排序
ListNode left = sort(node);
//对右排序
ListNode right = sort(mid.next);
//归并
return rankAndMerge(left,right);
}
public ListNode divideDoubleSegment(ListNode node){
return new ListNode();
}
ListNode rankAndMerge(ListNode left,ListNode right){
return new ListNode();
}
就是这样一个简单的思想,接下来,我们分别完成它的操作:
将一个获得一个ListNode的中点:
这也是一个算法的问题,我们放在算法实验室-14-双指针法获取链表中点
1.0 当然,一个递归,除了递归体还需要终止条件,不然就StackOverflowError
public ListNode sort(ListNode node){
//递归结束条件
if (node == null || node.next == null)
return node;
//将其分成两段
ListNode mid = divideDoubleSegment(node);
//对左排序
ListNode left = sort(node);
//对右排序
ListNode right = sort(mid);
//归并
return rankAndMerge(left,right);
}
public ListNode divideDoubleSegment(ListNode node){
return new ListNode();
}
ListNode rankAndMerge(ListNode left,ListNode right){
return new ListNode();
}
1.1 获取链表的中间节点用于截断链表
现在直接给出答案:
public ListNode divideDoubleSegment(ListNode head){
ListNode preEnd = head;
ListNode slow = head;
ListNode fast = head;
ListNode nextSegmentBegin = head;
while (fast != null && fast.next != null) {
preEnd = slow;
slow = slow.next;
fast = fast.next.next;
}
//截断
preEnd.next = null;
return slow;
}
1.2 对一段链表进行排序
ListNode rankAndMerge(ListNode left,ListNode right){
//return the new LikedList
ListNode tempHead = new ListNode();
//use for iteration
ListNode cur = tempHead;
//merge it by iteration
while (left!= null&&right != null){
if(left.val<=right.val){
cur.next = left;
left = left.next;
cur = cur.next;
}else {
cur.next = right;
right = right.next;
cur = cur.next;
}
}
return tempHead;
}
1.3 归并剩余问题
因为left和right两个segment很可能他们的length不相等
这就会导致leftSegement 或者 rightSegment会剩下一个(直觉告诉我rightSegment不会剩下来)
这个时候,要将它们给添加上
ListNode rankAndMerge(ListNode left,ListNode right){
//return the new LikedList
ListNode tempHead = new ListNode();
//use for iteration
ListNode cur = tempHead;
//merge it by iteration
while (left!= null&&right != null){
if(left.val<=right.val){
cur.next = left;
left = left.next;
cur = cur.next;
}else {
cur.next = right;
right = right.next;
cur = cur.next;
}
}
if (left!= null){
cur.next = left;
}
if(right!= null){
cur.next = right;
}
//注意tempHead本身是空的
//它的下个节点才是合并节点的开始
return tempHead.next;
}
这样子就可以进行排序啦~:
完整代码:
import jdk.nashorn.internal.runtime.Debug;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class LinkedListMerger {
public ListNode sort(ListNode node){
//递归结束条件
if (node == null || node.next == null)
return node;
//将其分成两段
ListNode mid = divideDoubleSegment(node);
//对左排序
ListNode left = sort(node);
//对右排序
ListNode right = sort(mid);
//归并
return rankAndMerge(left,right);
}
public ListNode divideDoubleSegment(ListNode head){
ListNode preEnd = head;
ListNode slow = head;
ListNode fast = head;
ListNode nextSegmentBegin = head;
while (fast != null && fast.next != null) {
preEnd = slow;
slow = slow.next;
fast = fast.next.next;
}
preEnd.next = null;
return slow;
}
ListNode rankAndMerge(ListNode left,ListNode right){
//return the new LikedList
ListNode tempHead = new ListNode();
//use for iteration
ListNode cur = tempHead;
//merge it by iteration
while (left!= null&&right != null){
if(left.val<=right.val){
cur.next = left;
left = left.next;
cur = cur.next;
}else {
cur.next = right;
right = right.next;
cur = cur.next;
}
}
if (left!= null){
cur.next = left;
}
if(right!= null){
cur.next = right;
}
//注意tempHead本身是空的
//它的下个节点才是合并节点的开始
return tempHead.next;
}
}
节点:
public class ListNode {
public int val;
public ListNode next;
}
原题: