跳至主要內容

排序方法

酷丁大约 4 分钟

冒泡排序

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行,直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

算法步骤:

  1. 比较相邻元素: 从第一个元素开始,比较相邻的元素,如果第一个比第二个大(升序排序)或者小(降序排序),就交换它们的位置。

  2. 重复步骤 1: 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大(升序)或最小(降序)的数。

  3. 缩小范围: 忽略已经排序好的最后一个元素,重复步骤 1 和 2,直到没有任何一对数字需要比较。

示例 (升序排序):

假设要排序的数组是 [5, 1, 4, 2, 8]

第一轮:

  • [5, 1] -> [1, 5]
  • [5, 4] -> [4, 5]
  • [5, 2] -> [2, 5]
  • [5, 8] -> [5, 8]
    结果: [1, 4, 2, 5, 8]

第二轮:

  • [1, 4] -> [1, 4]
  • [4, 2] -> [2, 4]
  • [4, 5] -> [4, 5]
    结果: [1, 2, 4, 5, 8]

第三轮:

  • [1, 2] -> [1, 2]
  • [2, 4] -> [2, 4]
    结果: [1, 2, 4, 5, 8]

第四轮:

  • [1, 2] -> [1, 2]
    结果: [1, 2, 4, 5, 8]

C代码实现 (升序):

#include <stdio.h>

void bubble_sort(int arr[], int n) {
  for (int i = 0; i < n - 1; i++) {       // 外层循环控制排序轮数
    for (int j = 0; j < n - 1 - i; j++) {   // 内层循环控制每轮比较次数
      if (arr[j] > arr[j + 1]) {           // 如果当前元素大于下一个元素
        int temp = arr[j];                 // 交换两个元素
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
}

int main() {
  int arr[] = {5, 1, 4, 2, 8};
  int n = sizeof(arr) / sizeof(arr[0]);
  bubble_sort(arr, n);
  for (int i = 0; i < n; i++) {
    printf("%d ", arr[i]);
  }
  printf("\n");
  return 0;
}

关键点:

  • 外层循环控制轮数,总共需要 n-1 轮。
  • 内层循环控制每轮的比较次数,随着轮数增加,比较次数减少。
  • n - 1 - i 避免了对已经排好序的元素进行不必要的比较。

改进:

可以添加一个标志位,如果在一轮比较中没有进行任何交换,说明数组已经有序,可以提前结束排序。

希望这个解释能够帮助你理解冒泡排序。

选择排序

(Selection Sort)是一种简单直观的排序算法。它的工作原理是每次从未排序的部分中找到最小(或最大)的元素,然后将其与未排序部分的第一个元素交换位置。重复这个过程,直到整个数组排序完成。

算法步骤:

  1. 找到最小元素: 从未排序部分的第一个元素开始,遍历剩余未排序的元素,找到其中最小的元素。

  2. 交换位置: 将找到的最小元素与未排序部分的第一个元素交换位置。

  3. 缩小未排序部分: 将未排序部分的起始位置向后移动一位。

  4. 重复步骤 1-3: 重复上述步骤,直到整个数组排序完成。

示例 (升序排序):

假设要排序的数组是 [64, 25, 12, 22, 11]

第一轮:

  • 未排序部分: [64, 25, 12, 22, 11]
  • 最小元素: 11
  • 交换: [11, 25, 12, 22, 64]

第二轮:

  • 未排序部分: [25, 12, 22, 64]
  • 最小元素: 12
  • 交换: [11, 12, 25, 22, 64]

第三轮:

  • 未排序部分: [25, 22, 64]
  • 最小元素: 22
  • 交换: [11, 12, 22, 25, 64]

第四轮:

  • 未排序部分: [25, 64]
  • 最小元素: 25
  • 交换: [11, 12, 22, 25, 64]

C 代码实现 (升序):

#include <stdio.h>

void selection_sort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        int min_idx = i; // 假设当前位置的元素是最小的
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[min_idx]) {
                min_idx = j; // 更新最小元素的索引
            }
        }
        // 交换最小元素和当前位置的元素
        if (min_idx != i) {
            int temp = arr[i];
            arr[i] = arr[min_idx];
            arr[min_idx] = temp;
        }
    }
}


int main() {
    int arr[] = {64, 25, 12, 22, 11};
    int n = sizeof(arr) / sizeof(arr[0]);
    selection_sort(arr, n);

    printf("排序后的数组: \n");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

关键点:

  • 外层循环控制已排序部分的末尾位置。
  • 内层循环在未排序部分中查找最小元素。
  • 每次交换都将一个元素放入其最终的排序位置。

时间复杂度: O(n^2) - 无论数组是否有序,都需要进行 n*(n-1)/2 次比较。

空间复杂度: O(1) - 选择排序是原地排序算法,只需要常数个额外空间。

希望这个解释能够帮助你理解选择排序。