【C++面试刷题】快排(quick_sort)和堆排(priority_queue)的细节问题

news/2024/10/25 13:29:21/

一、快排的快速选择算法两种思路(面试会考)O(N)

快排的三数取中思路:
重要的是将它三个数进行排序最左为最小,中间为次小,最右为最大的数。(错误原因:我刚开始没有将这三个数进行排序,只是找出其最中间的值,导致时间超时了,这是因为
1、避免最坏情况:如果数组已经部分排序或完全排序,直接选择第一个数或最后一个数作为枢轴值可能会导致分割极不平衡,即一个子数组包含大部分元素,而另一个子数组只包含少数元素。这种情况会使快速排序的性能退化到O(n^2)。通过三数取中法,我们可以选择一个更居中的数作为枢轴值,从而在一定程度上避免这种不平衡的分割。
2、提高分割效率:当选择的枢轴值比较居中时,数组被分割成两个大小相近的子数组,这使得后续的递归排序过程更加高效。因为每次递归调用都需要对两个子数组进行排序,如果子数组的大小相近,则递归的深度会更小,从而减少了排序所需的总时间。
3、减少比较次数:虽然三数取中法本身需要一些额外的比较操作来确定中间数,但这些比较操作的开销相对于整个排序过程来说是微不足道的。而且,通过选择一个更好的枢轴值,我们可以减少后续分割和递归过程中的比较次数,从而提高整体排序效率。)
在这里插入图片描述
快排的随机值思想:
仅仅是随机,是概率求期望,因为是对于随机序列,存在一种称为“Linear Time Median Finding”的算法,该算法能够在最坏情况下也达到O(n)的时间复杂度。
在这里插入图片描述

二、TopK问题–用堆求前K个大/小or第K大/小的元素O(N*logK)

1、开胃小菜

思考一下,既然前K个大/小的元素,那么其实就可以用优先级队列来解决这个问题,可是,我们要注意的是面试中大概率不会说你是否会用这个优先级队列(对于一个C++程序员这个应该是基操吧!?),而大概率是考一下topk问题的这个堆是怎么整出来的,其实也就是我们数据结构中的堆(二叉树)这个部分的向上调整和向下调整建堆的过程,我们先来看一下下面这道题的具体做法(堆和快排),再来讲解一下建堆的具体过程用以我们暂时的理解应对面试。
这是题目:
在这里插入图片描述
这是答案:
在这里插入图片描述
这是解析:
我们简单思考一下这里其实我们建立的是一个小根堆,因为有个greater<int>,所以是小根堆,这里为什么要建立小根堆是因为,当我们新插入的元素比堆顶元素大的时候,那么就交换与堆顶元素,再向下调整就ok了,那么也就是每次插入的时候替换掉最小的元素呗!
而如果是 对于找前K小的元素的时候,那么就建立个大根堆即可,因为我堆顶的元素是最大的,那么当比堆顶的数小的数进来的时候就替换掉并向下调整呗!

这是快排部分:
在这里插入图片描述
这是快排部分解析:
假设我们建立的是升序,那么我们只需要判断第k大的元素是否在最右区间,也就是数量可以比较一下,不在的话就判断是否在等于区间,不在的话就判断是否在最左区间,这里的细节就是在最左区间的时候传进去的大小只有k-b-c这是因为剩下两个区间都已经判断过确实没有,到最左区间就是减去前两个区间的数量的个数。

2、正式说明堆排序的问题

要想弄清楚堆排序,那么就必须先了解建堆的过程,也就是向上调整算法和向下调整算法。

up就是孩子比父亲大就交换,迭代上去,再判断孩子比父亲大就交换。

typedef int HPDataType;
void Swap(HPDataType* p1, HPDataType* p2) 
{ HPDataType temp = *p1; *p1 = *p2; 	*p2 = temp; 
}
//向上调整(除了child,其余全是堆)
//时间复杂度:O(N*logN)
void AdjustUp(HPDataType* a, HPDataType child)
{//判断孩子和父母的关系int parent = (child - 1) / 2;while (child > 0){if (a[child] > a[parent]){Swap(&a[child], &a[parent]);//迭代child = parent;parent = (child - 1) / 2;}else{break;}}
}

