排序

308 阅读4分钟

常见排序算法的时间复杂度和稳定性:

  • 冒泡排序(Bubble Sort)

  • 时间复杂度:最好O(n),平均O(n^2),最坏O(n^2)

  • 稳定性:稳定

  • 选择排序(Selection Sort)

  • 时间复杂度:

    • 平均、最好、最坏情况:O(n^2)
  • 空间复杂度:O(1)(原地排序)

  • 最坏情况:数组完全逆序

  • 稳定性:不稳定

  • 插入排序(Insertion Sort)

  • 时间复杂度:

    • 平均和最坏情况:O(n^2)
    • 最好情况:O(n)(当数组已经有序时)
  • 空间复杂度:O(1)(原地排序)

  • 最坏情况:数组完全逆序

  • 稳定性:稳定

  • 希尔排序(Shell Sort)

  • 时间复杂度:

    • 平均情况:O(nlogn)到O(n^2),取决于增量序列的选择
    • 最好和最坏情况:依赖于增量序列,最坏情况下为O(n^2)
  • 空间复杂度:O(1)(原地排序)

  • 最坏情况:增量序列选择不当导致算法性能退化

  • 稳定性:不稳定

  • 归并排序(Merge Sort)

  • 时间复杂度:

    • 平均、最好、最坏情况:O(nlogn)
  • 空间复杂度:O(n)(需要额外的存储空间来合并数组)

  • 最坏情况:数组完全逆序

  • 稳定性:稳定

  • 快速排序(Quick Sort)

  • 时间复杂度:

    • 平均情况:O(nlogn)
    • 最好情况:O(nlogn)(分区总是平衡的)
    • 最坏情况:O(n^2)(分区总是不平衡的,如数组已经有序)
  • 空间复杂度:O(logn)(平均情况,递归栈的深度),最坏情况下为O(n)(深度为n的递归)

  • 最坏情况:数组已经有序或完全逆序

  • 稳定性:不稳定

  • 堆排序(Heap Sort)

  • 时间复杂度:

    • 平均、最好、最坏情况:O(nlogn)
  • 空间复杂度:O(1)(原地排序,不考虑递归调用栈)

  • 最坏情况:数组完全逆序

  • 稳定性:不稳定

  • 计数排序(Counting Sort)

  • 时间复杂度:O(n+k),其中k是输入数据的范围

  • 空间复杂度:O(k)

  • 最坏情况:所有元素都落在k的范围内

  • 稳定性:稳定

  • 桶排序(Bucket Sort)

  • 时间复杂度:平均情况O(n+k),最坏情况O(n^2)(如果所有元素都分配到一个桶中)

  • 空间复杂度:O(n+k)

  • 最坏情况:所有元素都分配到同一个桶中

  • 稳定性:如果每个桶内部使用稳定的排序算法,则桶排序也是稳定的

  • 基数排序(Radix Sort)

  • 时间复杂度:O(nk),其中n是排序元素的数量,k是数字的位数

  • 空间复杂度:O(n+k)

  • 最坏情况:数字位数很多,但每个桶内的元素数量大致相同

  • 稳定性:稳定

需要注意的是,排序算法的稳定性和时间复杂度可能受到具体实现方式和数据特性的影响。上述信息是基于算法的基本特性和常见实现方式给出的。在实际应用中,可能需要根据具体情况进行调整和优化。

另外,对于非比较类排序算法(如计数排序、桶排序和基数排序),它们的时间复杂度通常与数据的范围或位数有关,而不是仅仅与数据量n有关。这些算法在处理具有特定属性的数据时可能非常高效,但在其他情况下可能并不适用。

冒泡排序(Bubble Sort)

void bubbleSort(int arr[], int n)
{  
    for (int i = 0; i < n - 1; i++)
    {  
        for (int j = 0; j < n - i - 1; j++)
        {  
            if (arr[j] > arr[j + 1])
            {  
                std::swap(arr[j], arr[j + 1]);  
            }  
        }  
    }  
}  

