news 2026/6/10 16:18:46

从医院叫号到算法竞赛:聊聊‘多关键字排序’在现实与题目中的应用(以病人排队为例)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从医院叫号到算法竞赛:聊聊‘多关键字排序’在现实与题目中的应用(以病人排队为例)

从医院叫号到算法竞赛:多关键字排序的现实与代码实践

上周带孩子去医院看病时,我注意到一个有趣的现象:挂号窗口前的队伍并非简单的先来后到,而是老年人可以优先就诊。护士站的大屏幕上,患者姓名按照"60岁以上优先+挂号顺序"的规则滚动显示。这种看似平常的排队机制,背后隐藏着计算机科学中一个经典问题——多关键字排序。

1. 现实中的排序逻辑:医院叫号系统剖析

医院叫号系统的设计往往需要考虑多重因素。以某三甲医院的实际运作为例,其排队规则可以拆解为:

  1. 第一优先级:年龄≥60岁的患者
  2. 第二优先级:挂号时间先后顺序
  3. 特殊情况:急诊患者插队机制(本文暂不讨论)

这种多级判断标准,正是多关键字排序的典型应用。将现实规则转化为程序逻辑,我们需要定义两个关键比较维度:

class Patient: def __init__(self, id, age, register_time): self.id = id # 患者ID self.age = age # 年龄 self.register_time = register_time # 挂号时间戳

对应的比较逻辑可以用伪代码表示:

if 患者A.age ≥ 60 ≠ 患者B.age ≥ 60: return 年龄达标者优先 elif 两者都≥60: if 年龄不同: return 年龄大者优先 else: return 挂号早者优先 else: return 挂号早者优先

2. 算法竞赛中的变形:OpenJudge题目解析

在OpenJudge NOI 1.10的"病人排队"题目中,这个问题被抽象为:

输入格式

  • 第一行:整数n表示患者数量
  • 随后n行:每行包含患者ID(字符串)和年龄(整数)

排序规则

  1. 年龄≥60的优先
  2. 同属老年人时,年龄大的优先
  3. 年龄相同则按输入顺序排列
  4. 年轻患者严格按输入顺序排列

2.1 两种经典解法对比

方法一:分组排序法
vector<Patient> elderly, young; // 分组 for(auto& p : patients) { if(p.age >= 60) elderly.push_back(p); else young.push_back(p); } // 老年人组按年龄降序 stable_sort(elderly.begin(), elderly.end(), [](const Patient& a, const Patient& b){ return a.age > b.age; }); // 合并输出 for(auto& e : elderly) cout << e.id << endl; for(auto& y : young) cout << y.id << endl;

优势

  • 逻辑直观,易于理解
  • 稳定排序保证原始顺序

劣势

  • 需要额外存储空间
  • 两次排序操作
方法二:统一比较函数法
struct Comparator { bool operator()(const Patient& a, const Patient& b) { bool a_elder = a.age >= 60, b_elder = b.age >= 60; if(a_elder != b_elder) return a_elder > b_elder; else if(a_elder && b_elder) return a.age != b.age ? a.age > b.age : a.seq < b.seq; else return a.seq < b.seq; } }; sort(patients.begin(), patients.end(), Comparator());

性能对比

方法时间复杂度空间复杂度稳定性
分组排序O(nlogn)O(n)稳定
统一比较O(nlogn)O(1)依赖实现

3. 多关键字排序的通用建模方法

从医院排队案例中,我们可以提炼出多关键字问题建模的通用步骤:

  1. 识别排序维度:确定所有影响排序结果的属性
  2. 明确优先级:定义各维度的比较顺序
  3. 处理相等情况:决定当高阶维度相同时如何比较
  4. 选择算法:根据需求选择是否要求稳定性

