c++算法| 排序 | 99% 程序员必踩的浮点数 + 排序坑
github热门推荐 › c++算法| 排序 | 99% 程序员必踩的浮点数 + 排序坑 (第 73 章)
浮点数不能直接比大小 + 排序的隐藏技巧 / 致命坑点,一篇彻底讲透,看完直接避开 80% 的 BUG。
<span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><vector></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><algorithm></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><cmath></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== 核心1:浮点数比较(排序必用!)====================</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 原理:float是二进制近似存储,直接==>/</=必出错</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 正确方案:放大转整数比较(无精度损耗,排序最稳定)</span></span></code><code><span leaf=""><span class="code-snippet__type">const</span> <span class="code-snippet__type">int</span> SCALE = <span class="code-snippet__number">1000000</span>; <span class="code-snippet__comment">// 放大系数,支持小数点后6位精度</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">bool</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">floatCompare</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__type">float</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> a, </span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__type">float</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> b)</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__type">long</span> <span class="code-snippet__type">long</span> na = <span class="code-snippet__built_in">llround</span>(a * SCALE);</span></code><code><span leaf=""> <span class="code-snippet__type">long</span> <span class="code-snippet__type">long</span> nb = <span class="code-snippet__built_in">llround</span>(b * SCALE);</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> na < nb; <span class="code-snippet__comment">// 升序</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== 核心2:自定义排序(结构体/对象排序)====================</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> <span class="code-snippet__title">Student</span> {</span></code><code><span leaf=""> <span class="code-snippet__type">int</span> id;</span></code><code><span leaf=""> <span class="code-snippet__type">float</span> score; <span class="code-snippet__comment">// 浮点数分数!坑点密集区</span></span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__comment">// 排序规则:分数升序,分数相同则id升序</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">bool</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">studentSort</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__type">const</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Student& s1, </span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__type">const</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Student& s2)</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__type">long</span> <span class="code-snippet__type">long</span> n1 = <span class="code-snippet__built_in">llround</span>(s<span class="code-snippet__number">1.</span>score * SCALE);</span></code><code><span leaf=""> <span class="code-snippet__type">long</span> <span class="code-snippet__type">long</span> n2 = <span class="code-snippet__built_in">llround</span>(s<span class="code-snippet__number">2.</span>score * SCALE);</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (n1 != n2) <span class="code-snippet__keyword">return</span> n1 < n2;</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> s<span class="code-snippet__number">1.</span>id < s<span class="code-snippet__number">2.</span>id;</span></code><code><span leaf="">}</span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">int</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">main</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 坑1:浮点数直接比较错误 ====================</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"===== 浮点数直接比较错误演示 ====="</span> << endl;</span></code><code><span leaf=""> <span class="code-snippet__type">float</span> a = <span class="code-snippet__number">0.1f</span> + <span class="code-snippet__number">0.2f</span>, b = <span class="code-snippet__number">0.3f</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"0.1+0.2 = "</span> << a << <span class="code-snippet__string">", 0.3 = "</span> << b << endl;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"直接==结果:"</span> << (a == b ? <span class="code-snippet__string">"相等"</span> : <span class="code-snippet__string">"不相等"</span>) << endl << endl;</span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 正确:浮点数放大转整数比较 ====================</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"===== 正确:放大转整数比较 ====="</span> << endl;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"放大后比较结果:"</span> << (<span class="code-snippet__built_in">llround</span>(a*SCALE) == <span class="code-snippet__built_in">llround</span>(b*SCALE) ? <span class="code-snippet__string">"相等"</span> : <span class="code-snippet__string">"不相等"</span>) << endl << endl;</span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 坑2:浮点数直接排序错误 ====================</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"===== 浮点数直接排序(错误)====="</span> << endl;</span></code><code><span leaf=""> vector<<span class="code-snippet__type">float</span>> arr = {<span class="code-snippet__number">0.3</span>, <span class="code-snippet__number">0.1+0.2</span>, <span class="code-snippet__number">0.5</span>, <span class="code-snippet__number">0.2</span>};</span></code><code><span leaf=""> <span class="code-snippet__built_in">sort</span>(arr.<span class="code-snippet__built_in">begin</span>(), arr.<span class="code-snippet__built_in">end</span>()); <span class="code-snippet__comment">// 直接用默认比较,精度丢失导致乱序</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">auto</span> f : arr) cout << f << <span class="code-snippet__string">" "</span>;</span></code><code><span leaf=""> cout << endl << endl;</span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 正确:浮点数专用排序 ====================</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"===== 浮点数放大转整数排序(正确)====="</span> << endl;</span></code><code><span leaf=""> <span class="code-snippet__built_in">sort</span>(arr.<span class="code-snippet__built_in">begin</span>(), arr.<span class="code-snippet__built_in">end</span>(), floatCompare);</span></code><code><span leaf=""> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">auto</span> f : arr) cout << f << <span class="code-snippet__string">" "</span>;</span></code><code><span leaf=""> cout << endl << endl;</span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 实战:结构体+浮点数 综合排序 ====================</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"===== 结构体+浮点数 综合排序 ====="</span> << endl;</span></code><code><span leaf=""> vector<Student> stus = {{<span class="code-snippet__number">1</span>, <span class="code-snippet__number">90.5f</span>}, {<span class="code-snippet__number">2</span>, <span class="code-snippet__number">85.3f</span>}, {<span class="code-snippet__number">3</span>, <span class="code-snippet__number">90.5f</span>}, {<span class="code-snippet__number">4</span>, <span class="code-snippet__number">92.1f</span>}};</span></code><code><span leaf=""> <span class="code-snippet__built_in">sort</span>(stus.<span class="code-snippet__built_in">begin</span>(), stus.<span class="code-snippet__built_in">end</span>(), studentSort);</span></code><code><span leaf=""> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">auto</span>& s : stus) cout << <span class="code-snippet__string">"id:"</span> << s.id << <span class="code-snippet__string">" 分数:"</span> << s.score << endl;</span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 排序隐藏坑点总结 ====================</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== 排序必背坑点 ====="</span> << endl;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"1. 整数排序:直接用sort,无坑n"</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"2. 浮点数排序:禁止直接比,必须放大转整数n"</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"3. 字符串排序:默认按ASCII,中文需指定编码n"</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"4. 结构体排序:必须写自定义比较函数,禁止省略n"</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"5. 稳定性:stable_sort()保留相等元素顺序,sort()不保证n"</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"6. 降序排序:直接用greater<>()或自定义函数n"</span>;</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">0</span>;</span></code><code><span leaf="">}</span>一、浮点数比较 / 排序:所有程序员必踩坑
为什么不能直接比?
- float/double 是二进制近似存储
,无法精确表示 0.1、0.2 这类小数 0.1 + 0.2
计算结果 ≠ 0.3,直接比较会出现逻辑错误 -
排序时直接用默认规则,会出现明明相等却排乱的问题
唯一工程正确方案:放大系数转整数比较
-
放大系数 1000000→ 支持小数点后 6 位精度 -
用 llround()四舍五入,避免截断误差 -
转成 long long后可安全使用 == > < -
排序、判断、逻辑判断全部通用
二、C++ 排序全技巧
1. 基础排序
<span leaf="">vector<<span class="code-snippet__type">int</span>> v = {<span class="code-snippet__number">3</span>,<span class="code-snippet__number">1</span>,<span class="code-snippet__number">2</span>};</span></code><code><span leaf=""><span class="code-snippet__built_in">sort</span>(v.<span class="code-snippet__built_in">begin</span>(), v.<span class="code-snippet__built_in">end</span>()); <span class="code-snippet__comment">// 升序(默认)</span></span></code><code><span leaf=""><span class="code-snippet__built_in">sort</span>(v.<span class="code-snippet__built_in">begin</span>(), v.<span class="code-snippet__built_in">end</span>(), <span class="code-snippet__built_in">greater</span><<span class="code-snippet__type">int</span>>()); <span class="code-snippet__comment">// 降序</span></span>stable_sort(v.begin(), v.end());
3. 字符串排序
-
默认按 ASCII 码 排序 -
中文需用 locale或自定义编码比较
4. 结构体 / 对象排序
- 必须写自定义比较函数
-
含浮点数必须放大转整数再比
5. 部分排序(只排前 N 个)
partial_sort(v.begin(), v.begin()+3, v.end());
nth_element(v.begin(), v.begin()+2, v.end());
三、排序 10 大致命坑点
- 浮点数直接 == 比较
→ 必错 - 浮点数直接排序
→ 乱序 -
比较函数返回 = 或 >= → 崩溃 / 死循环 -
排序函数传值而非传引用 → 效率暴跌 -
字符串默认排序中文乱序 -
忽略稳定性要求用了 sort而非stable_sort -
容器越界、空容器直接排序 -
自定义排序规则矛盾(双向返回 true) -
大数排序溢出(int 改 long long) -
未包含 <algorithm>头文件
四、一句话背会核心规则
- 整数随便排
- 浮点数禁止直接比,必须放大转整数
- 结构体必须自定义排序
- 比较函数只返回 <或>
- 稳定排序用 stable_sort
⚠️ 版权声明
本文为免费文章,欢迎转载。转载请注明出处:一木科技(https://www.pingquan.vip/2026/05/31/c%e7%ae%97%e6%b3%95-%e6%8e%92%e5%ba%8f-99-%e7%a8%8b%e5%ba%8f%e5%91%98%e5%bf%85%e8%b8%a9%e7%9a%84%e6%b5%ae%e7%82%b9%e6%95%b0-%e6%8e%92%e5%ba%8f%e5%9d%91/),并保留原文链接。
还没有评论,来说两句?