数据结构与算法面试专题——堆排序
完全二叉树
完全二叉树中如果每棵子树的最大值都在顶部就是大根堆
完全二叉树中如果每棵子树的最小值都在顶部就是小根堆
设计目标:完全二叉树的设计目标是高效地利用存储空间,同时便于进行层次遍历和数组存储。它的结构使得每个节点的子节点都可以通过简单的计算得到,从而实现快速的节点访问。
实现原理:完全二叉树是一棵满二叉树,除了最后一层外,每一层都被完全填充。最后一层的节点都集中在左边。这种结构可以用数组来存储,其中数组的索引对应节点的位置。例如,对于索引为i的节点,其左子节点的索引为2i+1,右子节点的索引为2i+2,父节点的索引为(i-1)/2。
优点:空间利用率高,易于实现数组存储。层次遍历简单,可以通过数组索引快速访问节点。
缺点:插入和删除节点可能比较耗时,特别是当需要保持完全二叉树的结构时,可能需要重新调整整个结构。
堆结构
堆结构就是用数组实现的完全二叉树结构
设计目标:堆结构的设计目标是实现高效的优先级队列和排序算法。它基于完全二叉树的结构,通过维护堆序性(父节点的值大于或等于子节点的值,或者小于或等于子节点的值)来实现快速的插入和删除操作。
实现原理:堆结构通常用数组来实现,其中数组的索引对应节点的位置。在堆中,每个父节点的值都满足一定的条件,例如最大堆中父节点的值大于或等于子节点的值,最小堆中父节点的值小于或等于子节点的值。插入操作通过在数组末尾添加元素,然后通过上浮(Percolate Up)来维护堆序性。删除操作通常是指删除堆顶元素,然后通过下沉(Percolate Down)来维护堆序性。
优点:插入和删除操作的时间复杂度为O(log n),在优先级队列和排序算法中性能优越。空间利用率高,用数组实现简单。
缺点:对于范围查询等操作不友好,无法高效地进行任意元素的查找和删除操作。
如何理解“堆”?
堆本质是一种特殊的树。关于这个树,只要满足两点要求,它就是一个堆:
- 堆是一个完全二叉树;
- 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。
第一点,堆必须是一个完全二叉树。完全二叉树要求,除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列。
第二点,堆中的每个节点的值必须大于等于(或者小于等于)其子树中每个节点的值。实际上,我们还可以换一种说法,堆中每个节点的值都大于等于(或者小于等于)其左右子节点的值。这两种表述是等价的。
对于每个节点的值都大于等于子树中每个节点值的堆,我们叫作“大顶堆”。对于每个节点的值都小于等于子树中每个节点值的堆,我们叫作“小顶堆”。
堆结构的heapInsert操作
将一个新元素插入到堆结构中,并维持堆的性质(即父节点的值大于或等于子节点的值,或者小于或等于子节点的值,视堆的类型而定)。
示例
假设有一个最大堆,堆数组为 [100, 85, 90, 80, 75, 70],现在需要插入元素 95。
-
插入后数组变为
[100, 85, 90, 80, 75, 70, 95]。 -
新元素的位置是 6(从 0 开始计数)。
-
比较新元素与父节点(位置
(6-1)/2=2,值 90):95 > 90,交换两者位置,数组变为[100, 85, 95, 80, 75, 70, 90]。 -
继续比较新元素与新的父节点(位置
(2-1)/2=0,值 100):95 < 100,无需交换。 -
插入完成,堆性质得以维持。
优点:能够在 O(log n) 时间复杂度内完成插入操作。
缺点:需要调整堆的结构,可能导致多次数据交换。
堆结构的heapify操作
在堆结构中,当某个节点的子节点可能违反堆的性质时,通过调整该节点及其子节点,维持堆的性质。
示例
假设有一个最大堆,堆数组为 [95, 85, 90, 80, 75, 70],现在需要对位置 0 的节点进行 heapify 操作。
-
该节点的值为 95,子节点为 85 和 90。
-
95 大于子节点,无需调整。
-
如果堆数组为
[75, 85, 90, 80, 75, 70],需要对位置 0 的节点进行 heapify。 -
比较子节点 85 和 90,选择较大的 90 作为候选。
-
交换 75 和 90,数组变为
[90, 85, 75, 80, 75, 70]。 -
继续 heapify 位置 2 的节点(原来的 75)。
-
比较子节点 80 和 75,交换 75 和 80,数组变为
[90, 85, 80, 75, 75, 70]。 -
继续 heapify 位置 3 的节点(原来的 75),没有子节点,调整完成。
优点:能够在 O(log n) 时间复杂度内完成调整操作。
缺点:需要遍历节点的子节点,可能导致多次数据交换。
堆结构的增大
当堆中的元素数量增加,需要扩展堆的存储空间。
-
通常使用动态数据结构,如动态数组或链表,来实现堆的动态增长。
-
当需要增大堆时,分配新的内存空间,并将原堆中的元素复制到新空间中。
示例
假设堆当前的存储数组大小为 10,已满。需要插入一个新元素,堆将自动增大到大小为 20。
堆结构的减少
当堆中的元素数量减少,可能需要缩小堆的存储空间,以节省内存。
-
释放堆中多余的存储空间,调整存储数组的大小。
-
可以通过动态数据结构的特性,如动态数组的收缩功能,实现堆的缩小。
示例
假设堆当前的存储数组大小为 20,但只有 5 个元素。可以将堆缩小到大小为 10,释放多余的空间。
优先级队列结构
设计目标
优先级队列的设计目标是允许高效地访问和操作优先级最高的元素。与普通队列中的先进先出(FIFO)原则不同,优先级队列中的元素根据其优先级进行排序,并且优先级最高的元素会被优先处理。
实现原理
优先级队列通常使用堆结构来实现,能够高效地维护元素的优先级顺序。
1. 插入操作(Enqueue)
将新元素添加到堆的末尾。
通过上浮(Percolate Up)操作,将新元素与父节点进行比较和交换,直到满足堆的性质。
2. 删除操作(Dequeue)
删除堆顶元素(优先级最高的元素)。
将堆的最后一个元素移动到堆顶。
通过下沉(Percolate Down)操作,将该元素与子节点进行比较和交换,直到满足堆的性质。
优点
插入和删除操作的时间复杂度为 O(log n),在需要动态维护优先级的场景中性能优越。
空间利用率高,可以用数组实现,节省存储空间。
缺点
不支持高效的随机访问和查询操作,无法快速找到任意元素。
对于某些操作(如批量插入),可能需要重新构建整个堆,导致较高的开销。
堆排序
堆排序是一种原地的、时间复杂度为O(n log n)的排序算法。
堆排序不是稳定的排序算法,因为在排序的过程,存在将堆的最后一个节点跟堆顶节点互换的操作,所以就有可能改变值相同数据的原始相对顺序。
实现步骤
-
先让整个数组都变成大根堆结构,建立堆的过程:
-
从上到下的方法,时间复杂度为O(N * logN)
-
从下到上的方法,时间复杂度为O(N)
-
-
把堆的最大值和堆末尾的值交换,然后减少堆的大小之后,再去调整堆,一直周而复始,时间复杂度为O(N * logN)
-
堆的大小减小成0之后,排序完成
实现代码
/*** 对给定的整数数组进行堆排序。* 堆排序是一种基于堆数据结构的排序算法,它的时间复杂度为O(N log N),空间复杂度为O(1)。** @param arr 待排序的整数数组*/public void heapSort(int[] arr) {// 如果数组为空或者长度小于2,直接返回,因为不需要排序if (arr == null || arr.length < 2) {return;}// O(N*logN)// 从数组的最后一个元素开始,依次将每个元素调整为大根堆for (int i = arr.length - 1; i >= 0; i--) {heapify(arr, i, arr.length);}// 初始化堆的大小为数组的长度int heapSize = arr.length;// 将堆顶元素(最大值)与堆的最后一个元素交换,并将堆的大小减1swap(arr, 0, --heapSize);// O(N*logN)// 当堆的大小大于0时,继续进行排序while (heapSize > 0) { // O(N)// 将堆顶元素调整为大根堆heapify(arr, 0, heapSize); // O(logN)// 将堆顶元素(最大值)与堆的最后一个元素交换,并将堆的大小减1swap(arr, 0, --heapSize); // O(1)}}/*** 将指定索引位置的元素插入到堆中,并调整堆结构,使其满足大根堆的性质。* 该方法会将新元素与其父节点比较,如果新元素大于父节点,则交换它们的位置,* 并继续向上比较,直到新元素小于等于父节点或到达堆顶。** @param arr 包含堆元素的数组* @param index 要插入的元素的索引*/public void heapInsert(int[] arr, int index) {// 当当前元素大于其父节点时,交换它们的位置,并更新当前元素的索引while (arr[index] > arr[(index - 1) / 2]) {swap(arr, index, (index - 1) / 2);index = (index - 1) / 2;}}/*** 调整指定索引位置的元素,使其满足大根堆的性质。* 该方法会将指定元素与其子节点比较,如果该元素小于其子节点中的最大值,* 则交换它们的位置,并继续向下比较,直到该元素大于等于其子节点或到达叶子节点。** @param arr 包含堆元素的数组* @param index 要调整的元素的索引* @param heapSize 当前堆的大小*/public void heapify(int[] arr, int index, int heapSize) {// 计算左孩子的下标int left = index * 2 + 1; // 当左孩子存在时,继续循环while (left < heapSize) { // 两个孩子中,谁的值大,把下标给largest// 1)只有左孩子,left -> largest// 2) 同时有左孩子和右孩子,右孩子的值<= 左孩子的值,left -> largest// 3) 同时有左孩子和右孩子并且右孩子的值> 左孩子的值, right -> largest// 找出左右孩子中值较大的那个的下标int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;// 比较父节点和较大孩子的值,将较大值的下标赋给largestlargest = arr[largest] > arr[index] ? largest : index;// 如果父节点已经是最大的,跳出循环if (largest == index) {break;}// 交换父节点和较大孩子的位置swap(arr, largest, index);// 更新当前节点的下标index = largest;// 计算新的左孩子的下标left = index * 2 + 1;}}/*** 交换数组中两个指定索引位置的元素。** @param arr 包含元素的数组* @param i 第一个元素的索引* @param j 第二个元素的索引*/public void swap(int[] arr, int i, int j) {// 使用临时变量交换两个元素的值int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}
过程分析
我们可以把堆排序的过程大致分解成两个大的步骤,建堆和排序。
建堆
我们首先将数组原地建成一个堆。所谓“原地”就是,不借助另一个数组,就在原数组上操作。建堆的过程,有两种思路。
第一种是在堆中插入一个元素。尽管数组中包含个数据,但是我们可以假设,起初堆中只包含一个数据,就是下标为1的数据。然后,我们调用插入操作,将下标从2到n的数据依次插入到堆中。这样我们就将包含n个数据的数组,组织成了堆。
第二种实现思路,跟第一种截然相反。第一种建堆思路的处理过程是从前往后处理数组数据,并且每个数据插入堆中时,都是从下往上堆化。而第二种实现思路,是从后往前处理数组,并且每个数据都是从上往下堆化。
逐层调整,直到整个数组满足堆的条件。
- 从最后一个非叶子节点开始,逐层向上进行 heapify 操作。
- 最后一个非叶子节点的索引为:floor((n-2)/2),其中 n 是数组的长度。
- 使用 heapify 调整以该节点为根的子树。
排序
建堆结束之后,数组中的数据已经是按照大顶堆的特性来组织的。数组中的第一个元素就是堆顶,也就是最大的元素。我们把它跟最后一个元素交换,那最大元素就放到了下标为n的位置。
当堆顶元素移除之后,我们把下标为n的元素放到堆顶,然后再通过堆化的方法,将剩下的n-1个元素重新构建成堆。堆化完成之后,我们再取堆顶的元素,放到下标是n一1的位置,一直重复这个过程,直到最后堆中只剩下标为1的一个元素,排序工作就完成了。
为什么快速排序要比堆排序性能好?
堆排序数据访问的方式没有快速排序友好
快速排序的数据访问方式:
-
快速排序是基于分治法(Divide and Conquer)的排序算法。它通过选择一个基准值(pivot),将数组划分为两个子数组,左侧子数组的元素小于或等于基准值,右侧子数组的元素大于或等于基准值。然后递归地对这两个子数组进行排序。在分割过程中,快速排序对数组中的元素进行连续的比较和交换,这种操作在内存中的数据访问模式通常是连续的,与现代计算机的缓存机制非常匹配。连续的内存访问使得缓存命中率更高,减少了内存访问的延迟,从而提高了排序的效率。
-
例如,当对一个已部分排序的数组进行快速排序时,基准值的选择和分割操作会使得数组被分割为较小的子数组,而这些子数组在内存中是连续存储的。对这些子数组进行递归排序时,缓存能够有效地预取(cache prefetch)这些连续的数据,减少了从主存中加载数据的次数,加快了排序的速度。
堆排序的数据访问方式:
-
堆排序依赖于堆数据结构,需要频繁地访问父节点和子节点。在堆排序过程中,数据的访问模式是随机的,无法充分利用内存的局部性原理。堆的父节点和子节点在内存中可能不是连续存储的,因此访问这些节点时,常常会导致缓存未命中。缓存未命中会增加内存访问的延迟,降低排序的效率。
-
例如,在调整堆结构时,需要比较父节点和子节点的值,并根据比较结果进行交换。这种访问模式使得数据在内存中的跳转较为频繁,无法像快速排序那样利用缓存的预取特性,导致性能下降。
对于同样的数据,在排序过程中,堆排序算法的数据交换次数要多于快速排序
快速排序的数据交换次数:
-
快速排序的平均时间复杂度为O(n log n),其数据交换次数相对较少。在快速排序的分割过程中,每个元素会被交换到正确的位置,但整个过程中交换的次数通常比堆排序少。快速排序的递归结构使得大部分元素的比较和交换发生在较小的子数组中,减少了不必要的数据移动。
-
例如,对一个随机分布的数组进行快速排序时,每次分割操作会使得元素被快速地放置在接近其最终位置的地方。这减少了后续排序过程中需要移动的数据量,从而降低了数据交换的总次数。
堆排序的数据交换次数:
-
堆排序的主要操作是构建堆和调整堆结构。在构建堆的过程中,需要多次比较和交换元素。每次插入或删除元素时,堆结构的维护需要进行多次比较和交换,以确保父节点的值大于或等于子节点的值(对于最大堆而言)。在堆排序的整个过程中,数据交换的次数相对较多。
-
例如,当构建一个最大堆时,每个元素都需要与它的子节点进行比较和交换。如果一个元素的值小于它的子节点中的较大者,就需要交换它们的位置,并继续对子节点进行调整。这个过程会涉及到多次数据交换,直到堆的性质被满足。在堆排序的调整过程中,这样的交换操作会频繁发生,导致数据交换次数增加,从而影响了排序的性能。
相关文章:
数据结构与算法面试专题——堆排序
完全二叉树 完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 完全二叉树中如果每棵子树的最小值都在顶部就是小根堆 设计目标:完全二叉树的设计目标是高效地利用存储空间,同时便于进行层次遍历和数组存储。它的结构使得每个节点的子节点都可以通过简…...
MongoDB索引介绍
索引简述 索引是什么 索引在数据库技术体系中占据了非常重要的位置,其主要表现为一种目录式的数据结构,用来实现快速的数据查询。通常在实现上,索引是对数据库表(集合)中的某些字段进行抽取、排列之后,形成的一种非常易于遍历读取…...
【一文读懂】WebRTC协议
WebRTC(Web Real-Time Communication)协议 WebRTC(Web Real-Time Communication)是一种支持浏览器和移动应用程序之间进行 实时音频、视频和数据通信 的协议。它使得开发者能够在浏览器中实现高质量的 P2P(点对点&…...
【弹性计算】容器、裸金属
容器、裸金属 1.容器和云原生1.1 容器服务1.2 弹性容器实例1.3 函数计算 2.裸金属2.1 弹性裸金属服务器2.2 超级计算集群 1.容器和云原生 容器技术 起源于虚拟化技术,Docker 和虚拟机和谐共存,用户也找到了适合两者的应用场景,二者对比如下图…...
【个人开发】deepspeed+Llama-factory 本地数据多卡Lora微调
文章目录 1.背景2.微调方式2.1 关键环境版本信息2.2 步骤2.2.1 下载llama-factory2.2.2 准备数据集2.2.3 微调模式2.2.3.1 zero-3微调2.2.3.2 zero-2微调2.2.3.3 单卡Lora微调 2.3 踩坑经验2.3.1 问题一:ValueError: Undefined dataset xxxx in dataset_info.json.2…...
两步在 Vite 中配置 Tailwindcss
第一步:安装依赖 npm i -D tailwindcss tailwindcss/vite第二步:引入 tailwindcss 更改配置 // src/main.js import tailwindcss/index// vite.config.js import vue from vitejs/plugin-vue import tailwindcss from tailwindcss/viteexport default …...
使用 HTML CSS 和 JAVASCRIPT 的黑洞动画
使用 HTML CSS 和 JAVASCRIPT 的黑洞动画 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Black Ho…...
计算机视觉-尺度不变区域
一、尺度不变性 1.1 尺度不变性 找到一个函数,实现尺度的选择特性。 1.2 高斯偏导模版求边缘 1.3 高斯二阶导 用二阶过零点检测边缘 高斯二阶导有两个参数:方差和窗宽(给定方差可以算出窗宽) 当图像与二阶导高斯滤波核能匹配…...
SNARKs 和 UTXO链的未来
1. 引言 SNARKs 经常被视为“解决”扩容问题的灵丹妙药。虽然 SNARKs 可以提供令人难以置信的好处,但也需要承认其局限性——SNARKs 无法解决区块链目前面临的现有带宽限制。 本文旨在通过对 SNARKs 对比特币能做什么和不能做什么进行(相对)…...
DeepSeek 通过 API 对接第三方客户端 告别“服务器繁忙”
本文首发于只抄博客,欢迎点击原文链接了解更多内容。 前言 上一期分享了如何在本地部署 DeepSeek R1 模型,但通过命令行运行的本地模型,问答的交互也要使用命令行,体验并不是很好。这期分享几个第三方客户端,涵盖了桌…...
性格测评小程序07用户登录
目录 1 创建登录页2 在首页检查登录状态3 搭建登录功能最终效果总结 小程序注册功能开发好了之后,就需要考虑登录的问题。首先要考虑谁作为首页,如果把登录页作为首页,比较简单,每次访问的时候都需要登录。 如果把功能页作为首页&…...
红队视角出发的k8s敏感信息收集——日志与监控系统
针对 Kubernetes 日志与监控系统 的详细攻击视角分析,聚焦 集群审计日志 和 Prometheus/Grafana 暴露 的潜在风险及利用方法 攻击链示例 1. 攻击者通过容器逃逸进入 Pod → 2. 发现未认证的 Prometheus 服务 → 3. 查询环境变量标签获取数据库密码 → 4. 通过审…...
deepseek多列数据对比,联想到excel的高级筛选功能
目录 1 业务背景 2 deepseek提示词输入 3 联想分析 4 EXCEL高级搜索 1 业务背景 系统上线的时候经常会遇到一个问题,系统导入的数据和线下的EXCEL数据是否一致,如果不一致,如何快速找到差异值,原来脑海第一反应就是使用公…...
国产编辑器EverEdit - “切换文件类型”的使用场景
1 “切换文件类型”的使用场景 1.1 应用背景 一般的编辑器都是通过扩展名映射到对应的语法高亮规则的,比如:文件test.xml中的扩展名“xml"对应XML的语法高亮,在编辑器中打开test.xml就会给不同标识符显示不同的颜色。 但有时一些应用程…...
VSCode 接入DeepSeek V3大模型,附使用说明
VSCode 接入DeepSeek V3大模型,附使用说明 由于近期 DeepSeek 使用人数激增,服务器压力较大,官网已 暂停充值入口 ,且接口响应也开始不稳定,建议使用第三方部署的 DeepSeek,如 硅基流动 或者使用其他模型/插件,如 豆包免费AI插件 MarsCode、阿里免费AI插件 TONGYI Lin…...
JavaScript 内置对象-数组对象
在JavaScript中,数组(Array)是一种非常重要的数据结构,它允许我们以列表的形式存储多个值,并提供了丰富的内置方法来操作这些值。无论是处理简单的数值集合还是复杂的对象数组,数组对象都能提供强大的支持。…...
在linux系统中安装Anaconda,并使用conda
系统 : ubuntu20.04 显卡:NVIDIA GTX1650 目录 安装Anaconda第一步:下载合适版本的Anconda1. 查看自己Linux的操作系统及架构命令:uname -a2. 下载合适版本的Anconda 第二步:安装Aanconda1. 为.sh文件设置权限2. 执行.sh文件2.1 .…...
机械学习基础-5.分类-数据建模与机械智能课程自留
data modeling and machine intelligence - CLASSIFICATION 为什么我们不将回归技术用于分类?贝叶斯分类器(The Bayes Classifier)逻辑回归(Logistic Regression)对逻辑回归的更多直观理解逻辑 /sigmoid 函数的导数我们…...
静态页面在安卓端可以正常显示,但是在ios打开这个页面就需要刷新才能显示全图片
这个问题可能有几个原因导致,我来分析一下并给出解决方案: 首要问题是懒加载实现方式的兼容性问题。当前的懒加载实现可能在 iOS 上不够稳定。建议修改图片懒加载的实现方式: // 使用 Intersection Observer API 实现懒加载 function initLazyLoading() {const imageObserver…...
代码随想录刷题攻略---动态规划---子序列问题1---子序列
子序列(不连续)和子序列(连续)的问题 例题1: 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的…...
八股取士--dockerk8s
一、Docker 基础 Docker 和虚拟机的区别是什么? 答案: 虚拟机(VM):虚拟化硬件,每个 VM 有独立操作系统,资源占用高,启动慢。Docker:容器化应用,共享宿主机内核…...
ubuntu系统下KVM设置桥接网络(失败)
20250216 - 概述 因实验需求,需要设置KVM下的虚拟机采用桥接模式进行通信,这种方式将使虚拟机与主机类似使用同一网段的IP。实际上,为了实现这个功能,我已经在自己mac上VMware使用过,虚拟机获得了自己独立的IP。 但…...
【ISO 14229-1:2023 UDS诊断(会话控制0x10服务)测试用例CAPL代码全解析④】
ISO 14229-1:2023 UDS诊断【会话控制0x10服务】_TestCase04 作者:车端域控测试工程师 更新日期:2025年02月15日 关键词:UDS诊断、0x10服务、诊断会话控制、ECU测试、ISO 14229-1:2023 TC10-004测试用例 用例ID测试场景验证要点参考条款预期…...
OpenAI 放王炸,将发布整合多项技术的 GPT-5,并免费无限使用,该模型有哪些技术亮点
对于 ChatGPT 的免费用户,将可以无限制地访问 GPT-5,但仅限于标准的智能级别。该级别会设定滥用限制,以防止不当使用(意思就是你得付费嘛)。 OpenAI CEO Sam Altman 今天在 X 上透露了 GPT-4.5 和 GPT-5 的最新发展计划。 OpenAI 将发布代…...
C 语言版--销售预测项目案例分享
以下是一个 C 语言销售预测项目案例,该项目模拟根据历史销售数据使用简单的移动平均法来预测未来的销售额。移动平均法是一种常见且基础的时间序列预测方法,它通过计算一定时间段内数据的平均值来预测未来的值。 项目需求 给定一系列历史销售数据,使用简单移动平均法预测下…...
用deepseek学大模型05-线性回归
deepseek.com:多元线性回归的目标函数,损失函数,梯度下降 标量和矩阵形式的数学推导,pytorch真实能跑的代码案例以及模型,数据,预测结果的可视化展示, 模型应用场景和优缺点,及如何改进解决及改进方法数据推…...
DC-7靶机渗透测试全过程
目录 前期准备 一、渗透测试 1.IP地址查询 2.端口地址收集 3.网页信息收集 社工收集信息 Drush直接修改账户密码 下载PHP插件 反弹shell 二、总结 前期准备 攻击机 : kali windows11 靶机: DC-7(调至NAT模式) 一、渗透测试 1.IP地址查询 …...
什么是服务的雪崩、熔断、降级的解释以及Hystrix和Sentinel服务熔断器的解释、比较
1.什么是服务雪崩? 定义:在微服务中,假如一个或者多个服务出现故障,如果这时候,依赖的服务还在不断发起请求,或者重试,那么这些请求的压力会不断在下游堆积,导致下游服务的负载急剧…...
解决IDEA报错:java 找不到符号
问题:IIDEA编译项目一直报 例如 java: 找不到符号 符号: 方法 getUserId()异常 的错误 解决方法: 1、刷新maven 2、clean package...
基于SpringBoot的医院药房管理系统【源码+答辩PPT++项目部署】高质量论文1-1.5W字
作者简介:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容:🌟Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…...
