链表排序

O(n log n)的时间复杂度对链表进行排序。

一、 归并排序

采用分治思想的归并排序,主要需要的方法有寻找中间结点的函数ListNode Findmid(ListNode head)和归并两个有序链表的函数ListNode merge(ListNode head1, ListNode head2)。然后采用递归的方式调用ListNode sortList(ListNode head)函数,找出中间结点,分别对右链和左链进行排序后,归并左链和右链。

1. Findmid(ListNode head)函数

采用快慢指针,快指针到链尾时,慢指针到中间结点。

2. merge(ListNode head1, ListNode head2)函数

从两个链表的第一个值开始比较,取小值存入新链表,取较小值链表的下一个值继续比较。

 

完整代码如下:

 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode mid = Findmid(head);
        ListNode right = sortList(mid.next);
        mid.next = null;
        ListNode left = sortList(head);
        return merge(left, right);
    }
    private ListNode Findmid(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode fast = head.next;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    private ListNode merge(ListNode head1, ListNode head2) {
        if (head1 == null && head2 == null) {
            return null;
        }
        ListNode dummy = new ListNode(0);
        ListNode head = dummy;
        while (head1 != null && head2 != null) {
            if (head1.val < head2.val) {
                dummy.next = new ListNode(head1.val);
                head1 = head1.next;
            } else {
                dummy.next = new ListNode(head2.val);
                head2 = head2.next;
            }
            dummy = dummy.next;
        }
        while (head1 != null) {
            dummy.next = new ListNode(head1.val);
            head1 = head1.next;
            dummy = dummy.next;
        }
        while (head2 != null) {
            dummy.next = new ListNode(head2.val);
            head2 = head2.next;
            dummy = dummy.next;
        }
        return head.next;
    }
}

二、 快速排序1

采用三点切分的快速排序,先用ListNode Findmid(ListNode head)函数找到参考的中间结点,然后遍历链表,找到小于、等于和大于中间结点的结点分别形成左、中、右三个链表,递归调用ListNode sortList(ListNode head)函数将三个链表进行排序,之后利用ListNode Link(ListNode head1, ListNode head2, ListNode head3)函数将三个链表拼接起来。

1. Findmid(ListNode head)函数如上

2. Link(ListNode head1, ListNode head2, ListNode head3)函数

用到ListNode FindTail(ListNode head)函数寻找尾结点,然后将上一个尾结点连接到下一个头结点即可。

需要注意的是考虑到三个输入参数的链表可能为空,所以需要新建一个哨兵结点连接到链表头,从而保证寻找到的尾结点不为空,方便进行连接操作。

 

完整代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode mid = Findmid(head);
        ListNode LeftDummy = new ListNode(0);
        ListNode LeftHead = LeftDummy;
        ListNode RightDummy = new ListNode(0);
        ListNode RightHead = RightDummy;
        ListNode MiddleDummy = new ListNode(0);
        ListNode MiddleHead = MiddleDummy;
        while (head != null) {
            if (head.val < mid.val) {
                LeftDummy.next = head;
                LeftDummy = LeftDummy.next;
            } else if (head.val > mid.val) {
                RightDummy.next = head;
                RightDummy = RightDummy.next;
            } else {
                MiddleDummy.next = head;
                MiddleDummy = MiddleDummy.next;
            }
            head = head.next;
        }
        LeftDummy.next = null;
        RightDummy.next = null;
        MiddleDummy.next = null;
        ListNode Left = sortList(LeftHead.next);
        ListNode Right = sortList(RightHead.next);
        return Link(Left, MiddleHead.next, Right);
    }
    private ListNode Findmid(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode fast = head.next;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    private ListNode Link(ListNode head1, ListNode head2, ListNode head3) {
        ListNode dummy = new ListNode(0);
        ListNode head = dummy;
        dummy.next = head1;
        dummy = FindTail(dummy);
        dummy.next = head2;
        dummy = FindTail(dummy);
        dummy.next = head3;
        return head.next;
    }
    private ListNode FindTail(ListNode head) {
        if (head == null) {
            return null;
        }
        while (head != null && head.next != null) {
            head = head.next;
        }
        return head;
    }
}

 三、 快速排序2

利用切分函数。

posted on 2015-11-09 22:40  ShinningWu  阅读(662)  评论(0编辑  收藏  举报

导航