视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JavaScript趣题:链表的归并排序
2020-11-27 20:26:04 责编:小采
文档


归并排序想必大家都知道,它的基本思想,是一个先分割,再合并的过程。

那么,如何对一条单链表进行归并排序呢?

首先,我们需要一个分割链表的方法,如下面的伪代码所展示的那样:

var source = 1 -> 3 -> 7 -> 8 -> 11 -> 12 -> 14 -> null 
var front = new Node() 
var back = new Node() 
frontBackSplit(source, front, back) 
front === 1 -> 3 -> 7 -> 8 -> null 
back === 11 -> 12 -> 14 -> null

它接收一个链表的尾指针作为参数,将该链表一分为二,也就是前半部分和后半部分。

那么,这个中间的分界值该如何确定下来?

可以使用快慢指针,快指针和慢指针同时从尾部出发,遍历单链表,快指针每次都走2步,慢指针每次走1步,那么快指针肯定会先达到终点,而慢指针此时只走了一半的路程,也就是说,慢指针正好处于这个分界的位置。

那剩下的就好办了,在分界处截断,该设置为null的设置好,第一阶段我们就完成了。

function Node(data) { 
 this.data = data === undefined ? null : data; 
 this.next = null; 
} 
 
function frontBackSplit(source, front, back) { 
 var total = 0; 
 var fast = source; 
 var slow = source; 
 var partial = null; 
 while(fast && fast.next){ 
 fast = fast.next.next; 
 slow = slow.next; 
 total++; 
 } 
 partial = slow; 
 while(slow){ 
 slow = slow.next; 
 total++; 
 } 
 if(total % 2 === 1){ 
 back.data = partial.next.data; 
 back.next = partial.next.next; 
 partial.next = null; 
 } 
 else{ 
 back.data = partial.data; 
 back.next = partial.next; 
 for(var e=source;e.next!=partial;e=e.next); 
 e.next = null; 
 } 
 front.data = source.data; 
 front.next = source.next; 
}

然后,链表打散了,甚至成了一个个不可分割的单元节点,我们就要想办法将它们合并,组装成新的有序的链表,于是,就需要下面的merge方法:

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

要写好一个这样的方法,考虑的case其实是有蛮多的,这在俺的代码里就有所体现了:

function sortedMerge(l1, l2) { 
 var newList = null; 
 var temp = null; 
 while(l1 && l2){ 
 if(l1.data > l2.data){ 
 if(!newList){ 
 newList = l2; 
 temp = l2; 
 } 
 else{ 
 temp.next = l2; 
 temp = l2; 
 } 
 l2 = l2.next; 
 } 
 else{ 
 if(!newList){ 
 newList = l1; 
 temp = l1; 
 } 
 else{ 
 temp.next = l1; 
 temp = l1; 
 } 
 l1 = l1.next; 
 } 
 } 
 if(l1){ 
 if(!newList){ 
 newList = l1; 
 } 
 else{ 
 temp.next = l1; 
 } 
 } 
 if(l2){ 
 if(!newList){ 
 newList = l2; 
 } 
 else{ 
 temp.next = l2; 
 } 
 } 
 return newList; 
}

好了,分割方法和合并方法都写好了,就好比案板和菜刀都准备好,只需要切肉了。主方法这是一个递归的过程。

function mergeSort(list) { 
 if(list && list.next){ 
 var front = new Node(); 
 var back = new Node(); 
 frontBackSplit(list, front, back); 
 return sortedMerge(mergeSort(front),mergeSort(back)); 
 } 
 return list; 
}

下载本文
显示全文
专题