5种链表排序算法(多语言描述)

148. 排序链表

与数组的排序算法相比,由于链表不支持随机访问,故不能使用堆排序希尔排序,因为他们都依赖于对下标的运算和随机访问某一下标的元素

冒泡排序

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
    }
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值