归并排序实现链表排序
归并排序:
递归版(自上而下)
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var sortList = (head) => {
//如果链表为空或者链表只有一个结点,直接返回头结点
if(head === null || head.next === null){
return head
}
//对链表进行分组
//为了方便分组,我们用快慢指针找到链表的中点,得到第二组的头结点
let fast = head.next
let slow = head
while(fast !== null && fast.next !== null){
fast = fast.next.next
slow = slow.next
}
let head2 = slow.next
slow.next = null
//将链表分为两组
let head1 = sortList(head)
head2 = sortList(head2)
//合并有序链表
let cur = new ListNode()
cur.next = head
let res = cur
while(head1 !== null && head2 !== null){
if(head1.val < head2.val){
cur.next = head1
head1 = head1.next
}else{
cur.next = head2
head2 = head2.next
}
cur = cur.next
}
cur.next = head1 !== null ? head1 : head2
return res.next
}
非递归版(自底向上)
所谓自底向上分组,即将一个链表划分为长度为一个结点的序列,这些序列两个一组比较结点值并按结点值大小排序。排序之后合并起来得到一个新的链表,然后我们再将新链表划分为长度为两个结点的序列,这些序列仍然按两个一组进行比较并排序,合并得到一个新的链表。以此类推,直到新链表无法继续划分,此时我们得到的新链表就是一个有序的链表。
if(head === null || head.next === null)
return head
let node = new ListNode()
node.next = head
//获取链表长度
let n = 0
let cur = head
while(cur){
cur = cur.next
n++
}
//自底向上分组
let len = 1
while(len < n){
//设置指针,beforeHead指向两个序列中第一个序列的哨兵结点
let beforeHead = node
while(beforeHead !== null){
let mid = beforeHead.next
for(let i = 0 ; i < len ; i++){
if(mid !== null)
mid = mid.next
else break
}
//mid指向的是两序列中第二个序列的头结点
let afterTail = mid
for(let i = 0 ; i < len ; i++){
if(afterTail !== null)
afterTail = afterTail.next
else break
}
//afterTail指向的是下一组的第一个序列的头结点,或者为空
merge(beforeHead,mid,afterTail)
for(let i = 0 ; i < len*2 ; i++){
if(beforeHead !== null)
beforeHead = beforeHead.next
else break
}
//将beforeHead指向下一组的第一个序列的头结点,若beforeHead为null,本轮合并完成
}
//改变序列的长度大小,继续下一轮分组
len*=2
}
return node.next
}
//合并排序链表
let merge = (beforeHead,mid,afterTail) => {
let cur = beforeHead
//设置第一个序列的头结点指针
let head1 = beforeHead.next
//设置第二个序列的头结点指针
let head2 = mid
while(head1 !== mid && head2 !== afterTail){
if(head1.val < head2.val){
cur.next = head1
head1 = head1.next
}else{
cur.next = head2
head2 = head2.next
}
cur = cur.next
}
while(head1 !== mid){
cur.next = head1
head1 = head1.next
cur = cur.next
}
while(head2 !== afterTail){
cur.next = head2
head2 = head2.next
cur = cur.next
}
cur.next = afterTail
}