当前位置: 首页 > news >正文

算法题中排序题的思路、模板与cmp/qsort用法详解

一、排序题解题通用思路

  1. 识别排序需求:分析题目,判断是否需要通过排序来获得有序数据,以便后续操作(如贪心、双指针、二分查找)。常见场景包括:
    • 求最大/最小值、前K大/小元素。
    • 合并区间、安排会议/任务(按开始或结束时间排序)。
    • 分组、配对问题(如两数之和、最近点对)。
    • 自定义排序规则(如按多个属性排序)。
  2. 确定排序依据(Key):明确按哪个或哪些属性排序。可能是单一属性(如数值大小),也可能是复合属性(先按身高排,身高相同按体重排)。
  3. 选择排序方法
    • 语言内置排序:绝大多数情况下,直接使用编程语言提供的排序函数(如C++的sort、Python的sorted)即可,其时间复杂度通常为O(n log n)。
    • 特殊数据结构:如果只需要前K个元素,考虑使用堆(优先队列)。
  4. 定义比较规则:当排序规则非默认(升序/降序)或涉及复杂对象时,需要自定义比较函数(Comparator)。这是排序题的核心考点。
  5. 排序后处理:在有序数组上执行后续算法逻辑。

二、排序模板与核心代码

1. C语言模板(使用qsort)

#include <stdio.h> #include <stdlib.h> #include <string.h> // 示例:对整数数组升序排序 int cmp_int_asc(const void *a, const void *b) { return *(int*)a - *(int*)b; // 升序 } int main() { int nums[] = {3, 1, 4, 1, 5}; int n = sizeof(nums) / sizeof(nums[0]); qsort(nums, n, sizeof(int), cmp_int_asc); // 打印排序结果 for (int i = 0; i < n; i++) { printf("%d ", nums[i]); } printf("\n"); return 0; } // 降序排序 int cmp_int_desc(const void *a, const void *b) { return *(int*)b - *(int*)a; // 降序 } // 使用自定义比较函数(例如按绝对值大小升序) int cmp_abs_asc(const void *a, const void *b) { int x = abs(*(int*)a); int y = abs(*(int*)b); if (x < y) return -1; if (x > y) return 1; return 0; } // 对自定义结构体排序 typedef struct { char name[20]; int age; } Person; int cmp_person(const void *a, const void *b) { Person *pa = (Person*)a; Person *pb = (Person*)b; // 先按年龄升序,年龄相同按名字字典序升序 if (pa->age != pb->age) return pa->age - pb->age; return strcmp(pa->name, pb->name); }

2. Python 模板(使用sorted或list.sort)

# 列表排序(原地修改) nums = [3, 1, 4, 1, 5] nums.sort() # 升序 nums.sort(reverse=True) # 降序 返回新列表(不修改原列表) sorted_nums = sorted(nums) # 升序 sorted_nums_desc = sorted(nums, reverse=True) # 降序 使用key参数自定义排序依据(例如按绝对值排序) sorted_by_abs = sorted(nums, key=lambda x: abs(x)) 多级排序:先按长度,再按字典序 words = ["apple", "banana", "cherry", "date"] sorted_words = sorted(words, key=lambda x: (len(x), x)) 对元组列表排序(默认按第一个元素,然后第二个...) pairs = [(1, 3), (2, 2), (1, 1)] sorted_pairs = sorted(pairs) # 结果:[(1, 1), (1, 3), (2, 2)]

三、C语言qsort与cmp函数详解

在C语言中,标准库函数qsort用于对数组进行快速排序,其核心在于自定义cmp(比较)函数。

1. qsort函数原型

#include <stdlib.h> void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
  • base:指向待排序数组首元素的指针。
  • nmemb:数组中元素的个数。
  • size:每个元素的大小(字节数),可用sizeof获取。
  • compar:比较函数指针。该函数接收两个const void*参数,返回int

2. cmp比较函数编写规则

cmp函数的返回值决定了排序顺序:

  • 返回负数(如 -1):表示第一个参数应排在第二个参数前面(升序时表示a < b)。
  • 返回0:表示两元素相等。
  • 返回正数(如 1):表示第一个参数应排在第二个参数后面(升序时表示a > b)。

