排序链表

题目要求

你需要编写一个算法,对一个单向链表进行排序。输入是链表的头结点 head,你需要对链表中的元素按照升序进行排序,然后返回排序后链表的头结点。

解题思路

要对链表进行排序,有几种不同的算法可以选择:

  1. 归并排序:这是链表排序中最常用的方法,因为它在链表上的时间复杂度是线性对数的,即 O(nlogn),而且它不需要额外的空间,这对链表来说是非常合适的。

    • 分解:首先,使用快慢指针法找到链表的中点,将链表分成两半。快指针每次移动两步,慢指针每次移动一步,当快指针到达链表末尾时,慢指针就在链表的中点。
    • 递归排序:递归地对两个子链表进行排序。
    • 合并:将两个已排序的子链表合并成一个有序的链表。
  2. 插入排序:虽然插入排序在数组排序中效率不高(时间复杂度为 O(n^2)),但在链表排序中,由于插入操作是 O(1) 的,所以在链表不是很长或基本有序的情况下,插入排序也是一个不错的选择。

    • 迭代:从头结点开始,对链表进行迭代,将每个节点插入到已排序部分的正确位置。
  3. 快速排序:链表上的快速排序实现起来比较复杂,且需要额外的空间来存储上一层递归的状态,因此不是最优选择。

在这些方法中,归并排序是最优的选择,因为它提供了最好的平均性能,并且是稳定的排序算法。具体步骤如下:

  1. 如果链表只有一个节点或为空,则不需要排序,直接返回。
  2. 使用快慢指针法找到链表的中间节点,将链表从中间分为两部分。
  3. 对这两部分分别进行归并排序。
  4. 将两个排序好的链表合并成一个有序链表。
  5. 返回排序后的链表头结点。

注意,在实际编码时,需要处理好边界条件,如链表为空或只有一个节点的情况,以及在分割和合并过程中对节点的正确处理。

Golang 版本

package main

import (
	"fmt"
)

// ListNode is a node in a singly-linked list.
type ListNode struct {
	Val  int
	Next *ListNode
}

// mergeTwoLists merges two sorted linked lists and returns the head of the sorted list.
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	dummy := &ListNode{}
	current := dummy

	for l1 != nil && l2 != nil {
		if l1.Val < l2.Val {
			current.Next = l1
			l1 = l1.Next
		} else {
			current.Next = l2
			l2 = l2.Next
		}
		current = current.Next
	}

	if l1 != nil {
		current.Next = l1
	} else {
		current.Next = l2
	}

	return dummy.Next
}

// sortList sorts the linked list in ascending order using merge sort and returns the head of the list.
func sortList(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}

	// Find the middle of the list
	slow, fast := head, head.Next
	for fast != nil && fast.Next != nil {
		fast = fast.Next.Next
		slow = slow.Next
	}

	// Split the list into two halves
	mid := slow.Next
	slow.Next = nil

	// Sort each half
	left := sortList(head)
	right := sortList(mid)

	// Merge the sorted halves
	return mergeTwoLists(left, right)
}

// Helper function to print the list - for testing purposes.
func printList(head *ListNode) {
	for head != nil {
		fmt.Printf("%d ", head.Val)
		head = head.Next
	}
	fmt.Println()
}

// main function to execute the code - for testing purposes.
func main() {
	// Example usage:
	// Create a linked list 4 -> 2 -> 1 -> 3 and sort it.
	node3 := &ListNode{Val: 3, Next: nil}
	node1 := &ListNode{Val: 1, Next: node3}
	node2 := &ListNode{Val: 2, Next: node1}
	head := &ListNode{Val: 4, Next: node2}

	sortedHead := sortList(head)
	printList(sortedHead) // Expected sorted list: 1 2 3 4
}

这段代码实现了链表的归并排序。sortList 函数是排序的主要入口,它使用递归将链表分成两半,然后对每一半进行排序,最后使用 mergeTwoLists 函数将两个有序链表合并成一个有序链表。main 函数提供了一个测试用例,创建了一个链表并调用 sortList 函数进行排序,然后打印排序后的链表。

C++版本

#include <iostream>

// Definition for singly-linked list.
struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    // Function to find the middle of the linked list
    ListNode* findMiddle(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head->next;
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }

    // Function to merge two sorted linked lists
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode dummy(0);
        ListNode* 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;
        }
        tail->next = l1 ? l1 : l2;
        return dummy.next;
    }

    // Main function to sort the linked list
    ListNode* sortList(ListNode* head) {
        if (!head || !head->next) return head;

        ListNode* mid = findMiddle(head);
        ListNode* left = head;
        ListNode* right = mid->next;
        mid->next = nullptr;

        left = sortList(left);
        right = sortList(right);

        return mergeTwoLists(left, right);
    }
};

