太久不写排序了,限时写已经写不出来了。愧为acmer。

面试官出了个单链表的排序,让我选一种排序,我选了归并排序。大概写了20分钟,一运行就崩溃,由于面试时间有限,面试官看了看我的代码提了几个易错点(如指针判空,链表分治)。

惭愧。

今天把排序算法搬出来分别用数组和单链表写了一遍,温故而知新。

数组版排序

#include <bits/stdc++.h>
using namespace std;

// 冒泡排序
void bubble_sort(int a[], int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n - i - 1; j++)
            if (a[j] > a[j + 1])
                swap(a[j], a[j + 1]);
    }
}

// 选择排序
void selection_sort(int a[], int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
            if (a[i] > a[j])
                swap(a[i], a[j]);
    }
}

// 插入排序
void insert_sort(int a[], int n)
{
    for (int i = 1; i < n; i++)
    {
        int curr = a[i], k = i;
        for (k = i - 1; k >= 0 && a[k] > curr; k--)
            a[k + 1] = a[k];
        a[k + 1] = curr;
    }
}

// 快速排序 严蔚敏版
void quick_sort(int a[], int L, int R)
{
    if (L >= R)
        return;
    int temp = a[L], low = L, high = R;
    while (low < high)
    {
        while (low < high && a[high] >= temp)
            high--;
        a[low] = a[high];
        while (low < high && a[low] <= temp)
            low++;
        a[high] = a[low];
    }
    a[low] = temp;
    quick_sort(a, L, low - 1);
    quick_sort(a, low + 1, R);
}

// 快速排序 交换版
void quick_sort_2(int a[], int L, int R)
{
    if (L >= R)
        return;
    int bound = a[L], low = L, high = R;
    while (low < high)
    {
        while (low < high && a[high] >= bound)
            high--;
        while (low < high && a[low] <= bound)
            low++;
        if (low < high)
            swap(a[low], a[high]);
    }
    swap(a[L], a[low]);
    quick_sort_2(a, L, low - 1);
    quick_sort_2(a, low + 1, R);
}

// 归并排序
void merge_sort(int a[], int L, int R)
{
    if (L >= R)
        return;
    int mid = (L + R) / 2;
    merge_sort(a, L, mid);
    merge_sort(a, mid + 1, R);
    // copy array
    static int *temp = new int[R - L + 1];
    for (int i = L; i <= R; i++)
        temp[i] = a[i];
    // merge
    for (int i = L, first = L, second = mid + 1; i <= R; i++)
    {
        if (second > R || first <= mid && temp[first] < temp[second])
            a[i] = temp[first++];
        else
            a[i] = temp[second++];
    }
}

// 堆排序
void heap_sort(int a[], int n)
{
    auto heap_down = [=](int x, int max_node)
    {
        while (x * 2 + 1 <= max_node) // 大顶堆
        {
            int max_child = x * 2 + 1; // 假设左孩子大
            if (max_child + 1 <= max_node && a[max_child] < a[max_child + 1])
                max_child = max_child + 1;
            if (a[x] < a[max_child])
            {
                swap(a[x], a[max_child]);
                x = max_child;
            }
            else
                break;
        }
    };
    for (int i = n / 2 - 1; i >= 0; i--) // 子树依次下沉
        heap_down(i, n - 1);
    for (int i = n - 1; i >= 0; i--)
    {
        swap(a[i], a[0]);
        heap_down(0, i - 1);
    }
}

// 希尔排序
void shell_sort(int a[], int n)
{
    for (int gap = n / 2; gap > 0; gap /= 2) // 步长
    {
        for (int start = 0; start < gap; start++) // 每组开头
        {
            for (int i = start; i < n; i += gap) //第start组进行插入排序
            {
                int temp = a[i], k = i;
                for (k = i - gap; k >= 0 && a[k] > temp; k -= gap)
                    a[k + gap] = a[k];
                a[k + gap] = temp;
            }
        }
    }
}

// 基数排序
void base_sort(int a[], int n)
{
    int max_base = 1; // 最大基数
    for (int i = 0; i < n; i++)
    {
        while (max_base < a[i])
            max_base *= 10;
    }
    vector<int> bucket[10];
    for (int base = max_base / 10; base > 0; base /= 10)
    {
        for (int i = 0; i < 10; i++)
            bucket[i].clear();
        for (int i = 0; i < n; i++)
            bucket[a[i] / base].push_back(a[i]);
        int count = 0;
        for (int i = 0; i < 10; i++)
        {
            for (auto &x : bucket[i])
                a[count++] = x;
        }
    }
}

void output(int a[], int n)
{
    for (int i = 0; i < n; i++)
        cout << a[i] << (i < n - 1 ? " " : "\n");
}