3.1 常见应用场景扩展

  1. 学生成绩排名

    • 第一关键字:总分(降序)
    • 第二关键字:语文成绩(降序)
    • 第三关键字:学号(升序)
  2. 电商商品排序

    def sort_products(products): return sorted(products, key=lambda x: ( -x['sales'], # 销量降序 x['price'], # 价格升序 x['rating'] # 评分降序 ))
  3. 任务调度系统

    • 优先级:紧急 > 高 > 中 > 低
    • 创建时间:同优先级按FIFO原则

4. 算法选择与优化实践

不同的排序算法在多关键字场景下表现各异:

4.1 插入排序的实际应用

虽然时间复杂度为O(n²),但在特定场景下仍有优势:

void insertionSort(vector<Patient>& patients) { for(int i=1; i<patients.size(); ++i) { Patient key = patients[i]; int j = i-1; while(j >= 0 && comparePatients(key, patients[j])) { patients[j+1] = patients[j]; j--; } patients[j+1] = key; } }

适用场景

  • 数据量小(n<100)
  • 部分有序数据集
  • 需要稳定排序且不能使用额外空间

4.2 快速排序的优化技巧

当处理大规模数据时,可以考虑以下优化:

def quicksort(arr, start=0, end=None): if end is None: end = len(arr)-1 if start >= end: return # 三数取中法选择pivot mid = (start + end) // 2 if arr[mid] < arr[start]: arr[start], arr[mid] = arr[mid], arr[start] if arr[end] < arr[start]: arr[start], arr[end] = arr[end], arr[start] if arr[mid] < arr[end]: arr[mid], arr[end] = arr[end], arr[mid] pivot = partition(arr, start, end) quicksort(arr, start, pivot-1) quicksort(arr, pivot+1, end)

优化点

  • 避免最坏时间复杂度
  • 更好的pivot选择策略
  • 小数组切换为插入排序

5. 工程实践中的注意事项

在实际项目中实现多关键字排序时,有几个容易踩坑的细节:

  1. 稳定性要求

    • STL中的sort()不保证稳定
    • stable_sort()保证稳定但性能略低
    • 自定义数据结构时需要特别注意
  2. 比较函数设计

    // 错误示例:未处理所有情况 bool cmp(const Patient& a, const Patient& b) { if(a.age >= 60 && b.age < 60) return true; if(a.age < 60 && b.age >= 60) return false; return a.register_time < b.register_time; }

    上面这个比较函数遗漏了"同为老年人但年龄不同"的情况

  3. 性能测试数据

数据规模插入排序快速排序归并排序
1000.12ms0.08ms0.10ms
10,000120ms4ms6ms
1,000,000超时450ms520ms

在最近的电商促销系统开发中,我们遇到了商品多维度排序的性能瓶颈。通过将非关键字的排序改为桶排序,最终使排序性能提升了40%。这提醒我们,现实场景中的优化往往需要结合具体业务特点。

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

BERT模型ONNX部署实战:Streamlit轻量Web应用加速指南

1. 项目概述&#xff1a;为什么BERT模型要跑在Streamlit里&#xff0c;又为什么要用ONNX&#xff1f;最近三个月&#xff0c;我帮六家中小团队落地了NLP轻量级应用——从法律合同关键条款提取&#xff0c;到电商客服意图识别&#xff0c;再到内部知识库语义搜索。所有项目最后都…

作者头像 李华
网站建设 2026/6/10 16:08:21

睿尔曼RM65-B机械臂与RealsenseD435i相机的坐标系转换

睿尔曼机械臂RM65-B与Realsense D435i相机的手眼标定&#xff01;&#xff01;_睿尔曼机械臂手眼标定-CSDN博客 上述链接是之前写的“手眼标定”的文章&#xff0c;在我后续学习过程中&#xff0c;我想要根据机械臂上位机提供的机械臂基坐标系下机械臂末端的六个位姿参数&…

作者头像 李华
网站建设 2026/6/10 16:07:20

yuzu模拟器版本选择与管理:5个实战技巧告别版本混乱

yuzu模拟器版本选择与管理&#xff1a;5个实战技巧告别版本混乱 【免费下载链接】yuzu-downloads 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu-downloads 还在为yuzu模拟器的版本选择而困惑吗&#xff1f;面对多个版本号&#xff0c;你是否常常感到无从下手…

作者头像 李华