对链表进行快速排序,之前有写过文章,详情可参考java实现单链表的快速排序,不过代码实现有些臃肿,因此有了今天的加强版(利用哑铃节点的技巧,减少了许多判空的代码)。
对应快速排序,相信非常熟悉了,直接来看代码实现
public ListNode quickSort(ListNode head, ListNode tail) {
ListNode p;
if (head == null || head == tail || (p = head.next) == null || p == tail) {
return head;
}
ListNode d1 = new ListNode(-1), d2 = new ListNode(-1), p1 = d1, p2 = d2;
do {
if (p.val < head.val) {
p1.next = p;
p1 = p1.next;
} else {
p2.next = p;
p2 = p2.next;
}
} while ((p = p.next) != tail);
p1.next = head;p2.next = tail;
ListNode left = quickSort(d1.next, head);
head.next = quickSort(d2.next, tail);
return left == null ? head : left;
}
不多不少,刚好20行,找力扣上的一道链表排序题验证准确性,发现可以AC的
现在来讲讲代码的主要逻辑,快速排序的思想就不说了,详情可参考这篇文章快速排序。
首先说明一下该方法的语义:对 [head,tail) 进行快速排序并返回新的头节点,注意方法的第二个参数tail,它的作用为用作边界挡板,因此方法首次调用时的传递为quickSort(head, null)
代码核心逻辑为引入2个哑铃节点d1(存较小的),d2(存较大的),每次都以头节点的值作为基准volt,比volt小的连接在d1上,比volt大的连接在d2上,举个例子,对以下链表排序,
3->6->5->1->2
第一趟排序结果为1->2->3->6->5
此时head指向3也就是volt,那么接下来就是要对[1,3)、[6,5]递归进行快速排序,因此函数的base会对head与tail做判断,如果碰到挡板直接返回了,对于[1,3),3也就是head(也是基准中间值)成为新的挡板,然后再对右边排序,最后返回新的头节点。