算法之链表排序

本文介绍了如何使用归并排序方法对链表进行升序排序,包括快速找到链表中间节点、递归分割链表和合并已排序链表的过程。时间复杂度分析为O(nlogn)。通过测试用例验证了排序功能的正确性。
摘要由CSDN通过智能技术生成

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);
    }
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值