记忆口诀a - b升序,b - a降序(适用于整型)。

3. 常用cmp函数示例

#include <stdio.h> #include <stdlib.h> #include <string.h> // 示例1:对int数组升序排序 int cmp_int_asc(const void *a, const void *b) { return (int)a - (int)b; // 升序 } // 降序 int cmp_int_desc(const void *a, const void *b) { return (int)b - (int)a; // 降序 } // 示例2:对double数组升序排序(注意浮点数不能直接相减返回int) int cmp_double_asc(const void *a, const void *b) { double diff = (double)a - (double)b; if (diff < 0) return -1; if (diff > 0) return 1; return 0; } // 示例3:对字符串数组按字典序升序排序 int cmp_str_asc(const void a, const void b) { return strcmp((const char*)a, (const char*)b); } // 示例4:对结构体数组排序(先按分数降序,分数相同按学号升序) typedef struct { int id; int score; } Student; int cmp_student(const void *a, const void *b) { Student sa = (Student)a; Student sb = (Student)b; if (sa->score != sb->score) { return sb->score - sa->score; // 分数降序 } return sa->id - sb->id; // 学号升序 } int main() { // 对int数组排序 int nums[] = {3, 1, 4, 1, 5}; int n = sizeof(nums) / sizeof(nums[0]); qsort(nums, n, sizeof(int), cmp_int_asc); // 对结构体数组排序 Student students[] = {{101, 85}, {102, 90}, {103, 85}}; int m = sizeof(students) / sizeof(students[0]); qsort(students, m, sizeof(Student), cmp_student); return 0; }

4. qsort使用注意事项

  • 类型转换:在cmp函数内,需先将const void*指针转换为实际类型的指针。
  • 稳定性qsort是不稳定排序,相等元素的相对位置可能改变。若需要稳定排序,需自己实现或使用其他方法。
  • 溢出风险:对整型使用a - b时,若差值超出int范围会导致溢出错误。更安全的写法是:
    int cmp_safe(const void *a, const void *b) { int x = *(int*)a; int y = *(int*)b; if (x < y) return -1; if (x > y) return 1; return 0; }

四、经典题型与实战模板

题型1:最大/最小K个数(Top K)

思路:排序后取前K个或后K个。时间复杂度O(n log n)。若只需前K个,可用堆优化至O(n log K)。

// C语言:取最小的K个数 #include <stdio.h> #include <stdlib.h> int cmp_int_asc(const void *a, const void *b) { return *(int*)a - *(int*)b; } void getLeastNumbers(int arr[], int n, int k, int result[]) { // 先排序 qsort(arr, n, sizeof(int), cmp_int_asc); // 取前k个 for (int i = 0; i < k; i++) { result[i] = arr[i]; } } int main() { int arr[] = {3, 2, 1, 5, 6, 4}; int n = sizeof(arr) / sizeof(arr[0]); int k = 3; int result[k]; getLeastNumbers(arr, n, k, result); printf("最小的%d个数: ", k); for (int i = 0; i < k; i++) { printf("%d ", result[i]); } printf("\n"); return 0; }

题型2:自定义排序(如“把数组排成最小的数”)

思路:定义一种新的比较规则,将数字转换为字符串后比较拼接结果。

// C语言:将数组里所有数字拼接成最小的数字 #include <stdio.h> #include <stdlib.h> #include <string.h> // 比较函数:比较两个字符串拼接后的大小 int cmp_min_number(const void *a, const void *b) { char str1[24], str2[24], combine1[48], combine2[48]; sprintf(str1, "%d", *(int*)a); sprintf(str2, "%d", *(int*)b); // 拼接两种顺序 strcpy(combine1, str1); strcat(combine1, str2); strcpy(combine2, str2); strcat(combine2, str1); return strcmp(combine1, combine2); } void minNumber(int nums[], int n, char result[]) { // 先排序 qsort(nums, n, sizeof(int), cmp_min_number); // 拼接结果 result[0] = '\0'; for (int i = 0; i < n; i++) { char str[12]; sprintf(str, "%d", nums[i]); strcat(result, str); } } int main() { int nums[] = {3, 32, 321}; int n = sizeof(nums) / sizeof(nums[0]); char result[100]; minNumber(nums, n, result); printf("拼接成的最小数字: %s\n", result); // 输出: 321323 return 0; }

