news 2026/4/22 18:16:27

洛谷 P1177 【模板】排序 从入门到精通:核心算法剖析与实战代码演进

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
洛谷 P1177 【模板】排序 从入门到精通:核心算法剖析与实战代码演进

1. 排序算法入门:从洛谷P1177开始

第一次接触排序算法时,我完全被各种专业术语搞晕了。直到在洛谷刷到P1177这道排序模板题,才真正理解了算法的魅力。这道题就像算法界的"Hello World",看似简单却能让我们掌握计算机科学中最基础也最重要的思想。

题目要求很简单:输入N个数字,输出排序后的结果。但就是这个简单的需求,背后藏着至少5种经典解法。新手最容易上手的是直接调用sort函数,只需要3行核心代码就能AC。但真正想学算法的人,一定会尝试自己实现排序逻辑。我建议初学者按照这个路线图来学习:库函数调用→冒泡排序→快速排序→归并排序,难度循序渐进。

记得我第一次提交冒泡排序时,因为没注意数组越界导致WA了3次。后来才发现是循环条件写错了,把j<n写成了j<=n。这种细节问题在初学阶段特别常见,建议大家多写注释,逐步调试。

2. 五种经典排序实现详解

2.1 偷懒但实用的sort函数

C++的库里的sort函数绝对是新手的福音。它采用类似快速排序的混合算法(IntroSort),时间复杂度是O(NlogN),对于1e5量级的数据完全够用。基本用法是sort(起始地址, 结束地址),比如:

#include<bits/stdc++.h> using namespace std; int a[100005]; // 注意数组要开得比题目要求稍大 int main() { int n; cin >> n; for(int i=0; i<n; i++) cin >> a[i]; sort(a, a+n); // 关键语句 for(int i=0; i<n; i++) cout << a[i] << " "; }

进阶用法可以自定义比较函数。比如要降序排列,可以:

bool cmp(int x, int y){ return x > y; } sort(a, a+n, cmp);

2.2 冒泡排序的两种写法

虽然时间复杂度是O(n²),但冒泡排序的逻辑最直观。我推荐先掌握这种基础版本:

for(int i=0; i<n-1; i++) for(int j=0; j<n-i-1; j++) if(a[j] > a[j+1]) swap(a[j], a[j+1]);

另一种我称为"选择式冒泡"的写法更易记忆:

for(int i=0; i<n-1; i++) for(int j=i+1; j<n; j++) if(a[i] > a[j]) swap(a[i], a[j]);

这两种写法在洛谷P1177都会超时,但作为算法入门练习很有价值。实际测试发现,当n=1e4时,冒泡排序需要约500ms,而sort函数仅需5ms。

2.3 快速排序的优化之路

快排的平均时间复杂度是O(NlogN),但写不好会退化成O(n²)。我经历过三个阶段的优化:

  1. 最初版(效率低):
void quickSort(int l, int r) { if(l >= r) return; int pivot = a[l], i = l, j = r; while(i < j) { while(i<j && a[j]>=pivot) j--; while(i<j && a[i]<=pivot) i++; if(i < j) swap(a[i], a[j]); } swap(a[l], a[i]); quickSort(l, i-1); quickSort(i+1, r); }
  1. 改进版(取中位数作为基准):
void quickSort(int q[], int l, int r) { if(l >= r) return; int mid = q[(l+r)>>1], i = l-1, j = r+1; while(i < j) { do i++; while(q[i] < mid); do j--; while(q[j] > mid); if(i < j) swap(q[i], q[j]); } quickSort(q, l, j); quickSort(q, j+1, r); }
  1. 最终版(加入插入排序优化):
