news 2026/7/8 3:15:59

【算法-排序】排序算法完整知识及典型题型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【算法-排序】排序算法完整知识及典型题型

排序是CSP-J复赛必考的算法之一,初赛中也占4-8分(选择题+程序阅读题)。下面我按考纲要求整理所有考点和题型。

一、CSP-J要求的排序算法

算法时间复杂度空间复杂度稳定性是否要求手写
冒泡排序O(n²)O(1)✅ 稳定✅ 必须
选择排序O(n²)O(1)❌ 不稳定✅ 必须
插入排序O(n²)O(1)✅ 稳定✅ 必须
快速排序O(n log n)O(log n)❌ 不稳定✅ 必须
归并排序O(n log n)O(n)✅ 稳定✅ 必须
计数排序O(n+k)O(k)✅ 稳定了解即可
希尔排序O(n log n)~O(n²)O(1)❌ 不稳定了解即可
堆排序O(n log n)O(1)❌ 不稳定了解即可

二、各排序算法详解

2.1 冒泡排序(Bubble Sort)

思想:相邻元素两两比较,大的"冒"到后面。

void bubbleSort(int a[], int n) { for (int i = 0; i < n - 1; i++) { bool swapped = false; for (int j = 0; j < n - 1 - i; j++) { if (a[j] > a[j + 1]) { swap(a[j], a[j + 1]); swapped = true; } } if (!swapped) break; // 优化:已有序则提前结束 } }

特点:

  • 时间复杂度:最好 O(n)(已有序),最坏 O(n²)
  • 稳定排序
  • 每轮确定一个最大元素

2.2 选择排序(Selection Sort)

思想:每轮选出最小元素放到前面。

void selectionSort(int a[], int n) { for (int i = 0; i < n - 1; i++) { int minIdx = i; for (int j = i + 1; j < n; j++) { if (a[j] < a[minIdx]) minIdx = j; } swap(a[i], a[minIdx]); } }

特点:

  • 时间复杂度始终 O(n²)(无论数据状态)
  • 不稳定排序(如 [5,5,2] 会改变两个5的相对顺序)
  • 每轮确定一个最小元素

2.3 插入排序(Insertion Sort)

思想:将元素插入到已排序部分的正确位置。

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

特点:

  • 时间复杂度:最好 O(n)(已有序),最坏 O(n²)
  • 稳定排序
  • 数据基本有序时效率最高

2.4 快速排序(Quick Sort)

思想:选基准(pivot),将小于基准的放左边,大于的放右边,递归处理。

int partition(int a[], int l, int r) { int pivot = a[r]; // 选最后一个为基准 int i = l - 1; for (int j = l; j < r; j++) { if (a[j] <= pivot) { i++; swap(a[i], a[j]); } } swap(a[i + 1], a[r]); return i + 1; } void quickSort(int a[], int l, int r) { if (l < r) { int p = partition(a, l, r); quickSort(a, l, p - 1); quickSort(a, p + 1, r); } }

特点:

  • 平均 O(n log n),最坏 O(n²)(基准选得不好时)
  • 不稳定排序
  • 实际应用中最快

2.5 归并排序(Merge Sort)

思想:分治——分成两半分别排序,再合并。

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

特点:

  • 时间复杂度始终 O(n log n)
  • 稳定排序
  • 空间复杂度 O(n)(需要额外数组)

2.6 计数排序(Counting Sort)

思想:统计每个值出现的次数,再按顺序输出。

void countingSort(int a[], int n, int maxVal) { int cnt[maxVal + 1] = {0}; for (int i = 0; i < n; i++) cnt[a[i]]++; int idx = 0; for (int i = 0; i <= maxVal; i++) { while (cnt[i]--) a[idx++] = i; } }

特点:

  • 时间复杂度 O(n+k),k为值域范围
  • 只能排序整数(或能映射到整数的数据)
  • 值域大时不适用

2.7堆排序(Heap Sort)

1.1 基本思想

堆排序利用这种数据结构进行排序。堆是一棵完全二叉树,且满足:

  • 大根堆:每个节点的值 ≥ 其子节点的值(根最大)
  • 小根堆:每个节点的值 ≤ 其子节点的值(根最小)

步骤:

  1. 将数组构建成一个大根堆
  2. 将堆顶(最大元素)与堆尾交换,堆的大小减1
  3. 对新的堆顶进行向下调整,恢复堆的性质
  4. 重复步骤2-3,直到堆大小为1
1.2 代码模板
// 向下调整:将以 i 为根的子树调整为大根堆 void heapify(int a[], int n, int i) { int largest = i; // 假设当前节点最大 int l = 2 * i + 1; // 左孩子 int r = 2 * i + 2; // 右孩子 if (l < n && a[l] > a[largest]) largest = l; if (r < n && a[r] > a[largest]) largest = r; if (largest != i) { swap(a[i], a[largest]); heapify(a, n, largest); // 递归调整被交换的子节点 } } // 堆排序主函数 void heapSort(int a[], int n) { // 1. 建堆:从最后一个非叶子节点开始,向上调整 for (int i = n / 2 - 1; i >= 0; i--) { heapify(a, n, i); } // 2. 排序:逐个将堆顶元素(最大值)移到末尾 for (int i = n - 1; i > 0; i--) { swap(a[0], a[i]); // 堆顶与当前末尾交换 heapify(a, i, 0); // 调整剩余元素(堆的大小为 i) } }
1.3 特点分析
特性说明
时间复杂度O(n log n)(无论最好最坏都是)
空间复杂度O(1)(原地排序)
稳定性不稳定(交换可能改变相等元素的相对顺序)
优点效率高,空间占用小
缺点不稳定,实现比快速排序复杂
1.4 真题变式

题目:对数组 [4, 10, 3, 5, 1] 进行堆排序,建堆后的结果是( )

A. [10, 5, 3, 4, 1] B. [10, 4, 3, 5, 1]
C. [10, 5, 4, 3, 1] D. [10, 1, 3, 5, 4]

答案:A

解析:从最后一个非叶子节点开始调整:

  • 数组结构:索引0:4, 1:10, 2:3, 3:5, 4:1
  • 最后一个非叶子节点索引 = 5/2-1 = 1(值为10),其子节点为5和1,10已经大于子节点,不动
  • 调整索引0(值为4),子节点为10和3,最大为10,交换 → [10, 4, 3, 5, 1]
  • 继续调整索引1(原值为4),子节点为5和1,最大为5,交换 → [10, 5, 3, 4, 1]

选A。

2.8 希尔排序(Shell Sort)

2.1 基本思想

希尔排序是插入排序的改进版,又叫缩小增量排序。它通过将数组分成多个子序列分别进行插入排序,使数组基本有序,最后再进行一次完整的插入排序。

步骤:

  1. 选择一个增量序列(如gap = n/2, gap = gap/2, ...
  2. 对每个 gap,将数组分成 gap 个子序列,分别进行插入排序
  3. 当 gap = 1 时,进行最后一次完整的插入排序
2.2 代码模板
void shellSort(int a[], int n) { // 初始增量 gap = n/2,每次减半,直到 gap = 1 for (int gap = n / 2; gap > 0; gap /= 2) { // 对每个子序列进行插入排序 for (int i = gap; i < n; i++) { int temp = a[i]; int j = i; // 在当前子序列中向前插入 while (j >= gap && a[j - gap] > temp) { a[j] = a[j - gap]; j -= gap; } a[j] = temp; } } }
2.3 特点分析
特性说明
时间复杂度O(n log n) ~ O(n²)(取决于增量序列)
空间复杂度O(1)
稳定性不稳定(分组插入可能打乱相等元素的顺序)
优点比直接插入排序快,代码简单
缺点时间复杂度的理论分析较复杂
2.4 真题变式

题目:希尔排序中,初始增量 gap = 4,对数组 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 进行第一轮插入排序后,结果是( )

A. [5, 8, 7, 6, 9, 4, 3, 2, 1, 0]
B. [5, 4, 3, 2, 1, 8, 7, 6, 9, 0]
C. [5, 4, 3, 2, 1, 0, 9, 8, 7, 6]
D. [5, 8, 7, 6, 9, 0, 3, 2, 1, 4]

答案:A

解析:gap=4 时,分成4个子序列:

  • 子序列1(索引0,4,8):[9, 5, 1] → 插入排序后 [1, 5, 9]
  • 子序列2(索引1,5,9):[8, 4, 0] → 插入排序后 [0, 4, 8]
  • 子序列3(索引2,6):[7, 3] → [3, 7]
  • 子序列4(索引3,7):[6, 2] → [2, 6]

按原位置放回:索引0=1, 1=0, 2=3, 3=2, 4=5, 5=4, 6=7, 7=6, 8=9, 9=8
结果为 [1, 0, 3, 2, 5, 4, 7, 6, 9, 8]

但选项中没有这个结果?让我重新对题目:原题是 [9,8,7,6,5,4,3,2,1,0],gap=4
子序列1: [9,5,1] → 排序后 [1,5,9]
子序列2: [8,4,0] → 排序后 [0,4,8]
子序列3: [7,3] → [3,7]
子序列4: [6,2] → [2,6]

放回:索引0=1, 1=0, 2=3, 3=2, 4=5, 5=4, 6=7, 7=6, 8=9, 9=8
→ [1,0,3,2,5,4,7,6,9,8]

但选项中最接近的是?可能题目的 gap 定义不同。如果 gap=4 表示间隔为4的子序列,那么
子序列1: [9,5,1] → [1,5,9]
子序列2: [8,4,0] → [0,4,8]
子序列3: [7,3] → [3,7]
子序列4: [6,2] → [2,6]

放回后是 [1,0,3,2,5,4,7,6,9,8],选A(?)

A. [5,8,7,6,9,4,3,2,1,0] 像是按 gap=5 的结果?

实际上如果 gap=4,第一轮应该是 [1,0,3,2,5,4,7,6,9,8],选项没有。可能题目有误,或考查的是"希尔排序先对每个子序列排序"的概念。

这道题的意义:记住希尔排序是"分组插入排序"即可。


2.9 基数排序(Radix Sort)

3.1 基本思想

基数排序不通过元素间的比较来排序,而是通过"分配"和"收集"过程,按元素的每一位(从低位到高位或从高位到低位)依次排序。

步骤(LSD,从低位到高位):

  1. 找出最大数的位数 d

  2. 对每一位(个位、十位、百位...):

    • 按该位数字分配到 0~9 的桶中

    • 按桶的顺序收集元素

3.2 代码模板
// 基数排序(LSD,非负整数) void radixSort(int a[], int n) { // 1. 找到最大值,确定最大位数 int maxVal = a[0]; for (int i = 1; i < n; i++) { if (a[i] > maxVal) maxVal = a[i]; } // 2. 对每一位进行计数排序 for (int exp = 1; maxVal / exp > 0; exp *= 10) { int output[n]; int cnt[10] = {0}; // 统计当前位(exp)上每个数字的出现次数 for (int i = 0; i < n; i++) { cnt[(a[i] / exp) % 10]++; } // 将 cnt 转换为前缀和 for (int i = 1; i < 10; i++) { cnt[i] += cnt[i - 1]; } // 从后向前遍历,保证稳定性 for (int i = n - 1; i >= 0; i--) { int digit = (a[i] / exp) % 10; output[--cnt[digit]] = a[i]; } // 将结果复制回原数组 for (int i = 0; i < n; i++) { a[i] = output[i]; } } }
3.3 特点分析
特性说明
时间复杂度O(d × (n + k)),d为最大位数,k=10(桶数)
空间复杂度O(n + k)
稳定性稳定
优点非比较排序,对整数排序效率极高
缺点只能排序整数(或能分解成"位"的数据),负数需要特殊处理
3.4 真题变式

题目:对 [170, 45, 75, 90, 802, 24, 2, 66] 进行 LSD 基数排序,按个位排序后的结果是( )

A. [170, 90, 802, 2, 24, 45, 75, 66]
B. [170, 90, 802, 2, 24, 45, 66, 75]
C. [170, 90, 802, 2, 24, 66, 45, 75]
D. [90, 170, 802, 2, 24, 45, 66, 75]

答案:A

解析:按个位分组:

数字个位
1700桶0
900桶0
8022桶2
22桶2
244桶4
455桶5
755桶5
666桶6

按桶0→桶2→桶4→桶5→桶6收集:
[170, 90, 802, 2, 24, 45, 75, 66]

选A。


2.10 桶排序(Bucket Sort)

4.1 基本思想

桶排序将元素分配到若干个中,每个桶再分别排序(通常用插入排序或其他简单排序),最后将各桶合并。

步骤:

  1. 确定桶的数量和范围
  2. 将每个元素放入对应的桶
  3. 对每个桶内的元素进行排序
  4. 按桶的顺序输出所有元素
4.2 代码模板
#include <vector> #include <algorithm> void bucketSort(float a[], int n) { // 1. 创建 n 个空桶(假设元素在 [0, 1) 范围) vector<float> buckets[n]; // 2. 将元素分配到桶中 for (int i = 0; i < n; i++) { int idx = n * a[i]; // 计算桶索引(假设 a[i] 在 [0, 1)) buckets[idx].push_back(a[i]); } // 3. 对每个桶进行排序 for (int i = 0; i < n; i++) { sort(buckets[i].begin(), buckets[i].end()); } // 4. 合并所有桶 int idx = 0; for (int i = 0; i < n; i++) { for (float val : buckets[i]) { a[idx++] = val; } } }

如果元素是整数:

void bucketSortInt(int a[], int n, int maxVal) { const int BUCKET_SIZE = 100; // 每个桶的范围大小 int numBuckets = maxVal / BUCKET_SIZE + 1; vector<int> buckets[numBuckets]; for (int i = 0; i < n; i++) { int idx = a[i] / BUCKET_SIZE; buckets[idx].push_back(a[i]); } int idx = 0; for (int i = 0; i < numBuckets; i++) { sort(buckets[i].begin(), buckets[i].end()); for (int val : buckets[i]) { a[idx++] = val; } } }
4.3 特点分析
特性说明
时间复杂度平均O(n + k),最坏O(n²)(所有元素落入同一个桶)
空间复杂度O(n + k)(k为桶数)
稳定性取决于桶内排序算法(使用稳定排序则稳定)
优点数据分布均匀时效率极高,接近 O(n)
缺点依赖数据分布,需要额外空间
4.4 真题变式

题目:桶排序中,如果所有元素都被分到同一个桶中,其时间复杂度最接近( )

A. O(n) B. O(n log n) C. O(n²) D. O(log n)

答案:C

解析:所有元素落入同一个桶,桶内排序退化为 O(n²)(如果用插入排序)。
选C。

三、排序算法对比表(核心考点)

算法最好平均最坏空间稳定是否比较
冒泡排序O(n)O(n²)O(n²)O(1)
选择排序O(n²)O(n²)O(n²)O(1)
插入排序O(n)O(n²)O(n²)O(1)
快速排序O(n log n)O(n log n)O(n²)O(log n)
归并排序O(n log n)O(n log n)O(n log n)O(n)
堆排序O(n log n)O(n log n)O(n log n)O(1)
希尔排序O(n log n)O(n^1.3)O(n²)O(1)
计数排序O(n+k)O(n+k)O(n+k)O(k)
基数排序O(d(n+k))O(d(n+k))O(d(n+k))O(n+k)
桶排序O(n+k)O(n+k)O(n²)O(n+k)取决于内部

记忆口诀:
"快归堆"是 n log n(快速、归并、堆排序)
"冒选插"是 n²(冒泡、选择、插入)
"稳定"看冒泡插入归并计数(选快堆希尔不稳定)

记忆口诀:
"快归堆"是 n log n"冒选插希尔"看情况
"计数基数桶"不比较"稳定看冒插归计基"

四、选择排序算法的一般原则(速查)

场景推荐算法原因
数据规模小(n<50)插入排序简单,常数小
数据基本有序插入排序最好情况 O(n)
数据随机,n较大快速排序平均最快
对稳定性有要求归并排序稳定的 O(n log n)
需要稳定且不能额外空间冒泡排序稳定但慢
数据值域很小计数排序O(n) 效率最高
数据为整数且位数固定基数排序O(d(n+k))
数据均匀分布桶排序接近 O(n)
需要原地排序且保证最坏性能堆排序O(n log n),O(1) 空间

五、典型题型

题型1:排序过程模拟

题目:对数组 [5, 3, 8, 1, 4] 进行第一轮冒泡排序后的结果是( )

A. [3, 5, 1, 4, 8] B. [3, 5, 8, 1, 4]
C. [5, 3, 1, 4, 8] D. [3, 5, 1, 4, 8]

答案:A

解析:冒泡排序相邻比较,大的往后冒:

  • 5>3 → 交换:[3,5,8,1,4]

  • 5<8 → 不动:[3,5,8,1,4]

  • 8>1 → 交换:[3,5,1,8,4]

  • 8>4 → 交换:[3,5,1,4,8]

一轮后最大元素8冒到最后。选A。


题型2:排序算法识别

题目:以下代码实现的是哪种排序算法?

cpp

for (int i = 1; i < n; i++) { int t = a[i], j = i - 1; while (j >= 0 && a[j] > t) { a[j + 1] = a[j]; j--; } a[j + 1] = t; }

A. 冒泡 B. 选择 C. 插入 D. 归并

答案:C

解析:将 a[i] 插入到前面已排好序的部分,典型的插入排序。
选C。


题型3:时间复杂度分析

题目:对几乎有序的数组,以下哪个排序算法效率最高?( )

A. 快速排序 B. 选择排序 C. 插入排序 D. 堆排序

答案:C

解析:插入排序在数据基本有序时最好能达到 O(n),而其他算法仍为O(n log n)或O(n²)。
选C。


题型4:稳定性判断

题目:以下哪个排序算法是不稳定的?( )

A. 冒泡排序 B. 归并排序 C. 选择排序 D. 插入排序

答案:C

解析:选择排序可能改变相等元素的相对顺序(如 [5a, 5b, 2] → [2, 5b, 5a])。
选C。


题型5:排序次数/轮数

题目:对 n 个元素进行冒泡排序,最多需要比较( )次。

A. n B. n(n-1)/2 C. n² D. n log n

答案:B

解析:冒泡排序最多比较 n-1 + n-2 + ... + 1 = n(n-1)/2 次。
选B。


题型6:交换次数分析

题目:对数组 [3, 1, 4, 1, 5, 9] 进行选择排序,需要交换( )次。

A. 2 B. 3 C. 4 D. 5

答案:C

解析:选择排序每轮最多交换一次(找到最小元素后与当前位置交换):

  • 第1轮:找最小1(位置1)与3交换 → [1,3,4,1,5,9]

  • 第2轮:找最小1(位置3)与3交换 → [1,1,4,3,5,9]

  • 第3轮:找最小3(位置3)与4交换 → [1,1,3,4,5,9]

  • 第4轮:找最小4(位置3)已经在正确位置 → 不交换

  • 第5轮:找最小5(位置4)已经在正确位置 → 不交换

共交换3次?不对,有交换的次数是第1、2、3轮,共3次。
但选项中最小是2?让我重新算:

[3,1,4,1,5,9]
第1轮:最小1在位置1,交换a[0]和a[1] → [1,3,4,1,5,9](交换1次)
第2轮:从位置1开始找最小1在位置3,交换a[1]和a[3] → [1,1,4,3,5,9](交换1次)
第3轮:从位置2开始找最小3在位置3,交换a[2]和a[3] → [1,1,3,4,5,9](交换1次)
第4轮:从位置3开始,4已经在正确位置 → 不交换
第5轮:从位置4开始,5已经在正确位置 → 不交换

共3次。选B


题型7:快速排序的递归深度

题目:快速排序最坏情况下的递归深度是( )

A. O(1) B. O(log n) C. O(n) D. O(n log n)

答案:C

解析:最坏情况(已有序且每次都选第一个为基准),递归深度为 n。
选C。


题型8:空间复杂度分析

题目:归并排序的空间复杂度是( )

A. O(1) B. O(log n) C. O(n) D. O(n log n)

答案:C

解析:归并排序需要额外 O(n) 的辅助数组。
选C。


题型9:排序算法的适用场景

题目:当数据规模很大(>10^6)且值域很小(0~100)时,最适合用( )

A. 快速排序 B. 归并排序 C. 计数排序 D. 堆排序

答案:C

解析:值域小(0~100)时,计数排序时间复杂度 O(n),最优。
选C。


题型10:多关键字排序

题目:对学生按总分从高到低排序,总分相同按学号从小到大排序。以下做法正确的是( )

A. 先按总分排序,再按学号排序
B. 先按学号排序,再按总分排序
C. 使用稳定排序先按学号排,再按总分排
D. 使用不稳定排序先按学号排,再按总分排

答案:C

解析:要保证总分相同的情况下学号有序,应使用稳定排序先按学号排,再按总分排(总分为主关键字)。
选C。

例题11:(堆排序过程)

题目:已知大根堆为 [20, 18, 15, 12, 10, 8, 6],删除堆顶元素后,调整后的堆是( )

A. [18, 12, 15, 8, 10, 6]
B. [18, 15, 12, 10, 8, 6]
C. [18, 15, 8, 12, 10, 6]
D. [18, 12, 8, 15, 10, 6]

<details> <summary><strong>点击查看答案与解析</strong></summary>

答案:A

解析:

  1. 删除堆顶20,用最后一个元素6替换到堆顶:
    [6, 18, 15, 12, 10, 8](原数组去掉20,把最后的6放在堆顶)

  2. 向下调整:6与左右孩子18、15比较,18最大 → 交换
    [18, 6, 15, 12, 10, 8]

  3. 继续调整6与子节点12、10比较,12最大 → 交换
    [18, 12, 15, 6, 10, 8]

  4. 继续调整6与子节点8比较,8>6 → 交换
    [18, 12, 15, 8, 10, 6]

选A。

</details>


例题12(堆排序与优先队列)

题目:以下哪个算法可以直接用优先队列实现?( )

A. 冒泡排序 B. 选择排序 C. 堆排序 D. 归并排序

<details> <summary><strong>点击查看答案与解析</strong></summary>

答案:C

解析:优先队列的底层实现就是堆,堆排序直接用优先队列就可以完成。
选C。

</details>


例题13(基数排序过程)

题目:对 [123, 45, 678, 9, 34, 567, 89] 进行 LSD 基数排序,按十位排序后的结果是( )

A. [9, 34, 45, 567, 123, 678, 89]
B. [9, 34, 45, 567, 678, 123, 89]
C. [34, 45, 123, 567, 678, 9, 89]
D. [9, 123, 34, 45, 567, 678, 89]

<details> <summary><strong>点击查看答案与解析</strong></summary>

答案:B

解析:先按个位排序:
个位:123(3), 45(5), 678(8), 9(9), 34(4), 567(7), 89(9)
按个位排序后:[123, 34, 45, 567, 678, 9, 89](个位0-9收集,9有两个注意原顺序)

按十位排序(0补前导0):

  • 123 → 2(十位为2)

  • 34 → 3

  • 45 → 4

  • 567 → 6

  • 678 → 7

  • 9 → 0

  • 89 → 8

按十位0-9收集:[9, 123, 34, 45, 567, 678, 89]
选D?(B是 [9, 34, 45, 567, 678, 123, 89] 不像)

让我重新算:按个位排序后应该是按个位0-9收集,对 [123,45,678,9,34,567,89]:

  • 个位0: 无

  • 个位1: 无

  • 个位2: 无

  • 个位3: 123

  • 个位4: 34

  • 个位5: 45

  • 个位6: 无

  • 个位7: 567

  • 个位8: 678

  • 个位9: 9, 89

按个位排序后:[123, 34, 45, 567, 678, 9, 89]

按十位(0补前导0):
9 → 09,十位=0
123 → 十位=2
34 → 十位=3
45 → 十位=4
567 → 十位=6
678 → 十位=7
89 → 十位=8

按十位0-9收集:[9, 123, 34, 45, 567, 678, 89]
选D。


例题14(桶排序与计数排序对比)

题目:计数排序和桶排序的共同点是( )

A. 都是稳定的 B. 都是比较排序
C. 空间复杂度相同 D. 时间复杂度相同

答案:A

解析:计数排序是稳定的,桶排序如果内部用稳定排序也是稳定的。两者都不是比较排序,空间复杂度不同(计数O(k),桶O(n+k)),时间复杂度也不同。
选A。


六、程序阅读题中的排序

题型11:排序算法的程序识别

题目:阅读以下程序,输出结果是( )

cpp

int a[] = {4, 2, 7, 1, 3}; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4 - i; j++) { if (a[j] > a[j + 1]) swap(a[j], a[j + 1]); } } for (int i = 0; i < 5; i++) cout << a[i] << " ";

A. 1 2 3 4 7 B. 2 4 1 3 7 C. 4 2 1 3 7 D. 1 3 2 4 7

答案:A

解析:这是冒泡排序,最终输出升序排列。
选A。


题型12:排序算法的边界条件

题目:以下程序段的时间复杂度是( )

cpp

for (int i = 0; i < n; i++) { int minIdx = i; for (int j = i + 1; j < n; j++) { if (a[j] < a[minIdx]) minIdx = j; } swap(a[i], a[minIdx]); }

A. O(n) B. O(n log n) C. O(n²) D. O(n² log n)

答案:C

解析:这是选择排序,比较次数为 n(n-1)/2,时间复杂度 O(n²)。
选C。

七、实战检测(8题自测)

题号题目你的答案
1对 [2, 5, 1, 8, 3] 进行冒泡排序,第2轮后的结果是?
2选择排序的时间复杂度总是( )
3快速排序在( )情况下退化为 O(n²)
4归并排序是否稳定?( )
5插入排序在数据( )时效率最高
6对 10^5 个 0~999 的整数排序,最适合用( )
7希尔排序是不稳定排序吗?( )
8堆排序的空间复杂度是( )
  1. [1, 2, 3, 5, 8](已有序?冒泡第二轮:第一轮得[2,1,5,3,8];第二轮:[1,2,3,5,8])
  2. O(n²)
  3. 数据已经有序或逆序(基准选得不好时)
  4. 是(稳定)
  5. 基本有序时
  6. 计数排序(值域小)
  7. 是(不稳定)
  8. O(1)

最后建议:排序是CSP-J复赛的基础工具,必须熟练手写冒泡、选择、插入、快速、归并这五种排序。初赛中重点考查时间/空间复杂度、稳定性、排序过程模拟。把对比表背熟,把代码练熟,这部分分数就能稳稳拿到。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 3:14:45

掌握AI核心组件:从LLM到Agent的全链路解析

概述2024 到 2026 年&#xff0c;AI 领域的术语几乎是爆发式增长。LLM、Token、Context、Prompt、RAG、MCP、Skill、Agent 这些词大家都听过&#xff0c;但真正难的不是分别记住它们&#xff0c;而是搞清楚它们在一个 AI 系统里到底是什么关系、分别扮演什么角色。 如果把一个 …

作者头像 李华
网站建设 2026/7/8 3:11:13

数据孤岛时代落幕:AgentRAG+企业本体语义构建企业大脑

数字化转型多年&#xff0c;多数企业依靠数据中台完成了多系统数据物理汇聚&#xff0c;却始终没能解决跨系统语义割裂、数据无法智能联动的核心痛点。向量空间 JBoltAI 在长期对接 Java 技术团队做 AI 改造的过程中发现&#xff0c;只做数据同步、报表汇总的传统中台&#xff…

作者头像 李华
网站建设 2026/7/8 3:07:37

高职AI实训基地建设找哪家?深度解析实战云的解决方案与成果

近年来&#xff0c;高职院校在推进AI实训基地建设时&#xff0c;普遍面临一个共同难题&#xff1a;既要跟上AI技术的快速迭代&#xff0c;又要控制建设成本、保障教学质量。本文从第三方视角&#xff0c;重点梳理高职AI实训基地建设的核心需求、选型要点&#xff0c;并以实战云…

作者头像 李华
网站建设 2026/7/8 3:06:36

Rocky9部署Zabbix8.0

1.Zabbix坏境准备 系统ipzabbix版本主机名RocKy9192.168.249.1518.0zabbix-serverRocKy9192.168.249.1528.0zabbix-agent # Step 1&#xff1a;关闭防火墙、selinux [rootlocalhost ~]# systemctl stop firewalld && systemctl disable firewalld [rootlocalhost ~]#…

作者头像 李华
网站建设 2026/7/8 3:02:15

Keras Seq2Seq 机器翻译实战:3步搭建英中翻译模型,BLEU 分数提升 0.15

Keras Seq2Seq 机器翻译实战&#xff1a;3步优化模型性能&#xff0c;BLEU 分数提升 0.15在自然语言处理领域&#xff0c;机器翻译一直是极具挑战性的任务。传统的基于规则的翻译系统早已被基于神经网络的端到端模型所取代&#xff0c;其中Seq2Seq&#xff08;Sequence to Sequ…

作者头像 李华