int main()
{
    int a[] = {14, 19, 11, 13, 16, 12, 10, 17, 15, 18};
    int n = sizeof(a) / sizeof(int);
    output(a, n);

    // bubble_sort(a, n);
    // selection_sort(a, n);
    // insert_sort(a, n);
    // quick_sort(a, 0, n - 1);
    // quick_sort_2(a, 0, n - 1);
    // merge_sort(a, 0, n - 1);
    // heap_sort(a, n);
    // base_sort(a, n);
    shell_sort(a, n);

    output(a, n);
}

单链表排序

#include <bits/stdc++.h>
using namespace std;

struct Node
{
    int val;
    Node *next;
};

void output(Node *head, bool has_head = true)
{
    if (has_head)
        head = head->next;
    for (Node *p = head; p; p = p->next)
        cout << p->val << (p->next ? ' ' : '\n');
}

// 冒泡排序 含头结点
void bubble_sort(Node *head)
{
    Node *sorted = NULL; // 保存已排序链表
    while (head->next)
    {
        Node *pre = head; // 比较pre后的两结点,完成冒泡
        for (; pre->next && pre->next->next; pre = pre->next)
        {
            Node *u = pre->next, *v = pre->next->next;
            if (u->val > v->val) // 交换结点
            {
                u->next = v->next;
                v->next = u;
                pre->next = v;
            }
        }
        // 从链表中删除尾结点(即pre->next)
        Node *tail = pre->next;
        pre->next = NULL;
        // 选中的结点插入到有序区(头插法)
        tail->next = sorted;
        sorted = tail;
    }
    head->next = sorted;
}

// 选择排序 含头结点
void selection_sort(Node *head)
{
    Node *sorted = NULL; // 保存已排序链表
    while (head->next)
    {
        // 找到最大的结点(记其前驱), 头插法插入到有序区
        Node *max_pre = head;
        for (Node *p = head->next; p && p->next; p = p->next)
        {
            if (max_pre->next->val < p->next->val)
                max_pre = p;
        }
        // 从链表中删除选中的结点
        Node *max_node = max_pre->next;
        max_pre->next = max_pre->next->next;
        // 选中的结点插入到有序区(头插法)
        max_node->next = sorted;
        sorted = max_node;
    }
    head->next = sorted;
}

// 插入排序 含头结点
void insert_sort(Node *head)
{
    Node *sorted = new Node();
    sorted->next = NULL;
    while (head->next)
    {
        // 删除当前结点(head->next)
        Node *cur = head->next;
        head->next = head->next->next;
        // 当前结点插入到有序区合适位置
        Node *pre = sorted;
        while (pre->next && pre->next->val < cur->val)
            pre = pre->next;
        cur->next = pre->next;
        pre->next = cur;
    }
    head->next = sorted->next;
    delete sorted;
}

// 快速排序 不含头结点
Node *quick_sort(Node *head)
{
    if (!head || !head->next)
        return head;
    Node *first = NULL, *second = NULL, *bound = head;
    for (Node *p = head; p;)
    {
        Node *next = p->next;
        if (p->val <= bound->val)
        {
            p->next = first;
            first = p;
        }
        else
        {
            p->next = second;
            second = p;
        }
        p = next;
    }
    // 递归
    first = quick_sort(first); // first一定至少包含一个元素bound
    second = quick_sort(second);
    // 拼接
    Node *first_tail = first;
    while (first_tail->next)
        first_tail = first_tail->next;
    first_tail->next = second;
    return first;
}

// 归并排序 不含头结点
Node *merge_sort(Node *head)
{
    if (!head || !head->next)
        return head;
    // 找到中间结点
    Node *mid = head, *fast = head->next;
    while (fast && fast->next)
    {
        mid = mid->next;
        fast = fast->next->next;
    }
    // 分治
    Node *first = head, *second = mid->next;
    mid->next = NULL; // 断开链表
    first = merge_sort(first);
    second = merge_sort(second);
    // 归并
    Node *sorted = new Node(), *tail = sorted; // 尾插法保存有序链表
    while (first || second)
    {
        if (first && second && first->val < second->val || !second)
        {
            Node *next = first->next;
            first->next = NULL;
            tail->next = first;
            first = next;
        }
        else
        {
            Node *next = second->next;
            second->next = NULL;
            tail->next = second;
            second = next;
        }
        tail = tail->next;
    }
    head = sorted->next;
    delete sorted;
    return head;
}

int main()
{
    int a[] = {14, 19, 11, 13, 16, 12, 10, 17, 15, 18};
    int n = sizeof(a) / sizeof(int);
    Node *head = new Node(), *tail = head;
    for (int i = 0; i < n; i++)
    {
        Node *p = new Node();
        p->val = a[i];
        p->next = NULL;
        tail->next = p;
        tail = p;
    }
    output(head);

    // bubble_sort(head);
    // selection_sort(head);
    // insert_sort(head);
    // head->next = quick_sort(head->next);
    head->next = merge_sort(head->next);

    output(head);
}