每日一恋 - LeetCode 147 & 148. 对链表进行排序

147. 对链表进行插入排序

这里写图片描述

  • 插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)
  • 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中

插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

分析

将原链表分为两个部分:已排好序和未排好序,pre指针代表已排好序链表的哑节点,cur为未排序链表的头节点。进行插入操作时,cur指针依次遍历原链表,pre指针遍历黑色表示的元素,找到正确的插入位置,将cur节点插入,然后cur指针指向下一个待排序的元素。

public ListNode insertionSortList(ListNode head) {

    if (head == null) {
        return head;
    }
    ListNode dummyHead = new ListNode(0);

    ListNode cur = head; // 待排序/插入的节点
    ListNode pre = dummyHead; // 正确插入位置的指针
    ListNode next; // 下一个插入结点
    while (cur != null) {
        next = cur.next;

        while (pre.next != null && pre.next.val < cur.val) { // 插入查找
            pre = pre.next;
        }
        // 断开现有结点
        cur.next = pre.next;
        pre.next = cur;
        pre = dummyHead;
        cur = next;
    }

    return dummyHead.next;
}

148. 排序链表

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

分析

归并排序的时间复杂度是 O( n log n ),将数组的归并排序修改成链表的归并排序即可。

我的代码

public ListNode sortList(ListNode head) {

    ListNode cur = head;
    int i = 0;
    while (cur != null) {
        cur = cur.next;
        i ++;
    }
    return sort(head, 0, i - 1);
}

public ListNode sort(ListNode head, int l, int r) {

    if (l >= r) {
        return head;
    }
    int mid = l + (r-l) / 2;
    ListNode cur = head;
    int i = 0;
    while (cur != null && i < mid - l) {
        cur = cur.next;
        i ++;
    }
    ListNode tmp = cur.next;
    cur.next = null;


    ListNode left = sort(head, l, mid);
    ListNode right = sort(tmp, mid + 1, r);
    ListNode merge = merge(left, right);
    return merge;
}

public ListNode merge(ListNode a, ListNode b) {

    ListNode dummyHead = new ListNode(0);
    ListNode cur = dummyHead;
    while (a != null || b != null) {

        if (a == null) {
            cur.next = b;
            break;
        }
        else if (b == null) {
            cur.next = a;
            break;
        }
        else if (a.val < b.val) {
            cur.next = new ListNode(a.val);
            cur = cur.next;
            a = a.next;
        }
        else {
            cur.next = new ListNode(b.val);
            cur = cur.next;
            b = b.next;
        }
    }
    return dummyHead.next;
}

其中merge这一步,我这里是创建新的节点,其实也可以直接使用原链表的节点。每移动一个节点,就选两个链表中较小的节点接到结果链表中,直到其中一个链表遍历完,将另一个链表余下的节点接到最后即可。

 public ListNode merge(ListNode l1, ListNode l2) {
    ListNode l = new ListNode(0), p = l;

    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            p.next = l1;
            l1 = l1.next;
        } else {
            p.next = l2;
            l2 = l2.next;
        }
        p = p.next;
    }

    if (l1 != null)
        p.next = l1;

    if (l2 != null)
        p.next = l2;

    return l.next;
}

如果文章里有说得不对的地方请前辈多多指正~ 与君共勉~

猜你喜欢

转载自blog.csdn.net/smartnijun/article/details/81774449