1、插入排序
思路:外循环保证元素的逐个插入,不用考虑是否断裂,内循环根据找个要插入元素的前一个节点,然后把待插入的节点放进去,修改两个指针即可。
//1 插入排序N*N
public static ListNode sortList1(ListNode head) {
if (head == null) return head;
ListNode helper = new ListNode(0);
while (head != null) {
ListNode temp = head.next;
ListNode node = helper;
while (node.next != null && node.next.val < head.val) node = node.next;
head.next = node.next;
node.next = head;
head = temp;
}
return helper.next;
}
2、归并排序
思路:找到链表的中间节点,把链表断开成两段,然后两段递归,返回两段的合并
使用归并排序 使用Merge Sort, 空间复杂度是 O(logN) 因为使用了栈空间
public ListNode sortList(ListNode head) {
// write your code here
if (head == null || head.next == null) {
return head;
}
ListNode slow = head;
ListNode fast = head.next.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode head2 = sortList(slow.next);
slow.next = null;
ListNode head1 = sortList(head);
return mergeSorted(head1,head2);
}
public ListNode mergeSorted(ListNode h1,ListNode h2) {
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
while (h1 != null && h2 != null) {
if (h1.val < h2.val) {
p.next = h1;
h1 = h1.next;
} else {
p.next = h2;
h2 = h2.next;
}
p = p.next;
}
if (h1 != null) {
p.next = h1;
}
if (h2 != null) {
p.next = h2;
}
return dummy.next;
}
3、快速排序
思路:
- 使第一个节点为中心点
- 创建2个指针(p,q),p指向头结点,q指向p的下一个节点
- q开始遍历,如果发现q的值比中心点的值小,则此时p=p->next,并且执行当前p的值和q的值交换,q遍历到链表尾即可
- 把头结点的值和p的值执行交换。此时p节点为中心点,并且完成1轮快排
- 使用递归的方法即可完成排序
方式一:通过交换节点的值来实现
public ListNode sortList(ListNode head) {
// write your code here
ListNode tail = head;
while (tail != null && tail.next!= null) {
tail = tail.next;
}
quick_sort(head,tail);
return head;
}
public void quick_sort(ListNode start,ListNode end) {
if (start == null || end == null || start == end) {
return;
}
ListNode slow = start;
ListNode fast = start.next;
int base = start.val;
while (fast != end.next && fast != null) {
if (fast.val < base) {
slow = slow.next;
if (slow != fast) {
int temp = slow.val;
slow.val = fast.val;
fast.val = temp;
}
}
fast = fast.next;
}
if (start != slow) {
int temp = slow.val;
slow.val = start.val;
start.val = temp;
}
quick_sort(start,slow);
quick_sort(slow.next,end);
}
方式二,通过交换节点来实现
一次遍历把链表分成三段,第一段都是比所选分界点值小的,第二段是值和分界点值相等的,第三段是比分界点值大的,然后合并三段即可
public ListNode sortList(ListNode head) {
// write your code here
if (head == null || head.next == null) {
return head;
}
ListNode left = new ListNode(-1);
ListNode mid = new ListNode(-1);
ListNode right = new ListNode(-1);
ListNode lefthead = left;
ListNode midhead = mid;
ListNode righthead = right;
int base = head.val;
ListNode p = head;
while (p != null) {
if (p.val < base) {
left.next = p;
left = left.next;
} else if (p.val > base) {
right.next = p;
right = right.next;
} else {
mid.next = p;
mid = mid.next;
}
p = p.next;
}
left.next = null;
mid.next = null;
right.next =null;
return merge(sortList(lefthead.next),midhead.next,sortList(righthead.next));
}
public ListNode merge(ListNode first,ListNode mid,ListNode end) {
ListNode res = null;
//判断是否有第一段
if (first != null) {
res = first;
ListNode tail = findtail(first);
tail.next = mid;
} else {
res = mid;
}
//拼接后半段
ListNode midtail = findtail(mid);
midtail.next = end;
return res;
}
public ListNode findtail(ListNode head) {
while (head != null && head.next != null) {
head = head.next;
}
return head;
}