与数组的排序算法相比,由于链表不支持随机访问,故不能使用堆排序和希尔排序,因为他们都依赖于对下标的运算和随机访问某一下标的元素
冒泡排序
C++
int listLength(ListNode* head) {
int l = 0;
while (head) {
l++;
head = head->next;
}
return l;
}
ListNode* bubbleSort(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return head;
int N = listLength(head);
bool sorted = false;
while (!sorted) {
sorted = true;
auto p1 = head, p2 = head->next;
for (int i = 0; i < N && p1 && p2; i++) {
if (p1->val > p2->val) {
swap(p1->val, p2->val);
sorted = false;
}
p1 = p1->next;
p2 = p2->next;
}
N--;
}
return head;
}
Python
def listLength(head):
l = 0
while head:
l += 1
head = head.next
return l
def bubbleSortList(head):
if head is None or head.next is None:
return head
N = listLength(head)
sorted = False
while not sorted:
sorted = True
p1, p2 = head, head.next
for i in range(0, N - 1):
if not (p1 and p2):
break
if p1.val > p2.val:
p1.val, p2.val = p2.val, p1.val
sorted = False
p1, p2 = p1.next, p2.next
N -= 1
return head
Golang
func listLength(head *ListNode) int {
l := 0
for head != nil {
l++
head = head.Next
}
return l
}
func bubbleSortList(head *ListNode) *ListNode{
if head == nil || head.Next == nil {
return head
}
N := listLength(head)
sorted := false
for !sorted {
sorted = true
p1, p2 := head, head.Next
for i := 0; i < N && p1 != nil && p2 != nil; i++ {
if p1.Val > p2.Val {
p1.Val, p2.Val = p2.Val, p1.Val
sorted = false
}
p1, p2 = p1.Next, p2.Next
}
}
return head
}
插入排序
C++
ListNode* cutHead(ListNode*& head) {
if (!head)
return head;
auto res = head;
head = head->next;
res->next = nullptr;
return res;
}
ListNode* insertionSortList(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return head;
auto dummy = new ListNode(0, cutHead(head));
while (head) {
auto p = cutHead(head);
auto n = dummy;
while (n->next && p->val >= n->next->val) {
n = n->next;
}
p->next = n->next;
n->next = p;
}
auto res = dummy->next;
delete dummy;
return res;
}
Python
def cut_head(head):
if head is None:
return head
n = head.next
head.next = None
return head, n
def insertion_sort(head):
if head is None or head.next is None:
return head
h, head = cut_head(head)
dummy = ListNode(0, h)
while head:
p, head = cut_head(head)
n = dummy
while n.next and n.next.val <= p.val:
n = n.next
p.next = n.next
n.next = p
return dummy.next
Golang
func cutHead(head **ListNode) *ListNode {
if *head == nil {
return nil
}
res := *head
*head = (*head).Next
res.Next = nil
return res
}
func insertionSort(head *ListNode) *ListNode{
if head == nil || head.Next == nil {
return head
}
dummy := &ListNode{Next: cutHead(&head)}
for head != nil {
p := cutHead(&head)
n := dummy
for n.Next != nil && p.Val >= n.Next.Val {
n = n.Next
}
p.Next = n.Next
n.Next = p
}
return dummy.Next
}
选择排序
C++
ListNode* findMin(ListNode* head) {
if (!head) return 0;
int min_val = head->val;
auto min_node = head;
while (head) {
if (head->val < min_val) {
min_val = head->val;
min_node = head;
}
head = head -> next;
}
return min_node;
}
ListNode* selectionSort(ListNode* head) {
if (head == nullptr && head->next == nullptr) return head;
auto p = head;
while (p) {
auto n = findMin(p);
swap(n->val, p->val);
p = p->next;
}
return head;
}
Python
def find_min(head):
if head is None:
return head
min_val = head.val
min_node = head
while head:
if head.val < min_node.val:
min_val = head.val
min_node = head
head = head.next
return min_node
def selection_sort(head):
if head is None or head.next is None:
return head
p = head
while p:
m = find_min(p)
m.val, p.val = p.val, m.val
p = p.next
return head
Golang
func findMin(head *ListNode) *ListNode {
if head == nil || head.Next == nil{
return head
}
min_val := head.Val
min_node := head
for head != nil {
if head.Val < min_val {
min_val = head.Val
min_node = head
}
head = head.Next
}
return min_node
}
func selectionSortList(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
p := head
for p != nil {
m := findMin(p)
p.Val, m.Val = m.Val, p.Val
p = p.Next
}
return head
}
归并排序
采用自底向上的归并排序算法,为了保持核心的排序算法尽可能简单,定义了一些语义明确的辅助函数
C++
int listLength(ListNode* head) {
int l = 0;
while (head) {
l++;
head = head->next;
}
return l;
}
void append(ListNode*& head, ListNode*& tail, ListNode* h, ListNode* t) {
if (head == nullptr) {
head = h;
tail = t;
} else {
tail->next = h;
tail = t;
}
}
ListNode* merge(ListNode* l1, ListNode* l2, ListNode*& tail) {
if (!l1)
return l2;
if (!l2)
return l1;
ListNode* dummy = new ListNode(0, nullptr);
tail = dummy;
while (l1 && l2) {
if (l1->val <= l2->val) {
tail->next = l1;
l1 = l1->next;
} else {
tail->next = l2;
l2 = l2->next;
}
tail = tail->next;
}
while (l1) {
tail->next = l1;
l1 = l1->next;
tail = tail->next;
}
while (l2) {
tail->next = l2;
l2 = l2->next;
tail = tail->next;
}
auto res = dummy->next;
delete dummy;
return res;
}
ListNode* take_n_nodes(ListNode*& h, int l) {
if (!h)
return h;
auto res = h, prev = h;
for (int i = 0; i < l && h; i++) {
prev = h;
h = h->next;
}
prev->next = nullptr;
return res;
}
ListNode* mergeSort(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return head;
int length = listLength(head);
auto h = head;
for (int sub_len = 1; sub_len < length; sub_len <<= 1) {
ListNode *hd = nullptr, *tail = nullptr;
while (h) {
auto h1 = take_n_nodes(h, sub_len);
auto h2 = take_n_nodes(h, sub_len);
ListNode* t = nullptr;
auto m = merge(h1, h2, t);
append(hd, tail, m, t);
}
h = hd;
}
return h;
}
Python
def listLength(head):
l = 0
while head:
head = head.next
l += 1
return l
def take_n_nodes(h, l):
if h is None:
return h, h
hn = h
while h.next and l > 1:
h = h.next
l -= 1
t = h.next
h.next = None
return hn, t
# h1 is None or h2 is None only happens when 1-0 merge
# so it's reasonble to just return h1 or h2 as tail
def merge(h1, h2):
if h1 is None:
return h2, h2 # sick tail
if h2 is None:
return h1, h1 # sick tail
dummy = ListNode()
t = dummy
while h1 and h2:
if h1.val <= h2.val:
t.next = h1
h1 = h1.next
else:
t.next = h2
h2 = h2.next
t = t.next
while h1:
t.next = h1
h1 = h1.next
t = t.next
while h2:
t.next = h2
h2 = h2.next
t = t.next
return dummy.next, t
def append(head, tail, h, t):
if head is None:
return h, t
tail.next = h
return head, t
def mergeSort(h):
if h is None or h.next is None:
return h
l = listLength(h)
sub_len = 1
while sub_len < l:
head, tail = None, None
while h:
h1, h = take_n_nodes(h, sub_len)
h2, h = take_n_nodes(h, sub_len)
h3, t = merge(h1, h2)
head, tail = append(head, tail, h3, t)
h = head
sub_len <<= 1
return h
Golang
func listLength(head *ListNode) int {
l := 0
for head != nil {
l++
head = head.Next
}
return l
}
func appendNode(head **ListNode, tail **ListNode, h *ListNode, t *ListNode) {
if *head == nil {
*head = h
*tail = t
} else {
(*tail).Next = h
*tail = t
}
}
func merge(l1 *ListNode, l2 *ListNode, tail **ListNode) *ListNode {
if l1 == nil {
return l2
}
if l2 == nil {
return l1
}
dummy := &ListNode{Val: 0}
*tail = dummy
for l1 != nil && l2 != nil {
if l1.Val <= l2.Val {
(*tail).Next = l1
l1 = l1.Next
} else {
(*tail).Next = l2
l2 = l2.Next
}
*tail = (*tail).Next
}
for l1 != nil {
(*tail).Next = l1
l1 = l1.Next
*tail = (*tail).Next
}
for l2 != nil {
(*tail).Next = l2
l2 = l2.Next
*tail = (*tail).Next
}
res := dummy.Next
return res
}
func takeNNodes(h **ListNode, l int) *ListNode {
if *h == nil {
return *h
}
res := *h
prev := *h
for i := 0; i < l && *h != nil; i++ {
prev = *h
*h = (*h).Next
}
prev.Next = nil
return res
}
func mergeSort(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
length := listLength(head)
h := head
for subLen := 1; subLen < length; subLen <<= 1 {
var hd, tail *ListNode
for h != nil {
h1 := takeNNodes(&h, subLen)
h2 := takeNNodes(&h, subLen)
var t *ListNode
m := merge(h1, h2, &t)
appendNode(&hd, &tail, m, t)
}
h = hd
}
return h
}
快速排序
C++
由于单链表不支持随机访问,只能选择第一个元素作为主元,所以会导致快速排序算法在链表完全有序的情况下超时
void append(ListNode*& head, ListNode*& tail, ListNode* n) {
if (head == nullptr) {
head = tail = n;
} else {
tail->next = n;
tail = n;
}
}
void quick_sort(ListNode*& head, ListNode*& tail) {
if (head == nullptr || head->next == nullptr) return;
int pivot = head->val;
ListNode *left_head = nullptr, *left_tail = nullptr;
ListNode *right_head = nullptr, *right_tail = nullptr;
auto h = head->next;
while (h) {
auto p = h->next;
h->next = nullptr;
if (pivot >= h->val) {
append(left_head, left_tail, h);
} else {
append(right_head, right_tail, h);
}
h = p;
}
quick_sort(left_head, left_tail), quick_sort(right_head, right_tail);
append(left_head, left_tail, head);
head->next = right_head;
head = left_head, tail = right_tail ? right_tail : left_tail;
}
ListNode* sortList(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return head;
auto tail = head;
while (tail->next) {
tail = tail->next;
}
quick_sort(head, tail);
return head;
}
Python
def append(head, tail, n):
if head is None:
return n, n
tail.next = n
return head, tail.next
def quick_sort(head, tail):
if head is None or head.next is None:
return head, head
pivot = head.val
left_head, left_tail = None, None
right_head, right_tail = None, None
h = head.next
while h:
p = h.next
h.next = None
if pivot >= h.val:
left_head, left_tail = append(left_head, left_tail, h)
else:
right_head, right_tail = append(right_head, right_tail, h)
h = p
if left_head and left_head.next:
left_head, left_tail = quick_sort(left_head, left_tail)
if right_head and right_head.next:
right_head, right_tail = quick_sort(right_head, right_tail)
left_head, left_tail = append(left_head, left_tail, head)
head.next = right_head
tail = right_tail if right_tail else left_tail
return left_head, tail
Golang
func append(head **ListNode, tail **ListNode, n *ListNode) {
if *head == nil {
*head = n
*tail = n
} else {
(*tail).Next = n
*tail = (*tail).Next
}
}
func quickSort(head **ListNode, tail **ListNode) {
if *head == nil || (*head).Next == nil {
return
}
pivot := (*head).Val
var left_head, left_tail *ListNode
var right_head, right_tail *ListNode
h := (*head).Next
for h != nil {
t := h.Next
h.Next = nil
if h.Val <= pivot {
append(&left_head, &left_tail, h)
} else {
append(&right_head, &right_tail, h)
}
h = t
}
quickSort(&left_head, &left_tail)
quickSort(&right_head, &right_tail)
append(&left_head, &left_tail, *head)
(*head).Next = right_head
*head = left_head
if right_tail != nil {
*tail = right_tail
} else {
*tail = left_tail
}
}