java算法系列,第十一篇:合并有序链表
现在有两个链表:
[1,3,8,9],
[2,4]
要求合并成一个新的有序列表:[1,2,3,4,8,9]
这该怎么办呢?
方法一:
- 循环比较两个链表中的值,谁小就在该次循环中取它的节点添加到一个新链表去
- 循环完了以后将剩余的节点追加到新链表
/**
* 合并两个有序列表
* @param p1 有序列表1
* @param p2 有序列表2
* @return 合并后的有序列表
*/
public ListNode mergeTwoLists(ListNode p1, ListNode p2) {
ListNode s = new ListNode(-1,null);//头哨兵
ListNode p = s;
while (p1 != null && p2 != null)
{
if(p1.getVal() < p2.getVal())
{
p.setNext(p1);
p1 = p1.getNext();
}
else
{
p.setNext(p2);
p2 = p2.getNext();
}
p = p.getNext();//更新p
}
if(p1 != null)//如果p1还不为空,就把p1剩下的追加到p后面
{
p.setNext(p1);
}
else if(p2 != null)//或者如果p2还不为空,就把p2剩下的追加到p后面
{
p.setNext(p2);
}
return s.getNext();
}
方法二:
将方法一中用循环做的事改成递归来完成:
/**
* 合并两个有序列表
* @param p1 有序列表1
* @param p2 有序列表2
* @return 合并后的有序列表
*/
public ListNode mergeTwoLists2(ListNode p1, ListNode p2) {
if(p1 == null)
{
return p2;
}
else if (p2 == null)
{
return p1;
}
if(p1.getVal() < p2.getVal())
{
p1.setNext(mergeTwoLists2(p1.getNext(),p2)); //让p1后面的节点去合并
return p1;
}
else
{
p2.setNext(mergeTwoLists2(p1,p2.getNext()));//让p2后面的节点去合并
return p2;
}
}
这种方式的话就不需要另外再新创建一个新链表,直接拿原来节点去组合。
以上两种方法都是合并两个有序链表,如果是多个呢?
这个就先用递归先合并成两个链表,然后再调用上面的合并两个链表的方法去合并就行了。
public ListNode mergeTwoLists3(ListNode[] nodes) {
if (nodes.length == 0)//如果数组为空,就返回null
{
return null;
}
else
{
return split(nodes,0,nodes.length-1);//如果数组不为空,就把数组分成两半,然后合并
}
}
/**
* 分割数组,并合并成两个链表
* @param nodes 有序列表数组
* @param start 开始位置
* @param end 结束位置
* @return 合并后的有序列表
*/
private ListNode split(ListNode[] nodes,int start,int end)
{
if (start == end)//如果数组只有一个元素,就返回这个元素
{
return nodes[start];
}
else if (start < end)//如果数组有多个元素,就把数组分成两半,然后合并
{
int mid = (start+end) >>> 1;
ListNode left = split(nodes,start,mid);
ListNode right = split(nodes,mid+1,end);
return mergeTwoLists(left,right);//合并两个有序列表
}
else
{
return null;
}
}