把两个升序排列的链表合并成一个,系列目录见 前言和目录 。node
实现函数 sortedMerge()
把两个升序排列的链表合并成一个新链表,新链表也必须是升序排列的。这个函数应该对每一个输入的链表都只遍历一次。git
var first = 2 -> 4 -> 6 -> 7 -> null var second = 1 -> 3 -> 5 -> 6 -> 8 -> null sortedMerge(first, second) === 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 6 -> 7 -> 8 -> null
有一些边界状况要考虑:first
或 second
可能为 null
,在合并过程当中 first
或 second
的数据有可能先取完。若是一个链表为空,就返回另外一个链表(即便它也为空),不须要抛出异常。github
在作这个 kata 以前,建议先完成 Shuffle Merge 。segmentfault
代码以下:app
function sortedMerge(first, second) { if (!first || !second) return first || second if (first.data <= second.data) { return new Node(first.data, sortedMerge(first.next, second)) } else { return new Node(second.data, sortedMerge(first, second.next)) } }
跟上个 kata 相似的思路。不过为了保证最后的结果是升序排列的,咱们要取两个链表中值更小的首节点,添加到结果链表的末尾。思路就不赘述了 。函数
循环是这个 kata 有意思的一点,不少边界状况的判断也发生在这里。很容易写出这样的 if/else
:测试
let [p1, p2] = [first, second] while (p1 || p2) { if (p1 && p2) { if (p1.data <= p2.data) { // append p1 data to result } else { // append p2 data to result } } else if (p1) { // append p1 to result } else { // append p2 to result } }
上面例子里 p1
和 p2
是指向两个链表节点的指针,在循环中它们随时可能变成空,所以要比较数据大小首先就要判断两个都不为空。并且注释中的 append 代码也会有必定重复。指针
为了解决这个问题,咱们能够上个 kata 里调换指针的方法。完整代码以下:code
function sortedMergeV2(first, second) { const result = new Node() let [pr, p1, p2] = [result, first, second] while (p1 || p2) { // if either list is null, append the other one to the result list if (!p1 || !p2) { pr.next = (p1 || p2) break } if (p1.data <= p2.data) { pr = pr.next = new Node(p1.data) p1 = p1.next } else { // switch 2 lists to make sure it's always p1 <= p2 [p1, p2] = [p2, p1] } } return result.next }
第 7 行判断 p1
或 p2
为空,而且把非空的链表直接添加到 result
末尾,省去了继续循环每一个节点。第 17 行的指针调换让 p1
始终小于等于 p2
,从而避免了重复的 append 代码 。其余技巧如 dummy node 在以前的 kata 都有讲,就很少说了。递归