1、快速排序
普通快速排序思路:
选择1个结点为中心点,保证中心点左边比中心点小,中心点右边比中心点大即可。这就是一次快排,确定一个数的正确位置,然后进行递归。
单链表的实现为:
(1) 使第一个节点为中心点
(2) 创建2个指针(p,q),p指向头结点,q指向p的下一个节点
(3) q开始遍历,如果发现q的值比中心点的值小,则此时p=p->next,并且执行当前p的值和q的值交换,q遍历到链表尾即可
(4) 把头结点的值和p的值执行交换。此时p节点为中心点,并且完成1轮快排
使用递归的方法即可完成排序
编码实现:
public class AlgoTest {
public static void main(String[] args) {
ListNode n1 = new ListNode(3);
ListNode n2 = new ListNode(1);
ListNode n3 = new ListNode(5);
ListNode n4 = new ListNode(2);
ListNode n5 = new ListNode(8);
ListNode n6 = new ListNode(9);
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5;
n5.next = n6;
print(n1);
quickSort(n1);
print(n1);
}
static class ListNode {
int val;
ListNode next;
ListNode(int data) {
this.val = data;
}
}
private static void print(ListNode p) {
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
System.out.println();
}
public static void quickSort(ListNode head) {
if (head == null || head.next == null) {
return;
}
ListNode end = head;
while (end.next != null) {
end = end.next;
}
sort(head, end);
}
private static void sort(ListNode begin, ListNode end) {
//判断为空,判断是不是只有一个节点
if (begin == null || end == null || begin == end)
return;
//从第一个节点和第一个节点的后面一个几点
ListNode first = begin;
ListNode second = begin.next;
int nMidValue = begin.val;
//结束条件,second到最后了
while (second != end.next && second != null) {
if (second.val < nMidValue) {
first = first.next;
//判断一下,避免后面的数比第一个数小,不用换的局面
if (first != second) {
swap(first, second);
}
}
second = second.next;
}
//判断,有些情况是不用换的,提升性能
if (begin != first) {
swap(begin, first);
}
//前部分递归
sort(begin, first);
//后部分递归
sort(first.next, end);
}
private static void swap(ListNode a, ListNode b) {
int temp = a.val;
a.val = b.val;
b.val = temp;
}
}
运行结果:
2、归并排序
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,归并排序将两个已排序的表合并成一个表。
归并排序基本原理:
通过对若干个有序结点序列的归并来实现排序。
所谓归并是指将若干个已排好序的部分合并成一个有序的部分
编码实现:
public class AlgoTest {
public static void main(String[] args) {
ListNode n1 = new ListNode(3);
ListNode n2 = new ListNode(1);
ListNode n3 = new ListNode(5);
ListNode n4 = new ListNode(2);
ListNode n5 = new ListNode(8);
ListNode n6 = new ListNode(9);
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5;
n5.next = n6;
print(n1);
// 注意返回值
n1 = mergeSort(n1);
print(n1);
}
static class ListNode {
int val;
ListNode next;
ListNode(int data) {
this.val = data;
}
}
private static void print(ListNode p) {
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
System.out.println();
}
//单链表的归并排序
public static ListNode mergeSort(ListNode head) {
if (head == null || head.next == null) {
return head;
}
//得到链表中间的数
ListNode middle = getMiddle(head);
ListNode midNext = middle.next;
//拆分链表
middle.next = null;
//递归调用
return merge(mergeSort(head), mergeSort(midNext));
}
// 合并排好序的链表
private static ListNode merge(ListNode a, ListNode b) {
ListNode dummyHead = new ListNode(-1);
ListNode curr = dummyHead;
while (a != null && b != null) {
if (a.val <= b.val) {
curr.next = a;
a = a.next;
} else {
curr.next = b;
b = b.next;
}
curr = curr.next;
}
if (a != null) {
curr.next = a;
}
if (b != null) {
curr.next = b;
}
return dummyHead.next;
}
//找到中间点,然后分割
private static ListNode getMiddle(ListNode head) {
if (head == null) {
return head;
}
//快慢指针
ListNode slow = head, fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}