链表排序
以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) 编辑 收藏 举报