C语言:排序

发布于:2024-12-20 ⋅ 阅读:(10) ⋅ 点赞:(0)

1. 插入排序 (Insertion Sort)

插入排序是一种简单直观的排序算法,它的工作原理类似于整理扑克牌。它的基本思想是将数组分为已排序部分和未排序部分,每次从未排序部分取出一个元素,插入到已排序部分的合适位置。

步骤
  1. 从数组的第二个元素开始(假设第一个元素是已排序部分)。
  2. 将当前元素与已排序部分的元素从后向前比较,找到合适的位置插入。
  3. 重复上述过程,直到所有元素都被插入到合适的位置。
示例代码(C语言):
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;
    }
}
性能分析
  • 时间复杂度
    • 最好情况:O(n)(数组已经有序)。
    • 最坏情况:O(n^2)(数组逆序)。
    • 平均情况:O(n^2)
  • 空间复杂度O(1)(原地排序)。
  • 稳定性:稳定(不改变相同元素的相对顺序)。
适用场景
  • 适用于小规模数据或部分有序的数据。

2. 选择排序 (Selection Sort)

选择排序是一种简单直观的排序算法,它的工作原理是每次从未排序部分选择最小(或最大)的元素,放到已排序部分的末尾。

步骤
  1. 将数组分为已排序部分和未排序部分。
  2. 从未排序部分中找到最小元素,与未排序部分的第一个元素交换位置。
  3. 重复上述过程,直到所有元素都被排序。
示例代码(C语言):
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;
            }
        }
        // 交换最小元素到已排序部分的末尾
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}
性能分析
  • 时间复杂度
    • 最好、最坏、平均情况:O(n^2)
  • 空间复杂度O(1)(原地排序)。
  • 稳定性:不稳定(交换操作可能改变相同元素的相对顺序)。
适用场景
  • 适用于小规模数据,尤其是内存受限的场景。

3. 快速排序 (Quick Sort)

快速排序是一种高效的排序算法,基于“分治法”的思想。它通过选择一个“基准元素”(pivot)将数组分为两部分:小于基准的部分和大于基准的部分,然后递归地对两部分进行排序。

步骤
  1. 选择一个基准元素(通常是数组的第一个或最后一个元素)。
  2. 将数组分为两部分:一部分小于基准,另一部分大于基准。
  3. 递归地对两部分进行快速排序。
示例代码(C语言):
void quickSort(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); // 递归排序右半部分
    }
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high]; // 选择最后一个元素作为基准
    int i = low - 1;
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    // 将基准元素放到正确位置
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
    return i + 1;
}
性能分析
  • 时间复杂度
    • 最好情况:O(n log n)(每次分区均匀)。
    • 最坏情况:O(n^2)(每次分区极不均匀,例如数组已经有序)。
    • 平均情况:O(n log n)
  • 空间复杂度O(log n)(递归栈的深度)。
  • 稳定性:不稳定(分区操作可能改变相同元素的相对顺序)。
适用场景
  • 适用于大规模数据的排序,尤其是随机数据的排序。

4. 冒泡排序 (Bubble Sort)

冒泡排序是一种简单的排序算法,它的工作原理是通过重复地遍历数组,依次比较相邻元素并交换顺序错误的元素。每一轮遍历都会将未排序部分的最大元素“冒泡”到末尾。

步骤
  1. 从数组的第一个元素开始,依次比较相邻元素。
  2. 如果前一个元素大于后一个元素,交换它们。
  3. 重复上述过程,直到没有需要交换的元素。
示例代码(C语言):
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]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
性能分析
  • 时间复杂度
    • 最好情况:O(n)(数组已经有序)。
    • 最坏情况:O(n^2)
    • 平均情况:O(n^2)
  • 空间复杂度O(1)(原地排序)。
  • 稳定性:稳定(不改变相同元素的相对顺序)。
适用场景
  • 适用于小规模数据,尤其是教学和理解排序算法的场景。

对比总结

算法 时间复杂度 空间复杂度 稳定性 特点
插入排序 O(n^2) O(1) 稳定 适合小规模数据或部分有序数据
选择排序 O(n^2) O(1) 不稳定 简单直观,适用于小规模数据
快速排序 O(n log n) O(log n) 不稳定 高效,适用于大规模数据
冒泡排序 O(n^2) O(1) 稳定 简单易于理解