如图
黑色的线为合并前的链表,蓝色的为合并后。
分析这个问题,可以发现此问题符合递归的四条基本法则。
1.基准情形。必须总要有某些基准情形,他无需递归就能解出。
2.不断推进。对于那些需要递归求解的情形,每一次递归调用都必须要使状况朝向一种基准情形推进。
3.设计法则。假设所有的递归调用都能运行。
4.合成效益法则。在求解一个问题的同一实例时,切勿在不同递归调用中做重复性的工作。
1.在最后一个节点的时候,只需要将最后一个节点链接到链表上即可。
2.每次递归调用只需要链接一个节点,在某一个链表为空的时候,链接另一个链表其余的节点。
3.此处需要进行三次四次判断,如果h1为空,则需要返回h2,如果h2为空则需返回h1,如果h1的data小于h2的data则需要把h1链接上,如果h1的data大于h2的data则链接h2。
4.每一次运行都会链接一部分节点,没有重复性工作。
代码
/**
* 合并两个有序链表
* @param h1
* @param h2
* @return 合成后的链表
*/
public static Link2 RecursiveMergeLink(Link2 h1,Link2 h2)
{
Link2 h3 = new Link2();
Entry h11 = h1.head.next;
Entry h22 = h2.head.next;
h3.head.next = RecursiveMergeEntry(h11, h22);
return h3;
}
/**
* 连接节点
* @param h1
* @param h2
* @return 连接好后的第一个节点
*/
public static Entry RecursiveMergeEntry(Entry h1,Entry h2)
{
Entry h3= null; //临时变量保存当前需要被插入的节点
if(h1 == null) //如果h1等于null了则h1已经被连接完成,此处只需要链接剩下的h2即可
return h2;
else if(h2 == null) //如果h2等于null了则h2已经被连接完成,此处只需要链接剩下的h1即可
return h1;
else
{
if(h1.data < h2.data) //如果h1比h2小
{
h3 = h1; //则当前节点为h1
h3.next = RecursiveMergeEntry(h1.next,h2); //进行后续节点的连接
}
else if(h1.data > h2.data)//同上
{
h3 = h2;
h3.next = RecursiveMergeEntry(h1,h2.next);
}
else //当两个相等的时候,同时往后移位
{
h3 = h1; //则当前节点为h1
h3.next = RecursiveMergeEntry(h1.next,h2.next); //进行后续节点的连接
}
return h3; //返回当前节点给上一层递归 当返回的时候 当前节点之后的节点都已经连接完成
}
}
测试结果
public static void main(String[] args) {
Link2 i = new Link2();
Link2 j = new Link2();
i.insertHead(9);
i.insertHead(7);
i.insertHead(5);
i.insertHead(3);
i.insertHead(1);
j.insertHead(10);
j.insertHead(8);
j.insertHead(6);
j.insertHead(4);
j.insertHead(2);
i.show();
j.show();
Link2 k = RecursiveMergeLink(i, j);
k.show();
}
结果
[1 3 5 7 9 ]
[2 4 6 8 10 ]
[1 2 3 4 5 6 7 8 9 10 ]
非递归实现
递归可以完成的事情,非递归肯定也可以完成。
/**
* 合并两个有序链表非递归
* @param h1
* @param h2
* @return
*/
public static Link2 MergeLink(Link2 h1,Link2 h2)
{
Link2 h3 = new Link2();
if(h1 == null||h1.head.next==null) //若某一个链表为空 直接返回另一个链表
return h2;
if(h2 == null||h2.head.next==null)
return h1;
Entry e1 = h1.head.next; //获得两个链表的第一个数据域
Entry e2 = h2.head.next;
Entry e3 = h3.head; //获取临时链表的头结点
while(e1!=null&&e2!=null) //循环直到某一个链表为空
{
if(e1.data>e2.data) //进行判断
{
e3.next = e2; //连接
e2 = e2.next; //移位
}else if(e1.data<e2.data) //同上
{
e3.next = e1;
e1 = e1.next;
}
else //防止存在两个相等的元素,去除掉一个
{
e3.next = e2;
e2 = e2.next;
continue;
}
e3 = e3.next; //连接后将e3向后移动
}
// if(e1 == null) //当e1为空时,剩下的为h2 需要将h2剩余的节点e2连上
// {
// e3.next = e2;
// }
// else if(e2 == null) //同上
// {
// e3.next = e1;
// }
e3.next = e1==null?e2:e1; //和上面if相同
return h3; //返回临时链表h3
}
测试结果
public static void main(String[] args) {
Link2 i = new Link2();
Link2 j = new Link2();
i.insertHead(9);
i.insertHead(7);
i.insertHead(5);
i.insertHead(3);
i.insertHead(1);
j.insertHead(10);
j.insertHead(8);
j.insertHead(6);
j.insertHead(4);
j.insertHead(2);
i.show();
j.show();
Link2 k = MergeLink(i, j);
k.show();
}
结果
[1 3 5 7 9 ]
[2 4 6 8 10 ]
[1 2 3 4 5 6 7 8 9 10 ]