// Helper function to print the list - for testing purposes.
void printList(ListNode* head) {
    while (head) {
        std::cout << head->val << " ";
        head = head->next;
    }
    std::cout << std::endl;
}

// main function to execute the code - for testing purposes.
int main() {
    // Example usage:
    // Create a linked list 4 -> 2 -> 1 -> 3 and sort it.
    ListNode* node3 = new ListNode(3);
    ListNode* node1 = new ListNode(1);
    node1->next = node3;
    ListNode* node2 = new ListNode(2);
    node2->next = node1;
    ListNode* head = new ListNode(4);
    head->next = node2;

    Solution solution;
    ListNode* sortedHead = solution.sortList(head);
    printList(sortedHead); // Expected sorted list: 1 2 3 4

    // Clean up memory
    while (sortedHead) {
        ListNode* temp = sortedHead;
        sortedHead = sortedHead->next;
        delete temp;
    }

    return 0;
}

这段 C++代码实现了链表的归并排序。Solution 类中的 sortList 函数是排序的主要入口,它使用递归将链表分成两半,然后对每一半进行排序,最后使用 mergeTwoLists 函数将两个有序链表合并成一个有序链表。main 函数提供了一个测试用例,创建了一个链表并调用 sortList 函数进行排序,然后打印排序后的链表,并在最后清理了分配的内存。

Python 版本

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head

        # Split the list into two halves
        slow, fast = head, head.next
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

        # Split the list into two halves
        mid = slow.next
        slow.next = None

        # Sort each half
        left = self.sortList(head)
        right = self.sortList(mid)

        # Merge the sorted halves
        return self.mergeTwoLists(left, right)

    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy = ListNode()
        tail = dummy

        while l1 and l2:
            if l1.val < l2.val:
                tail.next = l1
                l1 = l1.next
            else:
                tail.next = l2
                l2 = l2.next
            tail = tail.next

        tail.next = l1 or l2
        return dummy.next

# Helper function to print the list - for testing purposes.
def printList(node):
    while node:
        print(node.val, end=" ")
        node = node.next
    print()

# Example usage:
if __name__ == "__main__":
    # Create a linked list 4 -> 2 -> 1 -> 3 and sort it.
    node3 = ListNode(3)
    node1 = ListNode(1, node3)
    node2 = ListNode(2, node1)
    head = ListNode(4, node2)

    solution = Solution()
    sorted_head = solution.sortList(head)
    printList(sorted_head)  # Expected sorted list: 1 2 3 4

这段 Python 代码实现了链表的归并排序。Solution 类中的 sortList 方法是排序的主要入口,它使用递归将链表分成两半,然后对每一半进行排序,最后使用 mergeTwoLists 方法将两个有序链表合并成一个有序链表。printList 函数和 if __name__ == "__main__": 部分提供了一个测试用例,创建了一个链表并调用 sortList 方法进行排序,然后打印排序后的链表。

Java 版本

public class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        // Split the list into two halves
        ListNode prev = null, slow = head, fast = head;
        while (fast != null && fast.next != null) {
            prev = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        prev.next = null; // Cut the list into two halves

        // Sort each half
        ListNode l1 = sortList(head);
        ListNode l2 = sortList(slow);

        // Merge the sorted halves
        return mergeTwoLists(l1, l2);
    }

    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                current.next = l1;
                l1 = l1.next;
            } else {
                current.next = l2;
                l2 = l2.next;
            }
            current = current.next;
        }
        current.next = (l1 != null) ? l1 : l2;
        return dummy.next;
    }
}

