【數據結構與算法-Day 27】堆的應用:從堆排序到 Top K 問題,一文徹底搞定!

Langchain系列文章目錄

01-玩轉LangChain:從模型調用到Prompt模板與輸出解析的完整指南
02-玩轉 LangChain Memory 模塊:四種記憶類型詳解及應用場景全覆蓋
03-全面掌握 LangChain:從核心鏈條構建到動態任務分配的實戰指南
04-玩轉 LangChain:從文檔加載到高效問答系統構建的全程實戰
05-玩轉 LangChain:深度評估問答系統的三種高效方法(示例生成、手動評估與LLM輔助評估)
06-從 0 到 1 掌握 LangChain Agents:自定義工具 + LLM 打造智能工作流!
07-【深度解析】從GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【萬字長文】MCP深度解析:打通AI與世界的“USB-C”,模型上下文協議原理、實踐與未來

Python系列文章目錄

PyTorch系列文章目錄

機器學習系列文章目錄

深度學習系列文章目錄

Java系列文章目錄

JavaScript系列文章目錄

Python系列文章目錄

Go語言系列文章目錄

Docker系列文章目錄

數據結構與算法系列文章目錄

01-【數據結構與算法-Day 1】程序世界的基石:到底什么是數據結構與算法?
02-【數據結構與算法-Day 2】衡量代碼的標尺:時間復雜度與大O表示法入門
03-【數據結構與算法-Day 3】揭秘算法效率的真相:全面解析O(n^2), O(2^n)及最好/最壞/平均復雜度
04-【數據結構與算法-Day 4】從O(1)到O(n2),全面掌握空間復雜度分析
05-【數據結構與算法-Day 5】實戰演練:輕松看懂代碼的時間與空間復雜度
06-【數據結構與算法-Day 6】最樸素的容器 - 數組(Array)深度解析
07-【數據結構與算法-Day 7】告別數組束縛,初識靈活的鏈表 (Linked List)
08-【數據結構與算法-Day 8】手把手帶你拿捏單向鏈表:增、刪、改核心操作詳解
09-【數據結構與算法-Day 9】圖解單向鏈表:從基礎遍歷到面試必考的鏈表反轉
10-【數據結構與算法-Day 10】雙向奔赴:深入解析雙向鏈表(含圖解與代碼)
11-【數據結構與算法-Day 11】從循環鏈表到約瑟夫環,一文搞定鏈表的終極形態
12-【數據結構與算法-Day 12】深入淺出棧:從“后進先出”原理到數組與鏈表雙實現
13-【數據結構與算法-Day 13】棧的應用:從括號匹配到逆波蘭表達式求值,面試高頻考點全解析
14-【數據結構與算法-Day 14】先進先出的公平:深入解析隊列(Queue)的核心原理與數組實現
15-【數據結構與算法-Day 15】告別“假溢出”:深入解析循環隊列與雙端隊列
16-【數據結構與算法-Day 16】隊列的應用:廣度優先搜索(BFS)的基石與迷宮尋路實戰
17-【數據結構與算法-Day 17】揭秘哈希表:O(1)查找速度背后的魔法
18-【數據結構與算法-Day 18】面試必考!一文徹底搞懂哈希沖突四大解決方案:開放尋址、拉鏈法、再哈希
19-【數據結構與算法-Day 19】告別線性世界,一文掌握樹(Tree)的核心概念與表示法
20-【數據結構與算法-Day 20】從零到一掌握二叉樹:定義、性質、特殊形態與存儲結構全解析
21-【數據結構與算法-Day 21】精通二叉樹遍歷(上):前序、中序、后序的遞歸與迭代實現
22-【數據結構與算法-Day 22】玩轉二叉樹遍歷(下):廣度優先搜索(BFS)與層序遍歷的奧秘
23-【數據結構與算法-Day 23】為搜索而生:一文徹底搞懂二叉搜索樹 (BST) 的奧秘
24-【數據結構與算法-Day 24】平衡的藝術:圖解AVL樹,徹底告別“瘸腿”二叉搜索樹
25-【數據結構與算法-Day 25】工程中的王者:深入解析紅黑樹 (Red-Black Tree)
26-【數據結構與算法-Day 26】堆:揭秘優先隊列背后的“特殊”完全二叉樹
27-【數據結構與算法-Day 27】堆的應用:從堆排序到 Top K 問題,一文徹底搞定!


