题目
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
链表的插入排序法
//插入排序法,非进阶
public ListNode sortList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode cur = head;
ListNode nextNode = head.next;
ListNode aux = new ListNode(-1);
aux.next = head;
while(nextNode != null){
//只要下一个节点大于当前的就讲当前节点和下一个节点的指针向后移动
if(nextNode.val > cur.val){
cur = cur.next;
nextNode = cur.next;
}else{
//将下一个节点从链表中“摘取”下来,因为下一个节点小于当前节点,
//所以要将“摘取”下来的节点放到当前节点之前的合适位置。
cur.next = nextNode.next;
ListNode node1 = aux;
ListNode node2 = aux.next;
while(nextNode.val > node2.val){
node1 = node2;
node2 = node2.next;
}
//找到了合适的位置
node1.next = nextNode;
nextNode.next = node2;
//设置新的下个节点
nextNode = cur.next;
}
}
return aux.next;
}
链表的快速排序
public ListNode quickSort(ListNode start,ListNode end){
if(start == null || end == null || start == end){
return start;
}
ListNode first = start;
ListNode second = start.next;
int value = start.val;
while(second != end.next && second != null){
if(second.val < value){
first = first.next;
//可以应对链表形式如5->3->6->0这种情况,保证大于value的没有排序的节点往后放
if(first != second){
int temp = first.val;
first.val = second.val;
second.val =temp;
}
}
second = second.next;
}
//比如最开始节点是整个链表的最小值,这时候就不用移动指针
if(start != first){
int temp = start.val;
start.val = first.val;
first.val = temp;
}
quickSort(start,first);
quickSort(first.next,end);
return start;
}
写快排我记三个例子,第一个例子是最开始的节点就是全链表的最小节点;第二个例子最开始额节点是全链表最大的节点;第三个例子是5->3->6->0这个例子。
自底向下的归并排序
使用自底向上的方法实现归并排序,则可以达到 O(1)O(1) 的空间复杂度。
首先求得链表的长度 \textit{length}length,然后将链表拆分成子链表进行合并。
官方的方法:
//自底向下的归并排序,进阶
public ListNode sortList(ListNode head) {
if(head == null){
return head;
}
int length = 0;
ListNode node = head;
while(node != null){
length++;
node = node.next;
}
ListNode resultHead = new ListNode(0,head);
for(int subLength = 1;subLength < length; subLength <<= 1){
ListNode pre = resultHead, cur = resultHead.next;
while(cur != null){
ListNode head1 = cur;
for(int i = 1; i < subLength && cur.next != null; i++){
cur = cur.next;
}
ListNode head2 = cur.next;
cur.next = null;
cur = head2;
for(int i = 1; i < subLength && cur != null && cur.next != null; i++){
cur = cur.next;
}
ListNode temp = null;
if(cur != null){
temp = cur.next;
cur.next = null;
}
ListNode merged = merge(head1,head2);
pre.next = merged;
while(pre.next != null){
pre = pre.next;
}
cur = temp;
}
}
return resultHead.next;
}
public ListNode merge(ListNode h1,ListNode h2){
ListNode mergerHead = new ListNode(0);
ListNode h = mergerHead;
ListNode head1 = h1,head2 = h2;
while(head1 != null && head2 != null){
if(head1.val < head2.val){
h.next = head1;
head1 = head1.next;
}else{
h.next = head2;
head2 = head2.next;
}
h = h.next;
}
if(head1 != null){
h.next = head1;
}else if(head2 != null){
h.next = head2;
}
return mergerHead.next;
}
注意一下左移赋值就行。