// Helper function to print the list - for testing purposes.
class Main {
    public static void printList(ListNode node) {
        while (node != null) {
            System.out.print(node.val + " ");
            node = node.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // Example usage:
        // Create a linked list 4 -> 2 -> 1 -> 3 and sort it.
        ListNode node3 = new ListNode(3);
        ListNode node1 = new ListNode(1, node3);
        ListNode node2 = new ListNode(2, node1);
        ListNode head = new ListNode(4, node2);

        Solution solution = new Solution();
        ListNode sortedHead = solution.sortList(head);
        printList(sortedHead); // Expected sorted list: 1 2 3 4
    }
}

这段 Java 代码实现了链表的归并排序。Solution 类中的 sortList 方法是排序的主要入口,它使用递归将链表分成两半,然后对每一半进行排序,最后使用 mergeTwoLists 方法将两个有序链表合并成一个有序链表。Main 类中的 printList 方法和 main 方法提供了一个测试用例,创建了一个链表并调用 sortList 方法进行排序,然后打印排序后的链表。

Rust 版本

use std::cell::RefCell;
use std::rc::Rc;

// Definition for singly-linked list.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Rc<RefCell<ListNode>>>,
}

impl ListNode {
    #[inline]
    fn new(val: i32) -> Self {
        ListNode { next: None, val }
    }
}

struct Solution;

impl Solution {
    pub fn sort_list(head: Option<Rc<RefCell<ListNode>>>) -> Option<Rc<RefCell<ListNode>>> {
        if head.is_none() || head.as_ref().unwrap().borrow().next.is_none() {
            return head;
        }

        // Split the list into two halves
        let (left, right) = Self::split(head);
        // Sort each half
        let left_sorted = Self::sort_list(left);
        let right_sorted = Self::sort_list(right);
        // Merge the sorted halves
        Self::merge_two_lists(left_sorted, right_sorted)
    }

    fn split(
        head: Option<Rc<RefCell<ListNode>>>,
    ) -> (Option<Rc<RefCell<ListNode>>>, Option<Rc<RefCell<ListNode>>>) {
        let mut slow = head.clone();
        let mut fast = head.unwrap().borrow().next.clone();
        let mut prev = None;

        while let Some(fast_node) = fast {
            fast = fast_node.borrow().next.clone();
            if let Some(fast_node) = fast {
                prev = slow.clone();
                slow = slow.unwrap().borrow().next.clone();
                fast = fast_node.borrow().next.clone();
            }
        }

        let left = head;
        let right = slow.unwrap().borrow().next.take();
        if let Some(prev_node) = prev {
            prev_node.borrow_mut().next = None;
        }
        (left, right)
    }

    fn merge_two_lists(
        l1: Option<Rc<RefCell<ListNode>>>,
        l2: Option<Rc<RefCell<ListNode>>>,
    ) -> Option<Rc<RefCell<ListNode>>> {
        match (l1, l2) {
            (None, None) => None,
            (None, Some(node)) => Some(node),
            (Some(node), None) => Some(node),
            (Some(node1), Some(node2)) => {
                if node1.borrow().val < node2.borrow().val {
                    let next = Self::merge_two_lists(node1.borrow_mut().next.take(), Some(node2));
                    node1.borrow_mut().next = next;
                    Some(node1)
                } else {
                    let next = Self::merge_two_lists(Some(node1), node2.borrow_mut().next.take());
                    node2.borrow_mut().next = next;
                    Some(node2)
                }
            }
        }
    }
}

fn main() {
    // Example usage:
    // Create a linked list 4 -> 2 -> 1 -> 3 and sort it.
    let node3 = Rc::new(RefCell::new(ListNode::new(3)));
    let node1 = Rc::new(RefCell::new(ListNode { val: 1, next: Some(node3.clone()) }));
    let node2 = Rc::new(RefCell::new(ListNode { val: 2, next: Some(node1.clone()) }));
    let head = Some(Rc::new(RefCell::new(ListNode { val: 4, next: Some(node2.clone()) })));

    let sorted_head = Solution::sort_list(head);
    // Print the sorted list; expected: 1 -> 2 -> 3 -> 4
    let mut node = sorted_head;
    while let Some(n) = node {
        print!("{} -> ", n.borrow().val);
        node = n.borrow().next.clone();
    }
}

这段 Rust 代码实现了链表的归并排序。Solution 结构体中的 sort_list 函数是排序的主要入口,它使用递归将链表分成两半,然后对每一半进行排序,最后使用 merge_two_lists 函数将两个有序链表合并成一个有序链表。main 函数提供了一个测试用例,创建了一个链表并调用 sort_list 函数进行排序,然后打印排序后的链表。

总结

上面给出了使用不同编程语言实现的链表排序算法。这些算法主要使用了归并排序的思想,通过递归将链表分成两半,然后对每一半进行排序,最后合并两个有序链表。每种语言的实现细节略有不同,但整体思路是一致的。这些算法都能有效地对链表进行排序,并且在不同的编程语言中都有相应的数据结构和语法支持。