选择排序(Selection Sort)

void selectionSort(int arr[], int n) 
{  
    for (int i = 0; i < n - 1; i++) 
    {  
        int minIndex = i;  
        for (int j = i + 1; j < n; j++) 
        {  
            if (arr[j] < arr[minIndex]) 
            {  
                minIndex = j;  
            }  
        }  
        std::swap(arr[i], arr[minIndex]);  
    }  
}  

插入排序(Insertion Sort)

void insertionSort(int arr[], int n)
{  
    for (int i = 1; i < n; i++)
    {  
        int key = arr[i];  
        int j = i - 1;  
        while (j >= 0 && arr[j] > key)
        {  
            arr[j + 1] = arr[j];  
            j--;  
        }  
        arr[j + 1] = key;  
    }  
}  

链表插入排序

ListNode* findAndInsert(ListNode* sortList, ListNode* node)
{
    if(!sortList || sortList->val > node->val)
    {
        node->next = sortList;
        sortList = node;
    }
    else
    {
        ListNode *sortHead = sortList;
        while(sortHead->next && sortHead->next->val < node->val)
        {
            sortHead = sortHead->next;
        }
        node->next = sortHead->next;
        sortHead->next = node;
    }
    return sortList;
}

ListNode* insertSort(ListNode* head)
{
    ListNode* sortList = nullptr;
    ListNode* curNode = head;
    ListNode* nextNode = nullptr;
    while(curNode)
    {
        nextNode = curNode->next;
        curNode->next = nullptr;
        sortList = findAndInsert(sortList, curNode);
        curNode = nextNode;
    }
    return sortList;
}

希尔排序(Shell Sort)

void shellSort(int arr[], int n)
{  
    for (int gap = n / 2; gap > 0; gap /= 2)
    {  
        for (int i = gap; i < n; i++)
        {  
            int temp = arr[i];  
            int j = i;  
            while (j >= gap && arr[j - gap] > temp)
            {  
                arr[j] = arr[j - gap];  
                j -= gap;  
            }  
            arr[j] = temp;  
        }  
    }  
}  

归并排序(Merge Sort)

void merge(int arr[], int l, int m, int r)
{  
    int n1 = m - l + 1;  
    int n2 = r - m;  
    int L[n1], R[n2];  
    for (int i = 0; i < n1; i++) L[i] = arr[l + i];  
    for (int j = 0; j < n2; j++) R[j] = arr[m + 1 + j];  
    int i = 0, j = 0, k = l;  
    while (i < n1 && j < n2)
    {  
        if (L[i] <= R[j])
        {  
            arr[k] = L[i];  
            i++;  
        }
        else
        {  
            arr[k] = R[j];  
            j++;  
        }  
        k++;  
    }  
    while (i < n1)
    {  
        arr[k] = L[i];  
        i++;  
        k++;  
    }  
    while (j < n2)
    {  
        arr[k] = R[j];  
        j++;  
        k++;  
    }  
}  
  
void mergeSort(int arr[], int l, int r)
{  
    if (l < r)
    {  
        int m = l + (r - l) / 2;  
        mergeSort(arr, l, m);  
        mergeSort(arr, m + 1, r);  
        merge(arr, l, m, r);  
    }  
}  

给定链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

// 合并两个有序链表
ListNode* merge(ListNode* headA, ListNode* headB) {
   if(!headA)
   {
        return headB;
   }
   if(!headB)
   {
        return headA;
   }
   ListNode dummy(0);
   ListNode *p = &dummy;
   ListNode *p1 = headA, *p2 = headB;
   while(p1 && p2)
   {
        if(p1->val > p2->val)
        {
            p->next = p2;
            p2 = p2->next;
        }
        else
        {
            p->next = p1;
            p1 = p1->next;
        }
        p = p->next;
   }
   p->next = p1 ? p1 : p2;
   return dummy.next;
}