五、总结与技巧

  1. 掌握核心:排序题的核心在于自定义比较规则。深刻理解cmp函数的返回值与排序顺序的关系。
  2. 语言选择:。
    • Python:灵活运用keylambda
    • C:牢记qsortcmp的固定模式。
  3. 调试技巧:编写cmp函数时,可在函数内打印比较的值,验证逻辑是否正确。
  4. 注意边界:处理浮点数、大整数时,避免溢出和精度问题。
  5. 融会贯通:排序常作为其他算法(贪心、双指针、二分)的预处理步骤,结合使用威力更大。
http://www.jsqmd.com/news/1405772/

相关文章:

  • 2026读懂大额事故出险报告实操教程,多平台报告对比,乐爱查车标注结构性损伤 - 资讯报道
  • 在AI信息噪音里,真正拉开开发者差距的技能鸿沟
  • 2026年大语言模型分类难题有解!“弱”模型“想象”分类法更经济
  • 消杀公司需要具备哪些资质才能投标?苏州木渎虫控服务商选型参考 - 康一科技
  • 北京东城区2026奢侈品回收白皮书发布,八步标准化流程首次对外公示 - 大牌科普时报
  • 跨平台翻译软件 pot-desktop 上手实战:让划词与 OCR 变成肌肉记忆
  • 普通汽修店师傅能学会点喷技术吗?标准化就是答案 - 天下观知
  • GroundingDINO 在土星云 SE110S 系列上的部署与实战
  • 点喷加盟店开业初期怎么宣传?三招快速打开局面 - 天下观知
  • SpaceX 600 亿美元收购 Cursor,Cursor 将参与 Grok AI 项目
  • PCO 企业规范四害消杀全流程操作,需遵循哪些行业合规标准?苏州木渎选型参考 - 康一科技
  • 网页媒体资源捕获神器:猫抓浏览器扩展安装与使用完整指南
  • DeepSeek Harness 架构拆解:没有“核心“的 Agent 运行时,“万物皆插件“是怎么做到的
  • 基于SpringBoot的仁爱医院信息管理系统的实现(源码+lw+部署文档+讲解等)
  • 告别千兆瓶颈:RTL8125驱动安装全流程与2.5G跑满实战指南
  • 奢二网实操攻略:西城区钻石饰品迭代更新服务详情解读 - 大牌科普时报
  • 2026 广州黄金回收避坑指南,奢二网拆解虚假高价陷阱做好闲置黄金变现 - 每日小知识
  • 北京东城区香奈儿CF黑金和粉色回收价差30%的数据分析 - 大牌科普时报
  • Gemini 3.7 Flash 今日向订阅用户开放:遵循指令、理解意图能力升级
  • 微信聊天记录备份与导出终极指南:用WeChatMsg把十年对话永久存下来
  • 谷歌允许去除AI内容可见水印,不可见标记仍可验证生成来源
  • 网易孵化谦合益邦获超20亿B轮融资,3D存算一体芯片赛道竞争再升级
  • Ventoy 多系统启动盘制作指南:如何用一个U盘装下所有系统镜像
  • 衢州小白学摄影去哪里好?推荐知美人摄影学校 - 港焙西点-知美人美学
  • 中国 AI 低价方案抢占市场,OpenAI 降价 80%、Anthropic 推低价新品应战!
  • 旧 iPhone 的最后狂欢:palera1n 越狱工具从入门到拆机详解
  • 用了 3 天差点封号:OpenKore 自动化工具安全使用全复盘
  • Qucs-S 电路仿真入门:3 个关键步骤,快速搞定微波传输线计算
  • COOP 上线总是踩坑?webappsec 官方 rollouts 指南逐条拆解
  • 湖州热门轻食糕点培训机构|港焙学校真实测评 - 港焙西点-知美人美学