文章目錄

  • Langchain系列文章目錄
  • Python系列文章目錄
  • PyTorch系列文章目錄
  • 機器學習系列文章目錄
  • 深度學習系列文章目錄
  • Java系列文章目錄
  • JavaScript系列文章目錄
  • Python系列文章目錄
  • Go語言系列文章目錄
  • Docker系列文章目錄
  • 數據結構與算法系列文章目錄
  • 摘要
  • 一、溫故知新:堆的核心概念回顧
  • 二、堆排序 (Heap Sort):原地排序的藝術
    • 2.1 第一步:原地建堆 (Heapify)
        • (1)建堆過程圖解
    • 2.2 第二步:排序階段
        • (1)排序過程圖解
    • 2.3 代碼實現 (Java)
    • 2.4 性能分析
  • 三、Top K 問題:海量數據處理的利器
    • 3.1 問題定義與挑戰
    • 3.2 解決方案:小頂堆的妙用
        • (1)算法流程
        • (2)為什么用最小堆?
    • 3.3 代碼實現 (Java)
    • 3.4 復雜度分析與擴展
        • (1)復雜度分析
        • (2)舉一反三
  • 四、總結


摘要

在上一篇文章中,我們學習了堆(Heap)這種特殊的完全二叉樹結構及其核心操作。今天,我們將把理論付諸實踐,深入探討堆的兩個殺手級應用:堆排序 (Heap Sort) 和經典的 Top K 問題。堆排序是一種高效的原地排序算法,理解它的原理能加深我們對堆結構的掌握。而 Top K 問題則是大數據和面試場景下的常客,通過堆可以找到極其優雅且高效的解決方案。本文將通過圖解、代碼和詳盡的分析,帶你徹底征服這兩個知識點,讓你無論在項目開發還是技術面試中都能游刃有余。

一、溫故知新:堆的核心概念回顧

在深入應用之前,我們先快速回顧一下堆的關鍵特性,這將是理解后續內容的基礎。

  • 結構:堆在邏輯上是一棵完全二叉樹,在物理存儲上通常使用數組來實現,從而節省了指針開銷,并能方便地通過索引計算父子節點關系。
  • 特性
    • 最大堆 (Max-Heap):任意節點的值都不小于其子節點的值。堆頂元素是整個堆中的最大值。
    • 最小堆 (Min-Heap):任意節點的值都不大于其子節點的值。堆頂元素是整個堆中的最小值。
  • 核心操作
    • 插入 (Sift Up / 上浮):將新元素添加到數組末尾,然后通過與其父節點比較,一路向上調整,直到滿足堆的性質。
    • 刪除堆頂 (Sift Down / 下沉):將數組末尾元素替換堆頂,然后通過與其子節點比較,一路向下調整,直到滿足堆的性質。

上圖展示了一個最大堆及其在數組中的存儲方式。父節點索引為 i,其左子節點為 2*i+1,右子節點為 2*i+2

二、堆排序 (Heap Sort):原地排序的藝術

堆排序是一種利用堆結構特性設計的選擇排序。它的核心思想是:首先將待排序的序列構建成一個最大堆,然后依次將堆頂元素(當前最大值)與數組末尾元素交換,并縮小堆的范圍,再對新的堆頂進行下沉操作以維持最大堆性質。 重復此過程,直到所有元素都被排序。

整個過程分為兩大步:建堆排序

2.1 第一步:原地建堆 (Heapify)

給定一個無序數組,如何最高效地將其轉換為一個堆?一個直觀的想法是創建一個空堆,然后將數組中的元素逐個插入,時間復雜度為 O(nlog?n)O(n \log n)O(nlogn)。但存在一種更高效的原地建堆方法,其時間復雜度僅為 O(n)O(n)O(n)

該方法的核心思想是:從最后一個非葉子節點開始,自后向前、自下而上地對每個節點執行“下沉 (Sift Down)”操作

  • 為什么從最后一個非葉子節點開始? 因為葉子節點自身已經是一個合法的堆(沒有子節點),無需調整。
  • 為什么自下而上? 因為當調整一個節點時,我們保證了它的子樹已經滿足堆的性質,這樣只需將當前節點“下沉”到正確位置即可。