// 使用快慢指针找到链表的中点
ListNode* findMiddle(ListNode* head) {
   ListNode *slow = head, *fast = head->next;
   while(fast && fast->next)
   {
        fast = fast->next->next;
        slow = slow->next;
   }
   return slow;
}

// 对链表进行归并排序
ListNode* mergeSort(ListNode* head) {
    if(!head || !head->next)
    {
        return head;
    }
    ListNode *midNode = findMiddle(head);
    ListNode *nextNode = midNode->next;
    midNode->next = nullptr;

    ListNode *leftNode = mergeSort(head);
    ListNode *rightNode = mergeSort(nextNode);
    return merge(leftNode, rightNode);
}

堆排序

#include <iostream>  
#include <vector>  
  
void heapify(std::vector<int>& arr, int n, int i)
{  
    int largest = i;  
    int left = 2 * i + 1;  
    int right = 2 * i + 2;  
  
    if (left < n && arr[left] > arr[largest])
    {  
        largest = left;  
    }  
  
    if (right < n && arr[right] > arr[largest])
    {  
        largest = right;  
    }  
  
    if (largest != i)
    {  
        std::swap(arr[i], arr[largest]);  
        heapify(arr, n, largest);  
    }  
}  
  
void heapSort(std::vector<int>& arr)
{  
    int n = arr.size();  
  
    // Build max heap  
    for (int i = n / 2 - 1; i >= 0; i--)
    {  
        heapify(arr, n, i);  
    }  
  
    // Extract elements from heap  
    for (int i = n - 1; i >= 0; i--)
    {  
        std::swap(arr[0], arr[i]);  
        heapify(arr, i, 0);  
    }  
}  
  

计数排序(Counting Sort)

#include <iostream>  
#include <vector>  
#include <algorithm>  
  
void countingSort(std::vector<int>& arr)
{  
    int max_val = *std::max_element(arr.begin(), arr.end());  
    std::vector<int> count(max_val + 1, 0);  
    std::vector<int> output(arr.size());  
  
    // Count the occurrence of each element  
    for (int num : arr)
    {  
        count[num]++;  
    }  
  
    // Calculate the running total  
    for (int i = 1; i <= max_val; i++)
    {  
        count[i] += count[i - 1];  
    }  
  
    // Place the elements in the output array  
    for (int i = arr.size() - 1; i >= 0; i--)
    {  
        output[count[arr[i]] - 1] = arr[i];  
        count[arr[i]]--;  
    }  
  
    // Copy the sorted elements back to the original array  
    for (int i = 0; i < arr.size(); i++)
    {  
        arr[i] = output[i];  
    }  
}  

桶排序(Bucket Sort)

#include <iostream>  
#include <vector>  
#include <algorithm>  
  
void bucketSort(std::vector<float>& arr)
{  
    int n = arr.size();  
    std::vector<std::vector<float>> buckets(n);  
  
    // Put elements into buckets  
    for (float num : arr)
    {  
        int bucketIndex = static_cast<int>(n * num);  
        buckets[bucketIndex].push_back(num);  
    }  
  
    // Sort and concatenate buckets  
    int index = 0;  
    for (int i = 0; i < n; i++)
    {  
        std::sort(buckets[i].begin(), buckets[i].end());  
        for (float num : buckets[i]) {  
            arr[index++] = num;  
        }  
    }  
}  

基数排序(Radix Sort)

#include <iostream>  
#include <vector>  
#include <queue>  
  
// 获取数字的第d位数字  
int getDigit(int num, int d)
{  
    while (--d > 0 && num > 0)
    {  
        num /= 10;  
    }  
    return num % 10;  
}  
  