void quickSort(int q[], int l, int r) { if(r - l < 16) { // 小规模数据用插入排序 for(int i=l+1; i<=r; i++) { int temp = q[i], j; for(j=i; j>l && q[j-1]>temp; j--) q[j] = q[j-1]; q[j] = temp; } return; } int mid = q[l + rand()%(r-l+1)], i = l, j = r; // 后续相同... }

2.4 归并排序的稳定优势

归并排序虽然也是O(NlogN),但它是稳定排序,特别适合需要保持原始顺序的场景。核心思想是分治法:

int tmp[100005]; // 临时数组 void mergeSort(int q[], int l, int r) { if(l >= r) return; int mid = (l + r) >> 1; mergeSort(q, l, mid); mergeSort(q, mid+1, r); int k = 0, i = l, j = mid+1; while(i <= mid && j <= r) tmp[k++] = q[i] <= q[j] ? q[i++] : q[j++]; while(i <= mid) tmp[k++] = q[i++]; while(j <= r) tmp[k++] = q[j++]; for(i=l, j=0; i<=r; i++, j++) q[i] = tmp[j]; }

2.5 堆排序的进阶应用

虽然题目没要求,但作为完整的学习,堆排序也值得掌握:

void heapify(int n, int i) { int largest = i, l = 2*i+1, 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(n, largest); } } void heapSort() { for(int i=n/2-1; i>=0; i--) heapify(n, i); for(int i=n-1; i>0; i--) { swap(a[0], a[i]); heapify(i, 0); } }

3. 性能对比与优化技巧

实测在洛谷P1177的测试数据下(n=1e5):

  • sort函数:15ms
  • 优化快排:25ms
  • 归并排序:30ms
  • 堆排序:50ms
  • 冒泡排序:超时(TLE)

几个关键优化点:

  1. 递归改为迭代可以减少函数调用开销
  2. 小规模数据切换为插入排序
  3. 合理选择pivot(如三数取中法)
  4. 避免不必要的内存分配(如提前声明全局临时数组)

对于C++选手,STL还提供了partial_sort、stable_sort等变种,适合不同场景。比如需要前K个有序元素时,partial_sort比完整排序快得多。

4. 从AC到优化:我的踩坑记录

第一次做这道题时,我直接写了冒泡排序提交,结果毫无悬念地TLE了。后来改用sort函数轻松AC,但总觉得不够"硬核"。于是开始研究手写快排,期间遇到过:

  • 无限递归(忘记写递归终止条件)
  • 数组越界(边界条件处理不当)
  • 效率低下(pivot选择不合理)

经过多次优化,最终我的快排版本能在30ms内完成1e5数据的排序。关键突破是:

  1. 随机化pivot选择避免最坏情况
  2. 当区间小于16时改用插入排序
  3. 使用尾递归优化

对于想挑战自己的同学,还可以尝试:

  • 实现三路快排处理大量重复元素
  • 编写非递归版本的归并排序
  • 混合使用多种排序算法

记住洛谷的黄金法则:先保证正确性,再考虑优化。提交前务必用样例测试,并检查边界条件(如n=1, n=0)。

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

Qt调用MATLAB编译的DLL时,那些让人头疼的坑:mwArray传参、环境变量与版本匹配(Win10实测避坑指南)

Qt调用MATLAB编译DLL实战避坑指南&#xff1a;mwArray传参与环境变量精要 当Qt框架需要与MATLAB强大的数学计算能力结合时&#xff0c;混合编程成为理想选择。但在实际集成过程中&#xff0c;开发者常会遇到各种棘手的编译错误、链接失败或运行时崩溃问题。本文将深入解析Qt调用…

作者头像 李华
网站建设 2026/4/22 18:14:42

NVIDIA NIM如何用自然语言对话优化供应链AI规划

1. 供应链AI规划革命&#xff1a;NVIDIA NIM如何用自然语言对话数据在半导体制造业摸爬滚打十几年&#xff0c;我从未见过像NVIDIA这样规模的供应链挑战——数万张GPU、数百英里光缆、上千种零部件通过数百家供应商流向全球工厂。传统规划系统在这种复杂度面前就像用算盘计算航…

作者头像 李华
网站建设 2026/4/22 18:12:52

SAP MIRO批量发票校验后,应付科目行项目金额怎么按暂估比例拆分?一个FMRESERV增强实例

SAP MIRO批量发票校验中应付科目行项目金额的智能拆分方案 每到月末关账时&#xff0c;财务部门的王经理总要面对堆积如山的采购发票。这些通过MIRO批量处理的发票中&#xff0c;经常出现暂估科目与应付科目金额不匹配的情况。最让他头疼的是&#xff0c;系统默认生成的会计凭证…

作者头像 李华
网站建设 2026/4/22 18:11:44

忍者像素绘卷微信小程序集成:生成图自动适配iOS/Android刘海屏显示

忍者像素绘卷微信小程序集成&#xff1a;生成图自动适配iOS/Android刘海屏显示 1. 项目背景与核心价值 忍者像素绘卷是一款基于Z-Image-Turbo深度优化的图像生成工作站&#xff0c;将16-Bit复古游戏美学与现代AI图像生成技术完美结合。这款工具特别适合为微信小程序开发者提供…

作者头像 李华