(1)建堆過程圖解

假設我們有數組 [4, 10, 3, 5, 1, 2],我們要將其構建成一個最大堆。

  1. 定位:數組長度 n=6。最后一個非葉子節點的索引是 floor(n/2) - 1 = floor(6/2) - 1 = 2。該節點的值是 3
  2. 從索引 2 (值為 3) 開始下沉:節點 3 的子節點是 23 > 2,滿足最大堆性質,無需交換。
  3. 從索引 1 (值為 10) 開始下沉:節點 10 的子節點是 5110 大于它們,滿足性質,無需交換。
  4. 從索引 0 (值為 4) 開始下沉:節點 4 的子節點是 1034 < 10,不滿足最大堆性質。將 4 與其較大的子節點 10 交換。交換后,數組變為 [10, 4, 3, 5, 1, 2]。被交換下去的 4 成為索引為 1 的節點,它沒有子節點了(或者說它的新子節點51都比它小),下沉結束。

至此,建堆完成。最終的堆結構如下:

10
4
3
5
1
2

最終數組為 [10, 4, 3, 5, 1, 2]

2.2 第二步:排序階段

建堆完成后,數組的第一個元素 arr[0] 就是當前序列的最大值。排序階段的步驟如下:

  1. 將堆頂元素 arr[0] 與當前堆的最后一個元素 arr[i] 交換。此時,最大值被放到了數組的正確位置(末尾)。
  2. 將堆的大小減一(邏輯上將已排序的元素排除在外)。
  3. 對新的堆頂 arr[0] 執行“下沉”操作,以恢復最大堆的性質。
  4. 重復上述步驟,直到堆中只剩一個元素。
(1)排序過程圖解

繼續上面的例子,數組為 [10, 4, 3, 5, 1, 2],堆大小 heapSize = 6

  1. 第一次迭代

    • 交換 arr[0] (10) 和 arr[5] (2)。數組變為 [2, 4, 3, 5, 1, 10]
    • heapSize 減為 510 已被排序。
    • 對新堆頂 2 執行下沉。2 和其子節點 43 比較,與較大的 4 交換。數組變為 [4, 2, 3, 5, 1, 10]2 再與其新子節點 5 比較,與 5 交換。數組變為 [4, 5, 3, 2, 1, 10]。等等,下沉邏輯應該是與左右子節點中較大的那個交換。重新來:
    • 對新堆頂 2 執行下沉。子節點 434 更大。24 交換,數組變為 [4, 2, 3, 5, 1, 10]2 到了索引 1,它的子節點是 515 更大。25 交換。數組變為 [4, 5, 3, 2, 1, 10]。等等,邏輯錯了。下沉應該在交換后的子樹中進行。

    讓我們重新梳理下沉邏輯:

    • 堆頂 2,子節點 4 (索引1) 和 3 (索引2)。4 > 2,交換。數組變為 [4, 4, 3, 5, 1, 10]2 到了索引 1
    • arr[0] (2) 與 arr[5] (10) 交換 -> [2, 4, 3, 5, 1, 10]
    • arr[0] (2) 在 heapSize=5 的范圍內下沉。
    • i=0,左子 1 (值4),右子 2 (值3)。arr[1]>arr[2],所以和 arr[1] 比較。arr[0] < arr[1],交換 arr[0]arr[1]
    • 數組變為 [4, 2, 3, 5, 1, 10]
    • 現在 2 到了索引 1i=1,左子 3 (值5),右子 4 (值1)。arr[3]>arr[4],所以和 arr[3] 比較。arr[1] < arr[3],交換 arr[1]arr[3]
    • 數組變為 [4, 5, 3, 2, 1, 10]
    • 現在 2 到了索引 3,它沒有子節點了,下沉結束。
    • 第一次迭代后,堆部分為 [5, 4, 3, 2, 1],數組為 [5, 4, 3, 2, 1, 10]
  2. 第二次迭代

    • heapSize = 5。交換 arr[0] (5) 和 arr[4] (1)。數組變為 [1, 4, 3, 2, 5, 10]
    • heapSize 減為 4510 已被排序。
    • 對新堆頂 1 執行下沉。與 4 交換 -> [4, 1, 3, 2, 5, 10]1 再與 2 交換 -> [4, 2, 3, 1, 5, 10]
    • 第二次迭代后,堆部分為 [4, 2, 3, 1],數組為 [4, 2, 3, 1, 5, 10]
  3. … 以此類推,直到整個數組有序:[1, 2, 3, 4, 5, 10]