// 基数排序函数,按照指数d进行排序  
void radixSortUtil(std::vector<int>& arr, int d)
{  
    // 创建10个队列,分别对应0-9的数字  
    std::vector<std::queue<int>> buckets(10);  
  
    // 将元素分配到对应的队列中  
    for (int num : arr)
    {  
        int digit = getDigit(num, d);  
        buckets[digit].push(num);  
    }  
  
    // 从队列中取出元素,重新放回数组中  
    int index = 0;  
    for (int i = 0; i < 10; ++i)
    {  
        while (!buckets[i].empty())
        {  
            arr[index++] = buckets[i].front();  
            buckets[i].pop();  
        }  
    }  
}  
  
// 基数排序主函数  
void radixSort(std::vector<int>& arr)
{  
    // 获取数组中最大的数  
    int maxNum = *std::max_element(arr.begin(), arr.end());  
  
    // 对每一位进行排序,从最低位开始  
    int d = 1;  
    while (maxNum / d > 0)
    {  
        radixSortUtil(arr, d);  
        d *= 10;  
    }  
}  

快速排序(quickSort)

#include <iostream>  
#include <vector>  
  
// 交换两个元素的值  
void swap(int& a, int& b)
{  
    a = a ^ b;  
    b = a ^ b;  
    a = a ^ b;  
}  
  
// 快速排序的分区函数  
int partition(std::vector<int>& arr, int low, int high)
{  
    int pivot = arr[high]; // 选择最后一个元素作为基准  
    int i = (low - 1); // 小于基准的元素的索引  
  
    for (int j = low; j <= high - 1; j++)
    {  
        // 如果当前元素小于或等于基准  
        if (arr[j] <= pivot)
        {  
            i++;  
            swap(arr[i], arr[j]);  
        }  
    }  
    swap(arr[i + 1], arr[high]); // 将基准元素放到正确的位置上  
    return (i + 1); // 返回基准元素的索引  
}  
  
// 快速排序的主要函数  
void quickSort(std::vector<int>& arr, int low, int high)
{  
    if (low < high)
    {  
        int pi = partition(arr, low, high); // 对数组进行分区  
  
        // 分别对基准元素的左侧和右侧子数组进行递归排序  
        quickSort(arr, low, pi - 1);  
        quickSort(arr, pi + 1, high);  
    }  
}  



#include <iostream>  
#include <vector>  
  
using namespace std;  
  
// 交换两个元素  
void swap(int& a, int& b)
{  
    int temp = a;  
    a = b;  
    b = temp;  
}  
  
// 分区函数  
int partition(vector<int>& arr, int low, int high)
{  
    int pivot = arr[high]; // 选择最后一个元素作为基准  
    int i = (low - 1); // 小于基准的元素的最后一个位置  
  
    for (int j = low; j <= high - 1; j++)
    {  
        // 如果当前元素小于或等于基准  
        if (arr[j] <= pivot)
        {  
            i++; // 增大小于基准的元素的最后一个位置  
            swap(arr[i], arr[j]);  
        }  
    }  
    swap(arr[i + 1], arr[high]);  
    return (i + 1);  
}  
  
// 快速排序函数  
void quickSort(vector<int>& arr, int low, int high)
{  
    if (low < high)
    {  
        /* pi 是分区后基准的正确位置 */  
        int pi = partition(arr, low, high);  
  
        // 分别对基准的左右两部分进行快速排序  
        quickSort(arr, low, pi - 1);  
        quickSort(arr, pi + 1, high);  
    }  
}  
  
// 打印数组的函数  
void printArray(const vector<int>& arr)
{  
    for (int i = 0; i < arr.size(); i++)  
        cout << arr[i] << " ";  
    cout << endl;  
}  
  
// 主函数,用于测试快速排序  
int main()
{  
    vector<int> arr = {10, 7, 8, 9, 1, 5};  
    cout << "Original array: \n";  
    printArray(arr);  
  
    quickSort(arr, 0, arr.size() - 1);  
  
    cout << "Sorted array: \n";  
    printArray(arr);  
    return 0;  
}