down就是因为我们前面是把大根堆的堆顶结点和新进入的值比较小的节点交换了,所以需要向下调整一下,依旧保持此时除了最后一个最大的元素以外的第二大元素当大头,只需要与孩子节点一直比较就ok了,直到孩子节点到最后一个节点了。

//向下调整
//时间复杂度:O(N)
void AdjustDown(HPDataType* a, HPDataType n, HPDataType parent)
{int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void HeapSort(int* a, int n)
{//插入建堆//建堆 -- 向上调整//时间复杂度为O(N*logN)//升序 -- 建大堆int i = 1;for (i = 1; i < n; i++){AdjustUp(a, i);}//从后往前调整int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}

上述是一个升序的数组了,其实也就是先建立大根堆,每次把最大的哪个先选出来放到最后就好了!

结论:
在这里插入图片描述

3、附录

具体详看:
堆排序和TOP-K问题
堆(二叉树)的顺序实现


http://www.ppmy.cn/news/1541835.html

相关文章

设计模式(五)原型模式详解

设计模式&#xff08;五&#xff09;原型模式详解 原型模型简介 定义&#xff1a;原型模型是一种创建型设计模型&#xff0c;它允许通过克隆/复制现有对象来创建新的对象&#xff0c;而无需通过常规的构造函数进行实例化。 这种方式的主要优势是在运行时不需要知道具体的类&a…

E108-GN系列GNSS多模卫星导航定位模块产品说明

E108-GN03和E108-GN04系列系列GNSS多模卫星定位导航模块&#xff0c;具有高性能、高集成度、低功耗、低成本等特点。该系列GNSS多模卫星定位导航模块支持BDS/GPS/GLONASS/GALILEO卫星定位&#xff0c;可多系统联合定位或多系统单独定位&#xff01;米级高精度定位&#xff0c;A…

探索现代软件开发中的持续集成与持续交付(CI/CD)实践

探索现代软件开发中的持续集成与持续交付&#xff08;CI/CD&#xff09;实践 随着软件开发的飞速进步&#xff0c;现代开发团队已经从传统的开发模式向更加自动化和灵活的开发流程转变。持续集成&#xff08;CI&#xff09; 与 持续交付&#xff08;CD&#xff09; 成为当下主…

【MATLAB代码】EKF和CDKF的对比

目录 主要特点 应用场景 运行结果展示 本MATLAB程序实现了扩展卡尔曼滤波&#xff08;EKF&#xff09;与协方差差分卡尔曼滤波&#xff08;CDKF&#xff09;在三维状态估计中的效果对比&#xff0c;为需要高精度定位与动态系统分析的用户提供了一种实用工具。通过直观的结果…

spark sql 广播模式参数

在 Spark SQL 中&#xff0c;广播&#xff08;Broadcast&#xff09;模式常用于处理 Join 操作时的小表与大表的场景&#xff0c;尤其是在小表较小&#xff0c;可以被广播到每个 Executor 时&#xff0c;能够显著提升性能&#xff0c;避免了分布式 Shuffle 的开销。 Spark SQL…

宝塔如何部署Django项目(前后端分离篇)

一、环境安装 1、安装相关软件 点击软件商店&#xff0c;安装下面软件 一、宝塔部署前端 1、打包Vue项目 打开Vue3项目&#xff0c;输入下面打包命令&#xff0c;对Vue项目进行打包&#xff0c; npm run build 2、部署前端 点击宝塔的网站&#xff0c;在PHP项目里点击添加…

短视频账号矩阵系统源码---独立saas技术部署

#短视频账号矩阵系统# #短视频矩阵源码# #短视频账号矩阵系统技术开发# 抖音seo账号矩阵系统&#xff0c;短视频矩阵系统源码&#xff0c; 短视频矩阵是一种常见的视频编码标准&#xff0c;通过多账号一键授权管理的方式&#xff0c;为运营人员打造功能强大及全面的“矩阵式“…

HarmonyOS第一课——HarmonyOS介绍

HarmonyOS第一课 HarmonyOS介绍 HarmonyOS是新一代的智能终端操作系统&#xff08;泛终端服务的载体&#xff09;&#xff1b; 智慧互联协同&#xff0c;全场景交互体验&#xff1b; 核心技术理念&#xff1a; 一次开发 多次部署&#xff1a; 预览 可视化开发UI适配 事件交…