比较排序与非比较排序的区别是?
考点:比较排序与非比较排序(A1)。
解析:比较排序靠元素间比较定序(快排/归并/堆/冒泡/插入/选择);非比较排序利用值本身的信息(计数=值频次、基数=数位、桶=值域区间)。✅ 正确
排除法:无(判断题)。混淆点:稳定性与"比较/非比较"无关——归并(比较)稳定、朴素计数(非比较)不稳定。
关联 · 排序算法家族分类(A6):家族归属。
基于比较的排序算法,其最坏时间复杂度下界是?
考点:比较排序最坏下界(A2)。
解析:比较排序可看作决策树, 种排列对应 个叶 → 树高 ——最坏比较次数下界。✅ 正确
排除法:无(判断题)。混淆点:下界只对比较排序成立;计数/基数不受此限。
关联 · 非比较排序突破下界的原因(A3):为什么能突破。
计数/基数/桶排序能突破 下界,原因是?
考点:非比较排序突破下界的原因(A3)。
解析:非比较排序不做元素间比较,而是利用值域/位权等额外信息直接定位——比较下界的前提(只有比较)不成立。✅ 正确
排除法:无(判断题)。混淆点:代价是前提约束(值域小/位权固定/分布均匀)。
关联 · 非比较排序的适用前提(A4):前提约束。
判断题:非比较排序的适用前提是值域有限且可枚举(计数)、元素有固定位权(基数)、值域可均分(桶)——前提不满足时它们无法工作或退化为灾难。
考点:非比较排序的适用前提(A4)。
解析:计数需值域有限可枚举、基数需固定位权、桶需值域可均分——前提不满足则无法工作或退化(计数 值域爆炸)。✅ 正确
排除法:无(判断题)。混淆点:前提是"交换"来的——用额外信息换速度。
关联 · 计数排序的局限(B6):值域爆炸实例。
判断题:排序稳定性描述"相等元素的相对顺序在排序后是否保持不变"——它是 S 组初赛单选的高频考点。
考点:稳定性总表引入(A5)。
解析:稳定性 = 相等元素排序后相对顺序不变——S 组单选高频考点,须背总表。✅ 正确
排除法:无(判断题)。混淆点:稳定性的价值在多关键字排序与结构体排序。
关联 · 稳定性总表(E 组):总表见 E2/E3。
下列排序算法中,属于非比较排序的是?
考点:排序算法家族分类(A6)。
解析:非比较三兄弟 = 计数、基数、桶;其余(快排/归并/堆/冒泡/插入/选择/希尔)都是比较排序。✅ 正确
排除法:无(判断题)。混淆点:希尔是插入的变体,属比较排序。
关联 · 比较排序与非比较排序(A1):分类依据。
计数排序的核心思想是?
考点:计数排序思想(B1)。
解析:计数排序 = 统计每个值的频次 → 按值从小到大依次展开。✅ 正确
排除法:无(判断题)。混淆点:展开时相同值连在一起,但朴素版丢失了原始顺序信息。
关联 · 计数数组统计(I1):代码版。
计数排序适用于?
考点:计数排序适用(B2)。
解析:整数、值域 小(如成绩 0~100)——计数数组按值域开。✅ 正确
排除法:无(判断题)。混淆点:值域 开不下数组(B6);实数不能直接计数。
关联 · 值域小的场景(F3):应用场景。
计数排序的时间复杂度是?( 元素、值域 )
考点:计数排序复杂度(B3)。
解析:统计 + 展开 → 。✅ 正确
排除法:无(判断题)。混淆点: 小时接近 ; 大时被 主导。
关联 · 计数排序过程示例(B7):过程化理解。
关于计数排序的稳定性,正确的是?
考点:计数排序的稳定性(B4)。
解析:朴素版(直接按频次展开)不稳定(丢失原始顺序);前缀和 + 倒序回填版稳定。✅ 正确
排除法:无(判断题)。混淆点:倒序回填是关键——正序回填也不稳定(P2)。
关联 · 稳定版计数排序输出(I4):代码版。
判断题:计数排序需要 的计数数组和 的输出数组,是非原地排序。
考点:计数排序非原地(B5)。
解析:计数排序需 计数数组 + 输出数组——非原地。✅ 正确
排除法:无(判断题)。混淆点:空间也是"额外信息换速度"的代价。
关联 · 空间对比(F5):空间总表。
判断题:值域 时计数排序需要 大小的数组,空间爆炸——此时不能直接使用计数排序。
考点:计数排序的局限(B6)。
解析:值域 → 计数数组 格 → 内存爆炸——此时不能用计数排序。✅ 正确
排除法:无(判断题)。混淆点:这是"值域小"前提的反面。
关联 · 计数排序值域爆炸(H1):同坑双题。
对 {2, 1, 2, 0, 3} 做计数排序(值域 0~3),计数数组的最终状态是?
考点:计数排序过程示例(B7)。
解析::0 出现 1 次、1 出现 1 次、2 出现 2 次、3 出现 1 次 → {1, 1, 2, 1}。✅ 正确
排除法:无(判断题)。混淆点:计数数组下标是值、内容是频次。
关联 · 计数数组统计(I1):同数据代码题。
基数排序(LSD)的核心思想是?
考点:基数排序思想(C1)。
解析:LSD = 从最低位到最高位,每位一轮稳定排序——低位序被高位稳定排序保留,多轮后整体有序。✅ 正确
排除法:无(判断题)。混淆点:"稳定"是每轮的硬要求(C3/H2)。
关联 · 每轮必须稳定(C3):稳定性的作用。
LSD(最低位优先)与 MSD(最高位优先)的区别是?
考点:LSD 与 MSD(C2)。
解析:LSD 从个位往高位逐轮稳定排序;MSD 从最高位往低位递归分组(高位相同才看低位)。✅ 正确
排除法:无(判断题)。混淆点:LSD 实现简单(统一轮数),MSD 适合不等长(字符串)。
关联 · 基数排序适用(C6):两种策略的选择。
判断题:LSD 基数排序每一轮(每个数位)都必须用稳定排序——否则高位排序会打乱低位已排好的相对顺序。
考点:每轮必须稳定(C3)。
解析:LSD 每一轮必须稳定——否则高位轮会打乱低位轮已排好的相等元素相对顺序,前功尽弃。✅ 正确
排除法:无(判断题)。混淆点:这是 LSD 正确性的核心论证。
关联 · 基数排序每轮必须稳定(H2):同坑双题。
基数排序的时间复杂度是?( 元素、 位、每位基数 )
考点:基数排序复杂度(C4)。
解析: 轮 × 每轮分配收集 → 。✅ 正确
排除法:无(判断题)。混淆点: 小时接近 ; 大(位数多)时不如快排。
关联 · 八大排序复杂度总表(F1):总表。
判断题:LSD 基数排序整体是稳定排序。
考点:基数排序稳定性(C5)。
解析:LSD 基数排序稳定——每轮稳定 + 多轮组合仍稳定。✅ 正确
排除法:无(判断题)。混淆点:稳定性是 LSD 正确性的副产品。
关联 · 基数稳定性验证(L5):代码实证。
基数排序最适合的场景是?
考点:基数排序适用(C6)。
解析:等长整数/字符串、位数 不大——每轮分配收集代价与 成正比。✅ 正确
排除法:无(判断题)。混淆点:实数(浮点)需特殊处理;位数 10 位的整数 尚可。
关联 · 场景选择综合(F6):选择矩阵。
对 {53, 12, 41, 22} 做 LSD 基数排序,第一轮(个位)稳定排序后的顺序是?
考点:基数排序过程示例(C7)。
解析: 个位:1(41)、2(12,22)、3(53) → 41 12 22 53。✅ 正确
排除法:无(判断题)。混淆点:桶内按原顺序收集(稳定)。
关联 · 个位排序输出(J1):代码版。
桶排序的核心思想是?
考点:桶排序思想(D1)。
解析:桶排序 = 值域均分成桶 → 元素入桶 → 桶内排序 → 按桶序拼接。✅ 正确
排除法:无(判断题)。混淆点:桶间天然有序(前面的桶全小于后面的桶),只需桶内排序。
关联 · 桶分配输出(K1):代码版。
桶排序中桶的划分通常依据?
考点:桶的划分(D2)。
解析:按值域均分(如 0~99 分 10 桶、每桶 10 分区间)——保证桶间有序。✅ 正确
排除法:无(判断题)。混淆点:划分太细 ≈ 计数,太粗 → 桶内元素多、退化。
关联 · 桶的划分(K4 填空):桶号计算。
桶排序的平均时间复杂度是?
考点:桶排序复杂度(D3)。
解析:均匀分布时每桶常数个元素 → 桶内排序常数 → 总 平均。✅ 正确
排除法:无(判断题)。混淆点: 是平均且依赖分布假设。
关联 · 桶排序最坏(D4):最坏退化。
桶排序的最坏情况是?
考点:桶排序最坏(D4)。
解析:全部元素挤进同一个桶 → 桶内排序 个元素 → 退化(快排最坏 )。✅ 正确
排除法:无(判断题)。混淆点:最坏触发 = 分布极端不均。
关联 · 桶排序最坏(H3):同坑双题。
桶排序与计数排序的关系是?
考点:桶与计数(D5)。
解析:计数排序 = 每个值一个桶的特例;桶排序的桶是值域区间(一桶多值)。✅ 正确
排除法:无(判断题)。混淆点:两者谱系同源,粒度不同。
关联 · 桶与计数输出(K5):代码版。
判断题:桶排序的稳定性取决于桶内排序算法——桶内用稳定排序(如插入)则整体稳定。
考点:桶排序稳定性(D6)。
解析:桶排序稳定性取决于桶内排序——桶内稳定(如插入)则整体稳定。✅ 正确
排除法:无(判断题)。混淆点:桶内用快排则不稳定。
关联 · 桶内排序输出(K2):桶内插排代码。
桶排序最适合的场景是?
考点:桶排序适用场景(D7)。
解析:数据近似均匀分布、值域已知(0~1 随机实数、成绩分桶)——桶的划分有意义。✅ 正确
排除法:无(判断题)。混淆点:分布未知时桶排序可能严重退化。
关联 · 场景选择综合(F6):选择矩阵。
排序稳定性的准确定义是?
考点:稳定性定义回顾(E1)。
解析:稳定性 = 排序后值相等的元素保持排序前相对先后顺序。✅ 正确
排除法:无(判断题)。混淆点:与升序/降序无关、与原地无关。
关联 · 稳定性判定依据(E4):判定方法。
下列排序算法全部稳定的是?
考点:稳定排序全家(E2)。
解析:稳定五虎 = 冒泡、插入、归并、基数、计数(前缀和版)。✅ 正确
排除法:无(判断题)。混淆点:计数要注明"前缀和版"——朴素版不稳定。
关联 · 不稳定排序全家(E3):对照。
下列排序算法全部不稳定的是?
考点:不稳定排序全家(E3)。
解析:不稳定 = 选择、快速、堆、希尔。✅ 正确
排除法:无(判断题)。混淆点:选择/快排/堆都做"跨距离交换",可能跨过相等元素。
关联 · 稳定性判定依据(E4):为何不稳定。
判断题:判定稳定性的依据是"算法是否可能把相等的两个元素交换跨过彼此"——存在这种交换则不保证稳定。
考点:稳定性判定依据(E4)。
解析:判定标准:算法是否可能把相等元素交换跨过彼此——跨距离交换(选择/快排/堆)则不保证稳定。✅ 正确
排除法:无(判断题)。混淆点:相邻交换(冒泡/插入)不跨过相等元素 → 稳定。
关联 · 不稳定排序输出(L2):实证。
多关键字排序(先按主关键字、同主关键字按次关键字)的正确做法是?
考点:多关键字排序套路(E5)。
解析:先按次关键字稳定排序、再按主关键字稳定排序——第二轮保留第一轮次序。✅ 正确
排除法:无(判断题)。混淆点:顺序反了(先主后次)次关键字白排;不稳定排序两轮都白搭。
关联 · 多关键字排序(L3):代码版。
判断题:以下判定全部正确——"冒泡稳定、选择不稳定、插入稳定、快排不稳定、归并稳定、堆不稳定、基数稳定、朴素计数不稳定"。
考点:稳定性真题判定(E6)。
解析:八项判定全对——冒泡/插入/归并/基数稳定;选择/快排/堆不稳定;朴素计数不稳定。✅ 正确
排除法:无(判断题)。混淆点:S 组单选高频,逐个背熟。
关联 · 稳定性总表(E2/E3):总表收官。
关于时间复杂度,正确的总表是?
考点:八大排序复杂度总表(F1)。
解析:冒泡/选择/插入 ;快排平均 最坏 ;归并/堆 ;计数 ;基数 ;桶平均 。✅ 正确
排除法:无(判断题)。混淆点:总表是 S 组单选必背。
关联 · 复杂度与选择(F 组):全部场景。
值域 与 同阶(如 10 万学生成绩 0~100 万)时,计数排序复杂度 与快排 相比?
考点:比较与非比较的选择(F2)。
解析: 与 同阶时计数 线性——快于 ,前提是值域数组开得下。✅ 正确
排除法:无(判断题)。混淆点:比较"总表复杂度"时别忘了前提。
关联 · 值域小的场景(F3):实例。
对 100 万名学生按成绩(0~750 分)排序,最佳选择是?
考点:值域小的场景(F3)。
解析:100 万学生成绩 0~750:计数排序 ——值域 751 开得下,线性碾压。✅ 正确
排除法:无(判断题)。混淆点:这是计数的教科书场景。
关联 · 名次计算(N1):计数排序应用。
大数据量且要求稳定排序(内存充足),可选?
考点:大数据稳定排序(F4)。
解析:大数据 + 稳定 → 归并( 稳定)或基数(位数不大时)。✅ 正确
排除法:无(判断题)。混淆点:快排/堆不稳定,不满足需求。
关联 · 稳定需求场景(M3):代码场景。
关于空间开销,正确的是?
考点:空间对比(F5)。
解析:计数 、基数 、归并 、快排 、堆 。✅ 正确
排除法:无(判断题)。混淆点:堆排序是唯一原地 的比较排序。
关联 · 空间紧张场景(M4):应用。
判断题:以下选择全部合理——"值域小用计数;位数固定用基数;均匀分布用桶;通用用快排;稳定需求用归并;内存紧张用堆"。
考点:场景选择综合(F6)。
解析:六条选择全合理——值域小→计数、位数固定→基数、均匀分布→桶、通用→快排、稳定→归并、内存紧→堆。✅ 正确
排除法:无(判断题)。混淆点:选择矩阵 = 本章全部排序知识的综合应用。
关联 · 场景选择综合(M6):代码场景版。
某排序过程描述为"统计每个分数的人数,再按分数从低到高依次列出所有学生"——这是?
考点:排序算法识别(G1)。
解析:"统计每个分数人数、按分数列出" = 计数排序。✅ 正确
排除法:无(判断题)。混淆点:识别依据是"统计频次"这一动作。
关联 · 计数排序思想(B1):思想识别。
判断题:以下总表正确——"原地且稳定:冒泡、插入;原地不稳定:选择、快排、堆;非原地稳定:归并、基数、计数;非原地不稳定:朴素桶(桶内不稳定时)"。
考点:稳定性与原地性总表(G2)。
解析:原地稳定:冒泡/插入;原地不稳定:选择/快排/堆;非原地稳定:归并/基数/计数。✅ 正确
排除法:无(判断题)。混淆点:两个维度交叉记忆。
关联 · 稳定性总表(E2/E3)+ 空间对比(F5):双维度总表。
判断题:实际工程中快排(及其变体)最常用——原地、平均快、缓存友好;堆排序虽同是 但跳跃访问偏慢。
考点:排序算法的实际表现(G3)。
解析:工程最常用快排系——原地、平均快、缓存友好;堆排序跳跃访问(父↔子跨大步)缓存差。✅ 正确
排除法:无(判断题)。混淆点:复杂度相同 ≠ 实际一样快。
关联 · 实际运行对比(M5):代码场景。
判断题:STL sort 常用内省排序(快排 + 小规模插入排序 + 递归过深转堆排序)——混合多种算法取长补短。
考点:混合排序(G4)。
解析:内省排序 = 快排 + 小规模插排 + 递归过深转堆排——混合取长补短,是 STL sort 的实现。✅ 正确
排除法:无(判断题)。混淆点:混合排序是工程智慧——单一算法各有短板。
关联 · 排序算法的实际表现(G3):工程视角。
内存装不下全部数据时的外部排序,核心方法是?
考点:外部排序(G5)。
解析:内存装不下 → 分块内排序落盘 → 多路归并各块。✅ 正确
排除法:无(判断题)。混淆点:归并思想的外部化——磁盘块当"序列"。
关联 · 多路归并(J 组 20 章 F3):堆加速多路归并。
判断题:C++ sort 不保证稳定(需要稳定时用 stable_sort)——stable_sort 常用归并实现。
考点:C++ STL 的 sort(G6)。
解析:sort 不保证稳定;stable_sort 稳定(常用归并实现)。✅ 正确
排除法:无(判断题)。混淆点:需要稳定时显式用 stable_sort。
关联 · stable_sort 输出(L6):代码版。
判断题:值域 的整数序列不能用朴素计数排序—— 大小的计数数组内存装不下。
考点:计数排序值域爆炸(H1)。
解析:值域 → 计数数组约 4GB → 内存装不下——不能用朴素计数。✅ 正确
排除法:无(判断题)。混淆点:前提破坏 = 灾难,不是"慢一点"。
关联 · 计数排序的局限(B6):同坑双题。
判断题:LSD 基数排序若某一轮用了不稳定排序,最终结果可能错误——因为低位已排好的相等元素相对顺序会被破坏。
考点:基数排序每轮必须稳定(H2)。
解析:某轮不稳定 → 低位已排好的相等元素相对顺序被打乱 → 最终结果可能错误。✅ 正确
排除法:无(判断题)。混淆点:LSD 正确性的唯一依赖。
关联 · 每轮必须稳定(C3):同坑双题。
判断题:所有元素落入同一个桶时,桶排序退化为桶内排序的复杂度(桶内用快排则最坏 )。
考点:桶排序最坏(H3)。
解析:全部元素进同一个桶 → 桶内排序 个元素 → 退化(桶内快排最坏 )。✅ 正确
排除法:无(判断题)。混淆点:分布不均是桶排序的阿喀琉斯之踵。
关联 · 桶排序最坏(D4):同坑双题。
判断题:"快排稳定""堆排序稳定""基数排序不稳定"——这三个说法中恰好两个正确。
考点:稳定性误判(H4)。
解析:"快排稳定"错、"堆排序稳定"错、"基数排序不稳定"错——三个说法零个正确,不是两个。正确答案 B。
排除法:无(判断题)。混淆点:基数排序是稳定排序(易误判为不稳定)。
关联 · 稳定性真题判定(E6):判定总表。
判断题:以下结论全部正确——"比较排序最坏下界 ;计数排序 依赖值域;LSD 基数排序每轮稳定;桶排序平均 但最坏可退化"。
考点:排序综合判断(H5)。
解析:四结论全对:比较下界 ;计数 依赖值域;LSD 每轮稳定;桶平均 最坏可退化。✅ 正确
排除法:无(判断题)。混淆点:本章核心结论收官自查。
关联 · 本章全部核心结论:收官综合判断题。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {2, 1, 2, 0, 3}; 05 int cnt[4] = {0}; 06 for (int i = 0; i < 5; i++) cnt[a[i]]++; 07 for (int i = 0; i < 4; i++) cout << cnt[i] << " "; 08 return 0; 09}
单选题:程序输出是?(0~3 各值出现的次数)
考点:计数数组统计(I1)。
解析::值 0 出现 1 次、1 出现 1 次、2 出现 2 次、3 出现 1 次 → 1 1 2 1。正确答案 A。
实现要点:计数统计 = cnt[a[i]]++——数组下标是值、内容是频次。手算:逐元素打勾。
排除法:B 是元素本身;C 是下标;D 无依据。
关联 · 计数排序思想(B1):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {3, 1, 2, 1, 3, 0}; 05 int cnt[4] = {0}; 06 for (int i = 0; i < 6; i++) cnt[a[i]]++; 07 int k = 0; 08 for (int v = 0; v < 4; v++) // 按值从小到大展开 09 for (int j = 0; j < cnt[v]; j++) a[k++] = v; 10 for (int i = 0; i < 6; i++) cout << a[i] << " "; 11 return 0; 12}
单选题:程序输出是?
考点:朴素计数排序输出(I2)。
解析:按值 0~3 依次展开频次:0×1、1×2、2×1、3×2 → 0 1 1 2 3 3。正确答案 A。
实现要点:朴素计数 = 统计 + 双层循环按值展开;丢失原始顺序(不稳定)。手算:按 cnt 表逐值输出。
排除法:B 是降序;C 是原数组;D 无依据。
关联 · 计数排序的稳定性(B4):朴素版不稳定。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {2, 1, 2, 0, 3}; 05 int cnt[4] = {0}; 06 for (int i = 0; i < 5; i++) cnt[a[i]]++; 07 for (int v = 1; v < 4; v++) cnt[v] += cnt[v - 1]; // 前缀和:cnt[v] = 值 <= v 的元素个数 08 for (int v = 0; v < 4; v++) cout << cnt[v] << " "; 09 return 0; 10}
单选题:程序输出是?
考点:前缀和输出(I3)。
解析:频次 {1,1,2,1} 前缀和 → {1, 2, 4, 5}(值 ≤v 的个数)。正确答案 A。
实现要点:前缀和 cnt[v] += cnt[v-1]——cnt[v] 变为"值 ≤ v 的元素个数",是稳定回填的定位表。手算:逐项累加。
排除法:B 是原始频次;C/D 无依据。
关联 · 稳定版计数排序输出(I4):前缀和的用途。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04P a[4] = {{2, 'a'}, {1, 'b'}, {2, 'c'}, {1, 'd'}}; 05P out[4]; 06int main() { 07 int cnt[3] = {0}; 08 for (int i = 0; i < 4; i++) cnt[a[i].v]++; 09 for (int v = 1; v <= 2; v++) cnt[v] += cnt[v - 1]; // cnt[v] = 值 <= v 的个数 10 for (int i = 3; i >= 0; i--) { // 倒序回填 → 稳定 11 out[--cnt[a[i].v]] = a[i]; 12 } 13 for (int i = 0; i < 4; i++) cout << out[i].v << out[i].tag << " "; 14 return 0; 15}
单选题:程序输出是?
考点:稳定版计数排序输出(I4)。
解析:前缀和 {0,2,4};倒序回填:2c→out[3]、1d→out[1]、2a→out[2]、1b→out[0] → 1b 1d 2a 2c。正确答案 A。
实现要点:稳定三件套 = 统计 → 前缀和 → 倒序回填(out[--cnt[v]] = a[i]);倒序保证相等元素后出现的先放后面。手算:从后往前逐个定位。
排除法:B 是正序回填(P2 错误版);C/D 无依据。
关联 · 计数排序的稳定性(B4):稳定版代码。
01#include <bits/stdc++.h> 02using namespace std; 03int a[5] = {3, 0, 2, 1, 2}; 04int cnt[4] = {0}; 05int main() { 06 for (int i = 0; i < 5; i++) ______; // 统计频次 07 for (int v = 0; v < 4; v++) 08 for (int j = 0; j < cnt[v]; j++) cout << v << " "; 09 return 0; 10}
单选题:横线处应填入?(使输出为 0 1 2 2 3)
考点:计数排序填空(I5)。
解析:统计频次:cnt[a[i]]++。正确答案 A。
实现要点:下标用元素值而非循环变量——cnt[a[i]] 而非 cnt[i]。手算:验证每个值归位。
排除法:B 统计的是下标;C/D 无依据。
关联 · 计数数组统计(I1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {5, 8, 5, 7}; 05 int mx = 0; 06 for (int i = 0; i < 4; i++) mx = max(mx, a[i]); 07 cout << mx + 1; // 计数数组所需大小 08 return 0; 09}
单选题:程序输出是?(值 0~8 共 9 个位置)
考点:计数值域输出(I6)。
解析:最大值 8 → 值域 0~8 共 9 个位置 → 计数数组大小 mx + 1 = 9。正确答案 A。
实现要点:计数数组大小 = max + 1(值从 0 起)——开小了越界(P1)。手算:找最大值。
排除法:B 是最大值本身;C/D 无依据。
关联 · 计数数组下标错(P1):错误示范。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {53, 12, 41, 22}; 05 int bucket[10][4] = {0}, sz[10] = {0}; 06 for (int i = 0; i < 4; i++) { 07 int d = a[i] % 10; // 个位 08 bucket[d][sz[d]++] = a[i]; 09 } 10 int k = 0; 11 for (int d = 0; d < 10; d++) // 按个位 0~9 收集 12 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 13 for (int i = 0; i < 4; i++) cout << a[i] << " "; 14 return 0; 15}
单选题:程序输出是?(按个位稳定排序后)
考点:个位排序输出(J1)。
解析:个位:53→3、12→2、41→1、22→2;按桶 0~9 收集 → 41 12 22 53。正确答案 A。
实现要点:基数一轮 = 按位分桶 + 按桶序收集;桶内先进先出(稳定)。手算:列桶表。
排除法:B 是十位轮结果;C 是原序;D 无依据。
关联 · 基数排序过程示例(C7):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {41, 12, 22, 53}; // 个位已有序 05 int bucket[10][4] = {0}, sz[10] = {0}; 06 for (int i = 0; i < 4; i++) { 07 int d = a[i] / 10 % 10; // 十位 08 bucket[d][sz[d]++] = a[i]; 09 } 10 int k = 0; 11 for (int d = 0; d < 10; d++) 12 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 13 for (int i = 0; i < 4; i++) cout << a[i] << " "; 14 return 0; 15}
单选题:程序输出是?(个位有序基础上按十位稳定排序)
考点:十位排序输出(J2)。
解析:个位已有序,十位:41→4、12→1、22→2、53→5 → 12 22 41 53。正确答案 A。
实现要点:第二轮在第一轮结果上做——低位序被高位稳定排序保留。手算:两轮串联。
排除法:B 是十位桶内逆序;C 是第一轮结果;D 无依据。
关联 · 每轮必须稳定(C3):稳定性的体现。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {329, 457, 657, 839, 436}; 05 // LSD:对个位、十位、百位各做一轮稳定"分配-收集" 06 for (int pos = 1; pos <= 100; pos *= 10) { 07 int bucket[10][5] = {0}, sz[10] = {0}; 08 for (int i = 0; i < 5; i++) { 09 int d = a[i] / pos % 10; 10 bucket[d][sz[d]++] = a[i]; 11 } 12 int k = 0; 13 for (int d = 0; d < 10; d++) 14 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 15 } 16 for (int i = 0; i < 5; i++) cout << a[i] << " "; 17 return 0; 18}
单选题:程序输出是?
考点:完整基数排序输出(J3)。
解析:三位数三轮 LSD → 整体有序 329 436 457 657 839。正确答案 A。
实现要点:LSD 完整版 = for (pos = 1; pos <= 最高位权; pos *= 10) 循环三轮。手算技巧:验证框架即可。
排除法:B 是降序;C/D 无依据。
关联 · 基数排序思想(C1):完整代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[3] = {21, 12, 30}; 05 int bucket[10][3] = {0}, sz[10] = {0}; 06 for (int i = 0; i < 3; i++) { 07 int d = a[i] % 10; 08 bucket[d][sz[d]++] = a[i]; 09 } 10 int k = 0; 11 for (int d = 0; d < 10; d++) 12 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 13 cout << a[0] << " " << a[1] << " " << a[2]; 14 return 0; 15}
单选题:程序输出是?(第一轮按个位后:个位 0、1、2)
考点:基数排序过程(J4)。
解析: 个位 1、2、0 → 收集 30 21 12。正确答案 A。
实现要点:个位轮后只看个位有序——整体序在最后一轮才成立。手算:列桶。
排除法:B 是原序;C/D 无依据。
关联 · 个位排序输出(J1):同构题。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {53, 12, 41, 22}; 05 int bucket[10][4] = {0}, sz[10] = {0}; 06 for (int i = 0; i < 4; i++) { 07 int d = ______; // 取个位 08 bucket[d][sz[d]++] = a[i]; 09 } 10 int k = 0; 11 for (int d = 0; d < 10; d++) 12 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 13 for (int i = 0; i < 4; i++) cout << a[i] << " "; 14 return 0; 15}
单选题:横线处应填入?(使输出为 41 12 22 53)
考点:基数排序填空(J5)。
解析:取个位:a[i] % 10。正确答案 A。
实现要点:取第 位 = a[i] / pos % 10(pos=1 为个位)。手算:53%10=3。
排除法:B 是十位(丢个位);C 是十位;D 无依据。
关联 · 基数个位填空(O4):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {25, 16, 9, 61}; 05 // 两轮 LSD:个位、十位 06 for (int pos = 1; pos <= 10; pos *= 10) { 07 int bucket[10][4] = {0}, sz[10] = {0}; 08 for (int i = 0; i < 4; i++) { 09 int d = a[i] / pos % 10; 10 bucket[d][sz[d]++] = a[i]; 11 } 12 int k = 0; 13 for (int d = 0; d < 10; d++) 14 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 15 } 16 for (int i = 0; i < 4; i++) cout << a[i] << " "; 17 return 0; 18}
单选题:程序输出是?
考点:LSD 多轮输出(J6)。
解析::个位轮 → 61 25 16 9;十位轮(9 的十位是 0)→ 9 16 25 61。正确答案 A。
实现要点:不足位数的数高位按 0 处理(9/10%10 = 0)。手算:两轮列桶。
排除法:B 是降序;C/D 无依据。
关联 · LSD 多轮(J3):多轮串联。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {45, 12, 78, 23, 91, 34}; 05 int bkt[10][6] = {0}, sz[10] = {0}; 06 for (int i = 0; i < 6; i++) { 07 int b = a[i] / 10; // 十位作桶号:0~9 桶 08 bkt[b][sz[b]++] = a[i]; 09 } 10 int total = 0; 11 for (int b = 0; b < 10; b++) total += sz[b]; 12 cout << total << " "; 13 for (int b = 0; b < 10; b++) if (sz[b]) cout << b << " "; 14 return 0; 15}
单选题:程序输出是?(元素总数 + 非空桶号)
考点:桶分配输出(K1)。
解析:十位桶号:45→4、12→1、78→7、23→2、91→9、34→3 → 非空桶 1 2 3 4 7 9,共 6 元素。正确答案 A。
实现要点:桶分配 = 桶号 a[i] / 10(值域均分),sz 数组记每桶元素数。手算:逐元素算桶号。
排除法:B 含空桶;C/D 无依据。
关联 · 桶排序思想(D1):分配阶段。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int bkt[3] = {23, 21, 25}; // 桶 2 内元素(桶内用插入排序) 05 for (int i = 1; i < 3; i++) { 06 int t = bkt[i], j = i - 1; 07 while (j >= 0 && bkt[j] > t) { bkt[j + 1] = bkt[j]; j--; } 08 bkt[j + 1] = t; 09 } 10 for (int i = 0; i < 3; i++) cout << bkt[i] << " "; 11 return 0; 12}
单选题:程序输出是?(桶内插入排序后)
考点:桶内排序输出(K2)。
解析:桶内插入排序 → 21 23 25。正确答案 A。
实现要点:桶内排序自选算法——插入(稳定)保证整体稳定。手算:插排逐步。
排除法:B 是降序(P4 错误版);C/D 无依据。
关联 · 桶排序稳定性(D6):桶内选稳定算法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {34, 12, 25, 41, 8}; 05 int bkt[10][5] = {0}, sz[10] = {0}; 06 for (int i = 0; i < 5; i++) { 07 int b = a[i] / 10; // 十位作桶号 08 bkt[b][sz[b]++] = a[i]; 09 } 10 for (int b = 0; b < 10; b++) { // 桶内插入排序 11 for (int i = 1; i < sz[b]; i++) { 12 int t = bkt[b][i], j = i - 1; 13 while (j >= 0 && bkt[b][j] > t) { bkt[b][j + 1] = bkt[b][j]; j--; } 14 bkt[b][j + 1] = t; 15 } 16 } 17 for (int b = 0; b < 10; b++) // 按桶序拼接 18 for (int j = 0; j < sz[b]; j++) cout << bkt[b][j] << " "; 19 return 0; 20}
单选题:程序输出是?
考点:完整桶排序输出(K3)。
解析:分桶(十位)+ 桶内插排 + 按桶序拼接 → 8 12 25 34 41。正确答案 A。
实现要点:桶排序三阶段 = 分配 → 桶内排序 → 拼接;桶间天然有序。手算:三阶段各看一次。
排除法:B 是降序;C 是原序;D 无依据。
关联 · 桶排序思想(D1):完整代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {3, 15, 27, 40}; 05 // 值域 0~49 均分 5 个桶:桶号 = 值 / 10 06 int bkt[5][4] = {0}, sz[5] = {0}; 07 for (int i = 0; i < 4; i++) { 08 int b = ______; // 计算桶号 09 bkt[b][sz[b]++] = a[i]; 10 } 11 int total = 0; 12 for (int b = 0; b < 5; b++) total += sz[b]; 13 cout << total; 14 return 0; 15}
单选题:横线处应填入?(使输出为 4——所有元素都分入桶中)
考点:桶划分填空(K4)。
解析:值域 0~49 均分 5 桶:桶号 = a[i] / 10。正确答案 A。
实现要点:桶号 = 值 ÷ 桶宽(10)——整除定位。手算:验证 40/10=4(最后一桶)。
排除法:B 是取个位(基数逻辑);C/D 无依据。
关联 · 桶的划分(D2):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {1, 2, 1, 3}; 05 int cnt[4] = {0}; 06 for (int i = 0; i < 4; i++) cnt[a[i]]++; // 计数 = 每值一桶 07 for (int v = 1; v <= 3; v++) cout << cnt[v] << " "; 08 return 0; 09}
单选题:程序输出是?(值 1、2、3 各出现次数——计数排序可看作"每值一个桶")
考点:桶与计数输出(K5)。
解析::值 1 出现 2 次、2 出现 1 次、3 出现 1 次 → 2 1 1。正确答案 A。
实现要点:计数 = 每值一桶——计数是桶排序的极限细分。手算:统计频次。
排除法:B/C/D 无依据。
关联 · 桶与计数(D5):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03// 桶排序:桶号 = a[i] / 10,值域 0~99
单选题:下列哪个输入会让桶排序退化为最坏情况(所有元素挤进同一个桶)?
考点:桶排序最坏识别(K6)。
解析:{11,12,13,14,15} 十位全 1 → 5 个元素挤进桶 1 → 退化。正确答案 A。
实现要点:最坏识别 = 看分布——集中在一个桶 = 退化。手算:算各输入的桶分布。
排除法:B/C/D 分布在不同桶(不退化)。
关联 · 桶排序最坏(D4):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04P a[4] = {{2, 'a'}, {1, 'b'}, {2, 'c'}, {1, 'd'}}; 05int main() { 06 // 冒泡排序(稳定) 07 for (int i = 0; i < 3; i++) 08 for (int j = 0; j < 3 - i; j++) 09 if (a[j].v > a[j + 1].v) swap(a[j], a[j + 1]); 10 for (int i = 0; i < 4; i++) cout << a[i].v << a[i].tag << " "; 11 return 0; 12}
单选题:程序输出是?(稳定排序:相等元素保持原顺序)
考点:稳定排序输出(L1)。
解析:冒泡相邻交换、相等不交换 → 1b 1d 2a 2c(稳定)。正确答案 A。
实现要点:稳定 = 相等元素不交换(> 而非 >=)。手算:追踪相等元素对。
排除法:B 是相等元素顺序反转(不稳定表现);C/D 无依据。
关联 · 稳定性定义回顾(E1):实证。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04P a[4] = {{2, 'a'}, {2, 'b'}, {1, 'c'}, {3, 'd'}}; 05int main() { 06 // 选择排序(不稳定):每次选最小换到前面 07 for (int i = 0; i < 3; i++) { 08 int m = i; 09 for (int j = i + 1; j < 4; j++) 10 if (a[j].v < a[m].v) m = j; 11 swap(a[i], a[m]); 12 } 13 for (int i = 0; i < 4; i++) cout << a[i].v << a[i].tag << " "; 14 return 0; 15}
单选题:程序输出是?(观察值相同的 2a、2b 相对顺序)
考点:不稳定排序输出(L2)。
解析:选择排序:i=0 选最小 1c 与 2a 交换(跨过 2b)→ 1c 2b 2a 3d——2a/2b 顺序反转。正确答案 A。
实现要点:不稳定 = 跨距离交换跨过相等元素。手算:追踪交换的起点终点。
排除法:B 是稳定结果;C/D 无依据。
关联 · 稳定性判定依据(E4):判定实证。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int major; int minor; }; // 主关键字、次关键字 04P a[4] = {{2, 3}, {1, 5}, {2, 1}, {1, 2}}; 05int main() { 06 // 先按次关键字稳定排序,再按主关键字稳定排序 07 stable_sort(a, a + 4, [](P x, P y) { return x.minor < y.minor; }); 08 stable_sort(a, a + 4, [](P x, P y) { return x.major < y.major; }); 09 for (int i = 0; i < 4; i++) cout << a[i].major << "," << a[i].minor << " "; 10 return 0; 11}
单选题:程序输出是?(主关键字升序、同主关键字按次关键字升序)
考点:多关键字排序(L3)。
解析:先按 minor 稳定排、再按 major 稳定排 → 1,2 1,5 2,1 2,3。正确答案 A。
实现要点:双关键字套路 = 先次后主、两轮都稳定。手算:两轮分别看。
排除法:B 是主关键字内 minor 降序;C/D 无依据。
关联 · 多关键字排序套路(E5):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04P a[5] = {{2, 'a'}, {1, 'b'}, {2, 'c'}, {1, 'd'}, {3, 'e'}}; 05P out[5]; 06int main() { 07 int cnt[4] = {0}; 08 for (int i = 0; i < 5; i++) cnt[a[i].v]++; 09 for (int v = 1; v <= 3; v++) cnt[v] += cnt[v - 1]; 10 for (int i = 4; i >= 0; i--) out[--cnt[a[i].v]] = a[i]; 11 for (int i = 0; i < 5; i++) cout << out[i].v << out[i].tag << " "; 12 return 0; 13}
单选题:程序输出是?
考点:稳定版计数输出(L4)。
解析:倒序回填 → 1b 1d 2a 2c 3e(稳定)。正确答案 A。
实现要点:与 I4 同构,元素多一个值 3。手算:倒序逐个定位。
排除法:B 是正序回填;C 是倒序展开;D 无依据。
关联 · 稳定版计数排序输出(I4):扩展版。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04P a[4] = {{21, 'a'}, {11, 'b'}, {31, 'c'}, {22, 'd'}}; 05P bucket[10][4]; int sz[10] = {0}; 06int main() { 07 for (int i = 0; i < 4; i++) { // 按个位稳定分配-收集 08 int d = a[i].v % 10; 09 bucket[d][sz[d]++] = a[i]; 10 } 11 int k = 0; 12 for (int d = 0; d < 10; d++) 13 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 14 for (int i = 0; i < 4; i++) cout << a[i].v << a[i].tag << " "; 15 return 0; 16}
单选题:程序输出是?(个位 1、1、1、2——桶内按原顺序收集 → 稳定)
考点:基数稳定性验证(L5)。
解析:个位 1 的三个元素按原顺序收集 → 21a 11b 31c 22d。正确答案 A。
实现要点:桶内先进先出 = 稳定——同一位数字的元素保持输入顺序。手算:列桶看顺序。
排除法:B/C/D 桶内顺序乱。
关联 · 基数排序稳定性(C5):实证。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04int main() { 05 P a[4] = {{2, 'x'}, {1, 'a'}, {2, 'y'}, {1, 'b'}}; 06 stable_sort(a, a + 4, [](P p, P q) { return p.v < q.v; }); 07 for (int i = 0; i < 4; i++) cout << a[i].v << a[i].tag << " "; 08 return 0; 09}
单选题:程序输出是?
考点:stable_sort 输出(L6)。
解析:stable_sort 稳定 → 1a 1b 2x 2y。正确答案 A。
实现要点:stable_sort = 归并实现、保证稳定;sort 不保证。手算:相等元素保持原序。
排除法:B 是不稳定结果;C/D 无依据。
关联 · C++ STL 的 sort(G6):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 1000000; // 100 万学生 05 int scoreMax = 750; // 成绩 0~750 06 // 计数排序:数组大小 751,复杂度 O(n + 751) 07 cout << "counting " << n + scoreMax + 1; 08 return 0; 09}
判断题:100 万学生按成绩(0~750)排序,计数排序只需 751 大小的计数数组,复杂度 ——此时计数排序远快于 的比较排序。
考点:值域小场景(M1)。
解析:100 万学生、成绩 0~750:计数数组 751 格、复杂度 ——远快于比较排序。✅ 正确
实现要点:场景判定 = 值域开得下 → 计数排序。手算:比较 vs 。
排除法:无(判断题)。混淆点:值域是选择计数排序的唯一门槛。
关联 · 值域小的场景(F3):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 long long range = 1000000000LL; // 值域 10^9 05 // 计数排序需要 range 大小的数组 → 内存爆炸 06 cout << (range > 100000000 ? "no-counting" : "counting"); 07 return 0; 08}
单选题:程序输出是?(值域 时计数数组约 4GB,开不下)
考点:值域大场景(M2)。
解析: → no-counting——计数数组约 4GB 开不下。正确答案 A。
实现要点:值域门槛判断: 级别就慎用计数。手算:数组字节估算 B。
排除法:B 是值域小时;C/D 无依据。
关联 · 计数排序的局限(B6):代码判定。
01#include <bits/stdc++.h> 02using namespace std; 03struct S { int score; int id; }; // 成绩 + 学号 04int main() { 05 // 需求:按成绩排序,同分按学号升序 06 // 做法:先按学号稳定排序,再按成绩稳定排序 07 cout << "stable needed"; 08 return 0; 09}
判断题:同分保学号序——必须用稳定排序(或先学号后成绩的双关键字稳定排序);直接用不稳定的 sort 可能打乱同分者的学号顺序。
考点:稳定需求场景(M3)。
解析:同分保学号序 → 必须稳定(或先学号后成绩双关键字稳定)——不稳定 sort 会打乱同分者学号。✅ 正确
实现要点:稳定需求 → stable_sort/归并/基数。手算:构造同分不同学号的例子验证。
排除法:无(判断题)。混淆点:sort 不保证稳定。
关联 · 大数据稳定排序(F4):选择矩阵。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 内存极紧张(几乎无额外空间)且要 O(n log n) 05 int n = 100000; 06 cout << "heapsort"; // 堆排序:O(1) 额外空间 07 return 0; 08}
判断题:内存极紧张时选堆排序(原地 );归并需要 辅助、计数需要 计数数组,都不合适。
考点:空间紧张场景(M4)。
解析:内存极紧 + → 堆排序( 额外空间);归并/计数空间不够。✅ 正确
实现要点:空间判定:堆 < 快排 < 归并 < 计数 。手算:对比各算法额外空间。
排除法:无(判断题)。混淆点:堆排序是唯一原地 比较排序。
关联 · 空间对比(F5):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 200000; 05 int a[200000] = {0}; 06 // 同规模下实测:sort 常快于手写堆排序(缓存友好 vs 跳跃访问) 07 sort(a, a + n); 08 cout << "done"; 09 return 0; 10}
判断题:同为 ,STL sort(内省排序)实际常快于堆排序——复杂度假定下常数与缓存行为差异显著。
考点:实际运行对比(M5)。
解析:STL sort(内省排序)实际常快于堆排序——缓存友好 vs 跳跃访问。✅ 正确
实现要点:工程视角:复杂度相同看常数与缓存。手算:同规模实测对比。
排除法:无(判断题)。混淆点:理论 不能区分实际快慢。
关联 · 排序算法的实际表现(G3):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 场景 A:0~1000 分成绩 → 计数 05 // 场景 B:10 位以内整数 1 亿个 → 基数(3~4 轮) 06 // 场景 C:通用整数 → sort 07 // 场景 D:稳定 + 大数据 → 归并 / stable_sort 08 cout << "A-count B-radix C-sort D-merge"; 09 return 0; 10}
判断题:上述四种场景的算法选择全部合理。
考点:场景选择综合(M6)。
解析:四场景选择全合理——成绩计数、整数基数、通用 sort、稳定归并。✅ 正确
实现要点:选择矩阵 = 值域/位数/稳定性/空间四个维度综合。手算:逐场景套矩阵。
排除法:无(判断题)。混淆点:场景选择是本章知识的总检验。
关联 · 场景选择综合(F6):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int score[5] = {90, 80, 90, 70, 85}; 05 int cnt[101] = {0}; 06 for (int i = 0; i < 5; i++) cnt[score[i]]++; 07 // 前缀和:cnt[v] = 分数 <= v 的人数 08 for (int v = 1; v <= 100; v++) cnt[v] += cnt[v - 1]; 09 cout << cnt[85]; // 分数 <= 85 的人数 10 return 0; 11}
单选题:程序输出是?(90、80、90、70、85 中 ≤85 的人数)
考点:名次计算(N1)。
解析:分数 的有 80、70、85 三人 → 3。正确答案 A。
实现要点:计数前缀和 = 名次查询——cnt[v] 即"不超过 v 的人数"。手算:数分数。
排除法:B 漏了 85 本身;C/D 无依据。
关联 · 前缀和输出(I3):前缀和的应用。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {12, 23, 34, 45, 56}; 05 int cnt[10] = {0}; 06 for (int i = 0; i < 5; i++) cnt[a[i] % 10]++; // 统计个位分布 07 for (int d = 0; d < 6; d++) cout << cnt[d] << " "; 08 return 0; 09}
单选题:程序输出是?(个位 0~5 的出现次数)
考点:按位统计(N2)。
解析: 个位 2、3、4、5、6 → cnt[0..5] = 0 0 1 1 1 1。正确答案 A。
实现要点:按位统计 = cnt[a[i] % 10]++——基数排序的前置步骤。手算:逐元素取个位。
排除法:B/C/D 无依据。
关联 · 个位排序输出(J1):统计视角。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 string s[4] = {"banana", "apple", "cherry", "date"}; 05 sort(s, s + 4); // 字典序 06 for (int i = 0; i < 4; i++) cout << s[i] << " "; 07 return 0; 08}
单选题:程序输出是?
考点:字符串排序(N3)。
解析:字典序升序 → apple banana cherry date。正确答案 A。
实现要点:C++ sort 对 string 按字典序(比较排序 )。手算:字典序逐个字符比。
排除法:B 是降序;C/D 无依据。
关联 · 基数排序适用(C6):字符串也可基数排序。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int d[6] = {3, 9, 1, 7, 5, 2}; 05 int k = 2; 06 priority_queue<int, vector<int>, greater<int>> q; // 小根堆存最大的 k 个 07 for (int i = 0; i < 6; i++) { 08 if ((int)q.size() < k) q.push(d[i]); 09 else if (d[i] > q.top()) { q.pop(); q.push(d[i]); } 10 } 11 cout << q.top() << " "; q.pop(); 12 cout << q.top(); 13 return 0; 14}
单选题:程序输出是?(6 个数中最大的 2 个,从小到大)
考点:大数据 top-k(N4)。
解析:k=2 小根堆门槛:最终堆 {7,9} → 输出 7 9。正确答案 A。
实现要点:top-k = 大小为 k 的小根堆当门槛——大于堆顶才替换。手算:逐元素判断。
排除法:B 是降序;C/D 门槛判断错。
关联 · 堆求 top-k(J 组 20 章 F2):堆应用。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 0~999 的整数:先按百位分桶(10 桶),桶内用计数排序(值域 100) 05 int a[5] = {123, 321, 231, 312, 213}; 06 int bucket[10][5] = {0}, sz[10] = {0}; 07 for (int i = 0; i < 5; i++) { 08 int b = a[i] / 100; // 百位桶号 09 bucket[b][sz[b]++] = a[i]; 10 } 11 cout << sz[1] << " " << sz[2] << " " << sz[3]; // 各桶元素数 12 return 0; 13}
单选题:程序输出是?(百位 1、2、3 的桶内元素数)
考点:桶与计数混合(N5)。
解析:百位桶号:123→1、321→3、231→2、312→3、213→2 → sz[1]=1、sz[2]=2、sz[3]=2 → 1 2 2。正确答案 A。
实现要点:桶+计数混合 = 大值域先分桶、桶内小值域再计数——两者组合。手算:逐元素算桶号。
排除法:B/C/D 无依据。
关联 · 桶的划分(D2):混合策略。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; int idx; }; // 值与原始下标 04P a[4] = {{2, 0}, {1, 1}, {2, 2}, {1, 3}}; 05int main() { 06 stable_sort(a, a + 4, [](P x, P y) { return x.v < y.v; }); 07 // 稳定排序后,相等元素的 idx 仍递增 → 顺序可追溯 08 for (int i = 0; i < 4; i++) cout << a[i].idx << " "; 09 return 0; 10}
单选题:程序输出是?(稳定排序后各元素的原始下标)
考点:稳定性应用(N6)。
解析:稳定排序后值 1 的 idx 为 1、3;值 2 的为 0、2 → 1 3 0 2。正确答案 A。
实现要点:稳定性让"排序前下标"可追溯——相等元素的原始顺序信息不丢。手算:稳定排序后看 idx。
排除法:B 是值 2 在前;C/D 无依据。
关联 · 稳定性定义回顾(E1):应用实证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {2, 0, 1, 2, 1, 0}; 05 int cnt[3] = {0}; 06 for (int i = 0; i < 6; i++) ______; // 统计各值出现次数 07 for (int v = 0; v < 3; v++) cout << cnt[v] << " "; 08 return 0; 09}
单选题:横线处应填入?(使输出为 2 2 2)
考点:计数统计填空(O1)。
解析:cnt[a[i]]++——按元素值统计。输出 2 2 2。正确答案 A。
实现要点:下标是元素值(a[i])不是循环变量(i)。手算:验证频次。
排除法:B 统计下标;C 覆盖赋值;D 无依据。
关联 · 计数数组统计(I1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {1, 2, 1, 2}; 05 int cnt[3] = {0}; 06 for (int i = 0; i < 4; i++) cnt[a[i]]++; 07 for (int v = 1; v <= 2; v++) ______; // 前缀和:cnt[v] = 值 <= v 的个数 08 cout << cnt[2]; 09 return 0; 10}
单选题:横线处应填入?(使输出为 4)
考点:前缀和填空(O2)。
解析:cnt[v] += cnt[v - 1]——累计成"≤v 的个数"。输出 4。正确答案 A。
实现要点:前缀和公式 = 当前 + 前一项。手算:1~2 逐项累加。
排除法:B 覆盖(丢累计);C 加 1;D 反向。
关联 · 前缀和输出(I3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04P a[4] = {{2, 'a'}, {1, 'b'}, {2, 'c'}, {1, 'd'}}; 05P out[4]; 06int main() { 07 int cnt[3] = {0}; 08 for (int i = 0; i < 4; i++) cnt[a[i].v]++; 09 for (int v = 1; v <= 2; v++) cnt[v] += cnt[v - 1]; 10 for (int i = ______; i >= 0; i--) // 倒序回填 11 out[--cnt[a[i].v]] = a[i]; 12 for (int i = 0; i < 4; i++) cout << out[i].v << out[i].tag << " "; 13 return 0; 14}
单选题:横线处应填入?(使输出为 1b 1d 2a 2c——稳定)
考点:稳定计数填空(O3)。
解析:倒序回填起点:3(最后一个元素)。正确答案 A。
实现要点:稳定版必须倒序回填(i 从 n-1 到 0)——正序则不稳定(P2)。手算:验证相等元素位置。
排除法:B 正序(不稳定);C/D 无依据。
关联 · 稳定版顺序反(P2):错误对照。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {53, 12, 41, 22}; 05 int bucket[10][4] = {0}, sz[10] = {0}; 06 for (int i = 0; i < 4; i++) { 07 int d = ______; // 取个位数字 08 bucket[d][sz[d]++] = a[i]; 09 } 10 int k = 0; 11 for (int d = 0; d < 10; d++) 12 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 13 for (int i = 0; i < 4; i++) cout << a[i] << " "; 14 return 0; 15}
单选题:横线处应填入?(使输出为 41 12 22 53)
考点:基数个位填空(O4)。
解析:a[i] % 10——取个位数字。正确答案 A。
实现要点:取位公式 a[i] / pos % 10。手算:53%10=3。
排除法:B 是十位;C 是百位;D 无依据。
关联 · 基数排序填空(J5):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {329, 457, 657, 839}; 05 // 三位数:个位、十位、百位三轮 06 for (int pos = 1; pos <= ______; pos *= 10) { 07 int bucket[10][4] = {0}, sz[10] = {0}; 08 for (int i = 0; i < 4; i++) { 09 int d = a[i] / pos % 10; 10 bucket[d][sz[d]++] = a[i]; 11 } 12 int k = 0; 13 for (int d = 0; d < 10; d++) 14 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 15 } 16 for (int i = 0; i < 4; i++) cout << a[i] << " "; 17 return 0; 18}
单选题:横线处应填入?(使输出为 329 457 657 839——三轮覆盖百位)
考点:基数轮次填空(O5)。
解析:三位数三轮:pos <= 100(1、10、100)。正确答案 A。
实现要点:轮数 = 位数——最高位权(三位数 = 100)。手算:验证三轮覆盖。
排除法:B 只两轮(漏百位);C 多一轮(无碍但多余);D 只一轮。
关联 · 基数漏轮(P3):轮次的重要性。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {5, 15, 25, 35, 45}; 05 int bkt[5][5] = {0}, sz[5] = {0}; 06 for (int i = 0; i < 5; i++) { 07 int b = ______; // 桶号:值域 0~49 均分 5 桶 08 bkt[b][sz[b]++] = a[i]; 09 } 10 int total = 0; 11 for (int b = 0; b < 5; b++) total += sz[b]; 12 cout << total; 13 return 0; 14}
单选题:横线处应填入?(使输出为 5——元素全部入桶)
考点:桶分配填空(O6)。
解析:值域 0~49 均分 5 桶:a[i] / 10。正确答案 A。
实现要点:桶号 = 值 / 桶宽。手算:45/10=4。
排除法:B 取个位;C 是 5 分桶(0~9 一桶);D 无依据。
关联 · 桶划分填空(K4):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int major; int minor; }; 04int main() { 05 P a[3] = {{2, 1}, {1, 3}, {2, 2}}; 06 // 先按次关键字稳定排,再按主关键字稳定排 07 stable_sort(a, a + 3, [](P x, P y) { return x.minor < y.minor; }); 08 stable_sort(a, a + 3, [](P x, P y) { return ______; }); 09 for (int i = 0; i < 3; i++) cout << a[i].major << "," << a[i].minor << " "; 10 return 0; 11}
单选题:横线处应填入?(使输出为 1,3 2,1 2,2——主关键字升序、同主关键字保持次关键字升序)
考点:多关键字填空(O7)。
解析:第二轮主关键字:x.major < y.major。正确答案 A。
实现要点:先次后主——第一轮 minor、第二轮 major。手算:验证同 major 保持 minor 序。
排除法:B 是降序;C 重复 minor;D 无依据。
关联 · 多关键字排序(L3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {5, 8, 5, 7}; 05 int cnt[4] = {0}; // 错误:数组只开 4,但值最大 8 06 for (int i = 0; i < 4; i++) cnt[a[i]]++; // 越界写! 07 cout << cnt[0]; 08 return 0; 09}
单选题:程序会发生什么?(值 5、7、8 都超出 cnt[0..3] 的范围)
考点:计数数组下标错(P1)。
解析:cnt 只开 4,但值 5、7、8 越界——cnt[5]、cnt[8] 写数组外,未定义行为。正确答案 A。
实现要点:计数数组大小必须 ≥ max+1;越界写是计数排序的头号 bug。手算:先找最大值再开数组。
排除法:B 无依据;C 语法合法不报错;D 无此机制。
关联 · 计数值域输出(I6):正确大小。
01#include <bits/stdc++.h> 02using namespace std; 03struct P { int v; char tag; }; 04P a[4] = {{2, 'a'}, {1, 'b'}, {2, 'c'}, {1, 'd'}}; 05P out[4]; 06int main() { 07 int cnt[3] = {0}; 08 for (int i = 0; i < 4; i++) cnt[a[i].v]++; 09 for (int v = 1; v <= 2; v++) cnt[v] += cnt[v - 1]; 10 for (int i = 0; i < 4; i++) // 错误:正序回填 11 out[--cnt[a[i].v]] = a[i]; 12 for (int i = 0; i < 4; i++) cout << out[i].v << out[i].tag << " "; 13 return 0; 14}
单选题:程序输出是?(正序回填破坏稳定性)
考点:稳定版顺序反(P2)。
解析:正序回填:2a→out[3]、1b→out[1]、2c→out[2]、1d→out[0] → 1d 1b 2c 2a(不稳定)。正确答案 A。
实现要点:正序回填把后出现的相等元素放到前面——稳定性被破坏;必须倒序。手算:对比正倒序的 out。
排除法:B 是倒序正确结果;C/D 无依据。
关联 · 稳定版计数排序输出(I4):正误对照。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {329, 457, 657, 439}; 05 // 错误:三位数只做了两轮(个位、十位),漏了百位 06 for (int pos = 1; pos <= 10; pos *= 10) { 07 int bucket[10][4] = {0}, sz[10] = {0}; 08 for (int i = 0; i < 4; i++) { 09 int d = a[i] / pos % 10; 10 bucket[d][sz[d]++] = a[i]; 11 } 12 int k = 0; 13 for (int d = 0; d < 10; d++) 14 for (int j = 0; j < sz[d]; j++) a[k++] = bucket[d][j]; 15 } 16 for (int i = 0; i < 4; i++) cout << a[i] << " "; 17 return 0; 18}
单选题:程序输出是?(漏百位轮 → 本例输入恰好百位巧合有序;换成 {657, 329, 457, 439} 同代码输出 329 439 657 457 即错)
考点:基数漏轮(P3)。
解析:两轮后 329 439 457 657(本题百位巧合有序);换成 {657,329,457,439} 输出 329 439 657 457——漏轮算法不可靠。正确答案 A。
实现要点:轮数必须覆盖最高位——三位数做两轮,百位未参与排序。手算:多试一组输入验证。
排除法:B 称恒正确(错);C/D 无依据。
关联 · 基数轮次填空(O5):正确轮数。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int bkt[3] = {21, 25, 23}; 05 // 错误:桶内按降序排 06 for (int i = 1; i < 3; i++) { 07 int t = bkt[i], j = i - 1; 08 while (j >= 0 && bkt[j] < t) { bkt[j + 1] = bkt[j]; j--; } 09 bkt[j + 1] = t; 10 } 11 for (int i = 0; i < 3; i++) cout << bkt[i] << " "; 12 return 0; 13}
单选题:程序输出是?(桶内降序 → 拼接后整体错误)
考点:桶内排序方向(P4)。
解析:桶内降序插排 → 25 23 21——拼接后桶内逆序、整体错误。正确答案 A。
实现要点:桶内排序必须升序(与桶间顺序一致)——方向反则拼接结果错乱。手算:验证拼接后是否整体升序。
排除法:B 是正确升序;C/D 无依据。
关联 · 桶内排序输出(K2):正误对照。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 100; 05 int a[100]; 06 for (int i = 0; i < n; i++) a[i] = i * 10000000; // 值域到 10^9 07 // 若用计数排序:需 10^9 大小的数组 → 内存爆炸 08 int cnt[10] = {0}; 09 cout << cnt[0]; 10 return 0; 11}
判断题:值域 时计数排序需要约 字节的计数数组——内存装不下,应改用快排/归并等比较排序。
考点:计数空间爆炸(P5)。
解析:值域 → 计数数组 字节 ≈ 4GB——内存装不下,改用比较排序。✅ 正确
实现要点:计数数组字节 = 值域 × 4(int)——值域过亿即危险。手算:估算内存。
排除法:无(判断题)。混淆点:空间爆炸是静默的(越界写未定义行为)。
关联 · 计数排序值域爆炸(H1):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {1, 2, 1, 2}; 05 int cnt[4] = {0}; 06 for (int i = 0; i < 4; i++) cnt[a[i]]++; 07 for (int v = 2; v >= 1; v--) cnt[v] += cnt[v - 1]; // 错误:前缀和方向反 08 cout << cnt[1] << " " << cnt[2]; 09 return 0; 10}
单选题:程序输出是?(后缀和方向:cnt[2] 先加 cnt[1],cnt[1] 再加 cnt[0])
考点:前缀和下标错(P6)。
解析:方向反(从大到小累加):cnt[2]=2+2=4、cnt[1]=2+0=2 → 2 4——不是"≤v 的个数"语义。正确答案 A。
实现要点:前缀和必须从小到大累加(v 递增);反向累加变成后缀和。手算:验证语义。
排除法:B 称语义正确(错);C/D 无依据。
关联 · 前缀和填空(O2):正误对照。
判断题:以下结论全部正确——"计数排序 依赖值域、前缀和倒序回填可稳定;LSD 基数排序每轮必须稳定、复杂度 ;桶排序平均 最坏退化;快排/堆不稳定、归并/基数稳定"。
考点:综合判断(P7)。
解析:四结论全对:计数 前缀和倒序可稳定;LSD 每轮稳定 ;桶平均 最坏退化;快排/堆不稳定、归并/基数稳定。✅ 正确
实现要点:本章四大核心结论收官自查。手算:逐条对照本章代码。
排除法:无(判断题)。混淆点:稳定性总表与复杂度总表必须双表背熟。
关联 · 本章全部核心结论:收官综合判断题。