2.3 代碼實現 (Java)

public class HeapSort {public void sort(int[] arr) {if (arr == null || arr.length < 2) {return;}// 1. 構建最大堆 (從最后一個非葉子節點開始)// 數組長度為 n,則最后一個非葉子節點索引為 n/2 - 1for (int i = arr.length / 2 - 1; i >= 0; i--) {siftDown(arr, i, arr.length);}// 2. 排序階段for (int i = arr.length - 1; i > 0; i--) {// 將堆頂元素(最大值)與末尾元素交換swap(arr, 0, i);// 交換后,堆大小減 1,并對新的堆頂進行下沉操作siftDown(arr, 0, i);}}/*** 下沉操作 (調整為最大堆)* @param arr 待調整的數組* @param index 要下沉的節點索引* @param heapSize 堆的大小(不是數組的長度)*/private void siftDown(int[] arr, int index, int heapSize) {int parentValue = arr[index]; // 先保存父節點的值,用于最后賦值// 循環直到當前節點沒有左子節點 (2*index + 1 >= heapSize)for (int childIndex = 2 * index + 1; childIndex < heapSize; childIndex = 2 * childIndex + 1) {// 如果存在右子節點,并且右子節點比左子節點大,則定位到右子節點if (childIndex + 1 < heapSize && arr[childIndex + 1] > arr[childIndex]) {childIndex++;}// 如果父節點比最大的子節點還大,則無需下沉,直接跳出if (parentValue >= arr[childIndex]) {break;}// 否則,將子節點的值賦給父節點,繼續向下比較arr[index] = arr[childIndex];index = childIndex; // 更新 index 為子節點索引,準備下一輪循環}// 循環結束后,將最初的父節點值放到最終的位置arr[index] = parentValue;}private void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
}

2.4 性能分析

  • 時間復雜度
    • 建堆過程:O(n)O(n)O(n)。這是一個精確的結論,雖然看起來是 n/2n/2n/2siftDown,但大部分 siftDown 的路徑都很短。
    • 排序過程:進行了 n?1n-1n?1 次交換和 siftDown 操作。每次 siftDown 的時間復雜度是 O(log?n)O(\log n)O(logn)。所以這部分是 O(nlog?n)O(n \log n)O(nlogn)
    • 總時間復雜度O(n)+O(nlog?n)=O(nlog?n)O(n) + O(n \log n) = O(n \log n)O(n)+O(nlogn)=O(nlogn)
  • 空間復雜度O(1)O(1)O(1)。堆排序是原地排序,只需要常數級別的額外空間用于交換。
  • 穩定性:堆排序是不穩定的。在 siftDown 和交換堆頂的過程中,相同大小的元素的相對順序可能會被改變。

三、Top K 問題:海量數據處理的利器

Top K 問題是一個非常經典的面試題和工程問題,其描述通常是:從 N 個數據中,找出最大(或最小)的 K 個數,其中 N 的數量級可能非常大(如百萬、十億),無法一次性加載到內存中。

3.1 問題定義與挑戰

例如,從 10 億個搜索日志中,找出點擊量最高的 10 個搜索詞。

