leetcode 148 排序链表
题目
给定链表的头节点,将其按升序排序返回排序后的链表。
解题思路
归并排序对于链表排序来说是一种稳定高效的方法。
- 分解:利用快慢指针找到中间节点,将链表对半分割,一直到只剩下一个或两个节点。
- 递归:对于每个子链表,递归的进行归并排序。
- 合并:合并有序子链表。
时间复杂度分析:
- 链表对半分割,时间复杂度为O(n)
- 归并排序时间复杂度为O(nlogn)
- 合并链表时间复杂度为O(m+n)
- 整体的时间复杂度为O(nlogn)
代码实现
public ListNode sortList(ListNode head) {
return sortListx(head, null);
}
/**
* 递归将链表对半分割,直到只剩下一个或两个节点
* @param head
* @param tail
*/
public ListNode sortList(ListNode head, ListNode tail) {
// 链表为空直接返回
if(head == null) {
return head;
}
// 只有两个节点的链表,调整顺序返回
if(head.next == tail) { //??
head.next = null;
return head;
}
// 使用快慢指针找到中间节点
ListNode slow = head, fast = head;
while(fast != tail) {
slow = slow.next;
fast = fast.next;
if(fast != tail) {
fast = fast.next;
}
}
ListNode mid = slow;
// 递归对左右两部分进行排序
ListNode list1 = sortList(head, mid);
ListNode list2 = sortList(mid, tail);
// 合并已排序的链表
ListNode sorted = merge(list1, list2);
return sorted;
}
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode temp = dummy, temp1 = l1, temp2 = l2;
// 链表都不为空时合并链表
while(temp1 != null && temp2 != null) {
if(temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
// 两链表其中一个为空时,直接将另外一个链表连接到新链表的末尾
if(temp1 != null) {
temp.next = temp1;
} else if(temp2 != null) {
temp.next = temp2;
}
return dummy.next;
}
测试代码
public class SortListTest {
private SortList sortList;
@Before
public void setUp() {
sortList = new SortList();
}
@Test
public void testSortList_emptyList() {
ListNode head = null;
ListNode sortedHead = sortList.sortList(head);
Assert.assertNull("The sorted list should be null for an empty list", sortedHead);
}
@Test
public void testSortList_singleElementList() {
ListNode head = new ListNode(1);
ListNode sortedHead = sortList.sortList(head);
Assert.assertSame("The sorted list should be the same as the input for a list with a single element", head, sortedHead);
}
@Test
public void testSortList_listWithNegativeNumbers() {
ListNode head = new ListNode(-3);
head.next = new ListNode(0);
head.next.next = new ListNode(-1);
ListNode sortedHead = sortList.sortList(head);
Assert.assertEquals("The sorted list should be -3, -1, 0", -3, sortedHead.val);
Assert.assertEquals("The second node should be -1", -1, sortedHead.next.val);
Assert.assertEquals("The third node should be 0", 0, sortedHead.next.next.val);
}
@Test
public void testSortList_listWithDuplicates() {
ListNode head = new ListNode(4);
head.next = new ListNode(2);
head.next.next = new ListNode(1);
head.next.next.next = new ListNode(2);
head.next.next.next.next = new ListNode(1);
ListNode sortedHead = sortList.sortList(head);
Assert.assertEquals("The sorted list should be 1, 1, 2, 2, 4", 1, sortedHead.val);
Assert.assertEquals("The second node should be 1", 1, sortedHead.next.val);
Assert.assertEquals("The third node should be 2", 2, sortedHead.next.next.val);
Assert.assertEquals("The fourth node should be 2", 2, sortedHead.next.next.next.val);
Assert.assertEquals("The fifth node should be 4", 4, sortedHead.next.next.next.next.val);
}
@Test
public void testSortList_listWithLargeNumbers() {
ListNode head = new ListNode(10);
head.next = new ListNode(3);
head.next.next = new ListNode(5);
head.next.next.next = new ListNode(2);
head.next.next.next.next = new ListNode(8);
ListNode sortedHead = sortList.sortList(head);
Assert.assertEquals("The sorted list should be 2, 3, 5, 8, 10", 2, sortedHead.val);
Assert.assertEquals("The second node should be 3", 3, sortedHead.next.val);
Assert.assertEquals("The third node should be 5", 5, sortedHead.next.next.val);
Assert.assertEquals("The fourth node should be 8", 8, sortedHead.next.next.next.val);
Assert.assertEquals("The fifth node should be 10", 10, sortedHead.next.next.next.next.val);
}
}