  • 挑戰
    1. 內存限制:無法將 10 億條數據全部加載到內存中進行排序。
    2. 效率要求:即使內存足夠,對全部數據排序(時間復雜度 O(nlog?n)O(n \log n)O(nlogn))也是一種巨大的浪費,因為我們只關心前 K 個元素。

3.2 解決方案:小頂堆的妙用

堆是解決 Top K 問題的完美工具。這里有一個非常巧妙的設計:

要求解 “Top K 大” 的問題,我們使用一個容量為 K 的 “最小堆”。

(1)算法流程
  1. 創建一個大小為 K 的最小堆(優先隊列)。
  2. 遍歷數據源(N 個數據):
    a. 首先,讀取前 K 個元素,直接全部放入最小堆中。此時堆被填滿。
    b. 繼續讀取第 K+1 個元素 x
    * 將其與堆頂元素 heap_top(當前已發現的 K 個元素中的最小值)進行比較。
    * 如果 x > heap_top,說明 x 有資格進入 Top K 行列,而 heap_top 則被淘汰。具體操作是:彈出堆頂,并將 x 插入堆中
    * 如果 x <= heap_top,說明 x 連當前 Top K 的“門檻”都達不到,直接忽略。
  3. 遍歷完所有 N 個數據后,堆中剩下的 K 個元素,就是我們要求解的 Top K 大的元素。
(2)為什么用最小堆?

最小堆的堆頂始終是堆中最小的元素。這個堆的作用就像一個“擂臺”,堆頂就是“擂主”,只不過這個擂主是“守門員”,是當前 Top K 榜單中實力最弱的那個。任何新的挑戰者,只需要和這個最弱的“守門員”比試即可。如果連最弱的都打不過,那肯定沒資格上榜。如果打得過,就把它替換掉,成為新的(可能也是暫時的)“守門員”。

這種設計保證了堆中始終維護著當前為止遇到的 K 個最大元素,而堆頂就是這 K 個元素中的最小值,即 Top K 的“準入門檻”。

3.3 代碼實現 (Java)

在 Java 中,PriorityQueue 默認就是最小堆,非常適合用來解決此問題。

import java.util.PriorityQueue;public class TopKFinder {/*** 找出數組中最大的 K 個數* @param arr 數據源數組* @param k 需要找出的元素數量* @return 包含最大 K 個數的數組*/public int[] findTopK(int[] arr, int k) {if (arr == null || arr.length < k || k <= 0) {// 返回空數組或拋出異常,根據業務需求決定return new int[0];}// 創建一個最小堆,容量為 k// PriorityQueue 在 Java 中默認是最小堆PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);// 遍歷數組for (int num : arr) {if (minHeap.size() < k) {// 如果堆未滿,直接添加minHeap.offer(num);} else if (num > minHeap.peek()) {// 如果當前元素大于堆頂元素(當前 K 個中的最小值)// 彈出堆頂minHeap.poll();// 將當前元素入堆minHeap.offer(num);}}// 將堆中元素轉換為數組返回int[] result = new int[k];for (int i = 0; i < k; i++) {result[i] = minHeap.poll();}return result;}
}

3.4 復雜度分析與擴展

(1)復雜度分析
  • 時間復雜度O(nlog?k)O(n \log k)O(nlogk)
    • 我們遍歷了 N 個元素。
    • 對于每個元素,最多進行一次堆操作(offerpoll+offer)。堆的大小始終不超過 K,所以每次堆操作的時間復雜度是 O(log?k)O(\log k)O(logk)
    • 因此,總時間復雜度是 O(nlog?k)O(n \log k)O(nlogk)。當 K 遠小于 N 時,這比 O(nlog?n)O(n \log n)O(nlogn) 高效得多。
  • 空間復雜度O(k)O(k)O(k)。我們需要一個大小為 K 的堆來存儲臨時的 Top K 元素。
(2)舉一反三
  • 如何求解 “Top K 小”?
    • 思路完全相反:使用一個大小為 K 的最大堆
    • 遍歷數據,如果新元素比堆頂(當前 K 個中的最大值)還小,就替換掉堆頂。
    • 時間復雜度依然是 O(nlog?k)O(n \log k)O(nlogk),空間復雜度是 O(k)O(k)O(k)

四、總結

本文我們深入探討了堆的兩種核心應用,將理論知識轉化為了強大的編程武器。

  1. 堆排序 (Heap Sort):一種性能優秀的原地排序算法。其核心步驟是先用 O(n)O(n)O(n) 的時間復雜度原地建堆,然后通過 n?1n-1n?1 次“交換堆頂與末尾元素”并“下沉”的操作完成排序,總時間復雜度為 O(nlog?n)O(n \log n)O(nlogn)
  2. 堆排序特性:時間復雜度穩定在 O(nlog?n)O(n \log n)O(nlogn),空間復雜度為 O(1)O(1)O(1),但它是一種不穩定排序
  3. Top K 問題:解決“從海量數據中找出最大/最小的 K 個數”問題的經典場景。堆提供了極其高效的解決方案。
  4. Top K 解法精髓:求解 Top K ,使用容量為 K 的最小堆;求解 Top K ,使用容量為 K 的最大堆。這種“反向思維”是關鍵。該算法的時間復雜度為 O(nlog?k)O(n \log k)O(nlogk),空間復雜度為 O(k)O(k)O(k),完美契合了大數據、低內存的場景需求。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/98039.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/98039.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/98039.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

企業即時通訊保障企業通訊安全,提升企業部門協作效率

在當今數字化轉型的大潮中&#xff0c;企業即時通訊軟件已從單純的溝通工具&#xff0c;逐步演變為保障企業數據安全的核心基礎設施。吱吱企業即時通訊軟件通過“私有化部署全流程加密”的雙重機制&#xff0c;為企業構建了一套集“通訊安全”與“部門協作”于一體的數字化解決…

《華為變革法:打造可持續進步的組織》讀書筆記

推薦序一&#xff1a;變革是企業活下去的基礎&#xff08;胡彥平&#xff09;華為前常務副總裁、變革指導委員會成員胡彥平在序言中強調&#xff0c;企業存續的核心命題是應對不確定性&#xff0c;而變革能力是破解這一命題的唯一答案。他以華為 30 余年的發展歷程為例&#xf…

第二篇:排序算法的簡單認識【數據結構入門】

排序算法的分類標準 時間復雜度分類 a. 簡單排序算法&#xff1a;時間復雜度O(n)&#xff0c;冒泡排序、選擇排序、插入排序&#xff1b; b. 高級排序算法&#xff1a;時間復雜度O(n logn)&#xff0c;快速排序、歸并排序、堆排序&#xff1b; c. 線性排序算法&#xff1a;時間…

快速掌握Dify+Chrome MCP:打造網頁操控AI助手

你是否曾經希望那些強大的開源大模型能更貼合你的專業領域&#xff0c;或者學會模仿你的行文風格&#xff1f;其實&#xff0c;實現這個目標的關鍵就在于“微調”。曾幾何時&#xff0c;微調模型是大公司的專屬游戲——動不動就需要幾十張GPU和復雜的分布式訓練技術。 而現在&…

單詞記憶-輕松記憶10個實用英語單詞(15)

1. repaint含義&#xff1a;重新油漆 讀音標注&#xff1a;/?ri??pe?nt/ 例句&#xff1a;We need to repaint the walls after the repairs. 譯文&#xff1a;修理完成后需要重新粉刷墻壁。 衍生含義&#xff1a;重新繪制&#xff08;圖像場景&#xff09;&#xff1b;翻新…

visual studio快捷鍵

1.visual studio代碼格式化快捷鍵 1.CtrlA&#xff08;全選&#xff09; 2.CtrlK 3.CtrlF2.多行注釋 1.Ctrlk 2.Ctrlc2.多行取消注釋 1.Ctrlk 2.Ctrlu

Django全棧班v1.04 Python基礎語法 20250913 下午

練習&#xff1a;個人信息收集器 任務&#xff1a;創建一個個人信息收集和展示程序 要求&#xff1a; 收集用戶的姓名&#xff0c;年齡&#xff0c;城市&#xff0c;愛好驗證年齡輸入&#xff0c;必須是正數格式化輸出用戶信息計算用戶出生年份 name input("請輸入姓名&a…

學習海康VisionMaster之字符缺陷檢測

前言&#xff1a;差不多三個月沒更新了&#xff0c;天天碼代碼&#xff0c;實在是太忙了&#xff0c;有時候也在想這么忙到底是不是工作方法的問題&#xff0c;怎么樣才能變成大師呢&#xff01; 一&#xff1a;進一步學習 今天學習下VisionMaster中的字符缺陷檢測&#xff1…

若依4.8.1打包war后在Tomcat無法運行,404報錯的一個解決方法

背景 最近使用若依4.8.1進行二次開發&#xff0c;接著嘗試打包成war包進行部署&#xff0c;結果出現了404&#xff0c;提示“HTTP狀態 404 - 未找到&#xff0c;請求的資源[/ruoyi-admin/]不可用”&#xff0c;翻了網上的教程&#xff0c;包括看了官方的解疑都沒有說到該情況。…

華清遠見25072班網絡編程學習day6

重點內容&#xff1a;數據庫基本概念:數據&#xff08;Data&#xff09;&#xff1a;能夠輸入計算機并能被計算機程序識別和處理的信息集合數據 &#xff08;Database&#xff09;數據庫是在數據庫管理系統管理和控制之下&#xff0c;存放在存儲介質上的數據集合重要概念&#…

機器學習-網絡架構搜索

Neural Architecture Search&#xff08;NAS&#xff09; 一個神經網絡有不同類型的超參數 拓撲結構&#xff1a;resnet&#xff0c;mobilenet 單獨層&#xff1a;核大小&#xff0c;卷積層的通道&#xff0c;輸出隱藏單元的個數NAS自動設計神經網絡 如何設計搜索空間 如何探索…

云手機在辦公領域中自動化的應用

云手機在辦公自動化領域正逐漸展現出強大的潛力&#xff0c;以下是其在辦公中自動化應用的多方面介紹&#xff1a;企業借助云手機搭載的辦公軟件&#xff0c;可實現文檔處理自動化&#xff0c;對于重復性文檔任務&#xff0c;如制作每月固定格式的銷售報告、財務報表等&#xf…

c++多線程(3)------休眠函數sleep_for和sleep_until

操作系統&#xff1a;ubuntu22.04 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 這兩個函數都定義在 頭文件中&#xff0c;屬于 std::this_thread 命名空間&#xff0c;用于讓當前線程暫停執行一段時間。函數功能sleep_for(rel_time)讓當前線程休眠一段相對時間&…

Intel RealSense D455深度相機驅動安裝與運行

Intel RealSense D455深度相機安裝過程遇到過一些報錯&#xff0c;所以記錄一下安裝過程&#xff01;&#xff01;&#xff01;以后方便回顧。 1.安裝最新的IntelRealSense SDK2.0 (1) 注冊服務器的公鑰 sudo apt-get update && sudo apt-get upgrade && su…

從異步到半同步:全面解讀MySQL復制的數據一致性保障方案

MySQL 主從復制&#xff08;Replication&#xff09;是其最核心的高可用性和擴展性功能之一。它的原理是將一個 MySQL 實例&#xff08;稱為主庫 Master&#xff09;的數據變更&#xff0c;自動同步到另一個或多個 MySQL 實例&#xff08;稱為從庫 Slave&#xff09;的過程。下…

PostgreSQL GIN 索引揭秘

文章目錄什么是GIN Index?示例場景GIN Index的原理GIN Index結構MetapageEntriesLeaf PagesEntry page 和 Leaf page 的關系Posting list 和posting tree待處理列表&#xff08;Pending List&#xff09;進階解讀GIN index索引結構總結什么是GIN Index? GIN (Generalized In…

開源多模態OpenFlamingo橫空出世,基于Flamingo架構實現圖像文本自由對話,重塑人機交互未來

注&#xff1a;此文章內容均節選自充電了么創始人&#xff0c;CEO兼CTO陳敬雷老師的新書《GPT多模態大模型與AI Agent智能體》&#xff08;跟我一起學人工智能&#xff09;【陳敬雷編著】【清華大學出版社】 清華《GPT多模態大模型與AI Agent智能體》書籍配套視頻課程【陳敬雷…

電子衍射模擬:基于GPU加速的MATLAB/Julia實現

點擊 “AladdinEdu&#xff0c;同學們用得起的【H卡】算力平臺”&#xff0c;注冊即送-H卡級別算力&#xff0c;80G大顯存&#xff0c;按量計費&#xff0c;靈活彈性&#xff0c;頂級配置&#xff0c;學生更享專屬優惠。 引言&#xff1a;電子衍射模擬的重要性與計算挑戰 電子…

easyExcel動態應用案例

代碼鏈接&#xff1a;https://download.csdn.net/download/ly1h1/919402991.案例說明&#xff1a;1.1.導入功能導入數據實現轉換成 List<List<String>> headers和 List<List<String>> datas&#xff0c;后續補充可以與數據模型注解結合&#xff0c;形…

【數據結構入門】排序算法(5):計數排序

目錄 1. 比較排序和非比較排序 2. 計數排序的原理 2.1 計數排序的弊端 3.代碼復現 3.1 代碼分析 3.2 排序核心 3.3 時間、空間復雜度 1. 比較排序和非比較排序 比較排序是根據排序元素的具體數值比較來進行排序&#xff1b;非比較排序則相反&#xff0c;非比較排序例如&…