01數據結構-交換排序

01數據結構-交換排序

  • 1.冒泡排序
    • 1.1基礎冒泡排序
      • 1.1.1基礎冒泡排序代碼實現
    • 1.2冒泡排序的一次優化
      • 1.2.1冒泡排序的第一次優化代碼實現
    • 1.3冒泡排序的二次優化
      • 1.3.1 冒泡排序的二次優化代碼實現
  • 2.快速排序
    • 2.1雙邊循環法
      • 2.1.1雙邊循環法的代碼實現
    • 2.2單邊循環法
      • 2.2.1單邊循環法代碼實現

1.冒泡排序

1.1基礎冒泡排序

算法思想

冒泡排序是最簡單的排序算法了。冒泡排序通過不斷地比較兩個相鄰元素,將較大的元素交換到右邊(升序),從而實現排序。那我們直接看例子。

在這里插入圖片描述
我們對數組 [5,1,4,2,8,4] ,采用冒泡排序進行排序,注意這里的兩個 4 的顏色是不同
的,主要是為了區分兩個不同的 4 ,進而解釋冒泡排序算法的穩定性問題。

第一輪冒泡排序:第一步:比較 5 和 1 ,5 > 1,則交換 5 和 1 的位置:
在這里插入圖片描述
第二步,比較 5 和 4,5 > 4,交換 5 和 4 的位置:
在這里插入圖片描述
第三步:比較 5 和 2 ,5 > 2,交換 5 和 2 的位置:
在這里插入圖片描述
第四步:比較 5 和 8 ,5 < 8 ,不交換
在這里插入圖片描述
第五步:比較 8 和 4 , 8 > 4,交換 8 和 4 :
在這里插入圖片描述
此刻我們獲得數組當中最大的元素 8 ,使用橘?色進行標記:

第一輪冒泡結束,最大的元素8到了最后,然后對于前面5個元素,進行第二輪冒泡將第二大的數據放在右邊。

最終結果:在這里插入圖片描述
事實上第二階段結束,整個數組已經有序了,但是對于冒泡排序而言并不知道,她還需要通過第三階段的比較操作進行判斷。

對于冒泡排序算法而言,她是通過判斷整個第三階段的比較過程中是否發生了交換來確定數組是否有序的,顯然上面的過程中沒有交換操作,冒泡排序也就知道了數組有序,整個算法執行結束。

1.1.1基礎冒泡排序代碼實現

void bubbleSortV1(SortTable *table) {for (int i = 0; i < table->length-1; ++i) {for (int j = 0; j < table->length-1-i; ++j) {if (table->data[j].key > table->data[j+1].key) {swapElement(&table->data[j+1],&table->data[j]);}}}
}

這里面的swapElement是我測試框架里的代碼,作用是交換兩個元素的位置,外層循環用于把最大的元素冒到右邊去,內層循環從0開始length-1-i,才能完整掃描未排好區間,實現“冒泡”效果。注意第二層循環的上界,最右邊 i 個元素已經是有序區,不需要再碰,所以上界寫成 table->length-1-i。

來測一下:

#include"bubbleSort.h"
void test01() {int n=100000;SortTable *table1=generateRandomArray(n,0,1+5000);testSort("bubbleSortV1",bubbleSortV1,table1);releaseSortTable(table1);
}int main() {test01();return 0;
}

結果:

D:\work\DataStruct\cmake-build-debug\04_Sort\SwapSort.exe
bubbleSortV1 cost time: 20.063000s.進程已結束,退出代碼為 0

可以看到同樣是十萬個元素上一節課中的插入排序幾秒鐘就能完成,但是這里的冒泡排序需要20幾秒,原因在于無論數據是否已經有序,都要跑完全部 n-1 趟且交換次數往往也很高,我們就在想能不能優化一下呢?

1.2冒泡排序的一次優化

這里我們增加了一個標識數組是否有序 ,當冒泡排序過程中沒有交換操作時,swapped = false ,也意味著數組有序;否則數組無序繼續進行冒泡排序。不要小看這個變量奧,因為這個變量,當數組有序的時候,冒泡排序的時間復雜度將降至 O(n)(因為其只需要執行一遍內層的 for 循環就可以結束冒泡排序),沒有這個變量,數組有序也需要O(n2)的時間復雜度。講直白點因為冒泡排序始終把大的元素冒到右邊,可以當作右邊始終是有序的,當發現某一輪不需要交換,那么就說明已經有序,退出循環。

1.2.1冒泡排序的第一次優化代碼實現

void bubbleSortV2(SortTable* table) {for (int i = 0; i < table->length - 1; ++i) {int isSorted = 1;for (int j = 0; j < table->length - 1 - i; ++j) {if (table->data[j].key > table->data[j + 1].key) {swapElement(&table->data[j + 1], &table->data[j]);isSorted = 0;}}if (isSorted) {break;}}
}

來測一下:

#include"bubbleSort.h"
void test01() {int n=10000;SortTable *table1=generateRandomArray(n,0,1+5000);SortTable *table2=copySortTable(table1);testSort("bubbleSortV1",bubbleSortV1,table1);testSort("bubbleSortV2",bubbleSortV2,table2);releaseSortTable(table1);releaseSortTable(table2);
}int main() {test01();return 0;
}

結果:

D:\work\DataStruct\cmake-build-debug\04_Sort\SwapSort.exe
bubbleSortV1 cost time: 0.130000s.
bubbleSortV2 cost time: 0.130000s.進程已結束,退出代碼為 0

這里看不出來精度差是因為我們產生的數據太隨機了,意義不太大,但是這種思想要學會。

1.3冒泡排序的二次優化

一次優化是為了避免數組有序的情況下,繼續進行判斷操作的。那么二次優化又為了什么呢 ?

我們看下面的例子。
在這里插入圖片描述
經過一次冒泡后,我們會注意到一個問題,但是我們注意到,數組數組中的 [5,6,8] 本身已經有序,而對于有序的部分進行比較是沒有意義的,相當于在白白浪費資源,有沒有什么辦法減少這樣的比較次數呢?

換句話說,是否能夠確定出已經有序部分和無序部分的邊界呢?

答案當然是肯定的,這個邊界就是第一趟冒泡排序的過程中最后一次發生交換的位置 j :也就是 1 和 4 發生交換之后,4 和 5 沒有發生交換,此時 1 之后的元素為有序。

第一步:4 和 2比較,4 > 2 ,交換 4 和 2 ,將 LastSwappedIndex = 0;

第二步:4 和 1 比較,4 > 1,交換 4 和 1, LastSwappedIndex = 1 ;

第三步:比較 4 和 5 , 4 < 5,不交換, lastSwappedIndex 也不更新;

第四步:比較 5 和 6 ,不交換, lastSwappedIndex 也不更新;

第五步:比較 6 和 8 ,不交換, lastSwappedIndex 也不更新;

第一趟冒泡排序結束了,我們把 LastSwappedIndex放在了4這里,相當于是一個擋板
在這里插入圖片描述
來看第二趟冒泡排序,此時 j 的 取值將從 j = 0 到 j = lastSwappedIndex ,第一步:比較 2 和 1 ,2 > 1,交換,lastSwappedIndex = 0 ,并且第二趟冒泡也就結束了,也就說我們節省了 從 2 到 6的比較操作;

最后再來一趟冒泡排序,發現沒有任何交換,所以冒泡排序結束。

相比于一次優化的實現方式,二次優化的實現方式進一步減少了不必要的執行次數,兩種優化后的實現方式需要冒泡排序的趟數是一樣的,本質上沒有什么區別。所以即使對于一個有序的數組,兩種方式的時間復雜度都是O(n)

1.3.1 冒泡排序的二次優化代碼實現

/* 引入newIndex標記交換的索引位置,下次冒泡的時候結束位置就是newIndex */
void bubbleSortV3(SortTable* table) {int newIndex;int n = table->length;do {newIndex = 0;for (int i = 0; i < n - 1; ++i) {if (table->data[i].key > table->data[i + 1].key) {swapElement(&table->data[i + 1], &table->data[i]);newIndex = i + 1;}}//更新擋板位置n = newIndex;} while (newIndex > 0);
}

注意要把i+1賦給newIndex,如果賦的是i由于我們for循環中循環條件是n-1就會少一個數的排序,如圖假設newIndex在6,本來該是2,1,4,5冒泡排序,但是由于newIndex-1賦值給n,n-1為循環條件就會導致5沒有參與冒泡排序。
在這里插入圖片描述

來測一下:

#include"bubbleSort.h"
void test01() {int n=10000;SortTable *table1=generateRandomArray(n,0,1+5000);SortTable *table2=copySortTable(table1);SortTable *table3=copySortTable(table1);testSort("bubbleSortV1",bubbleSortV1,table1);testSort("bubbleSortV2",bubbleSortV2,table2);testSort("bubbleSortV3",bubbleSortV3,table3);releaseSortTable(table1);releaseSortTable(table2);
}int main() {test01();return 0;
}

結果:

D:\work\DataStruct\cmake-build-debug\04_Sort\SwapSort.exe
bubbleSortV1 cost time: 0.129000s.
bubbleSortV2 cost time: 0.131000s.
bubbleSortV3 cost time: 0.125000s.進程已結束,退出代碼為 0

看的出來第二次優化會比前兩次是要好一點的

2.快速排序

找pos犄點,pos是索引號,pos對應的值的左邊都是比pos值小的,pos對應的值的右邊都是比pos值大的,這樣咱們就把要排序的序列分成兩部分,我們拿排序的最差時間復雜度來說,假設左邊部分有x個元素,右邊部分為y個,那么分別排序這兩個序列的時間復雜度為x2+y2而沒有拆分前的時間復雜度是x2+y2+2xy,同理在左邊部分的序列又可以找一個犄點,右邊部分的序列也可以找一個犄點。如圖所示:
如果我們每次的犄點都是均分,一直分下去最后的時間復雜度為nlogn。找犄點的方法有兩種:雙邊循環法,單邊循環法。
在這里插入圖片描述

2.1雙邊循環法

所謂雙邊就是兩個指針在左右,用這兩個指針從數組兩端向中間“夾擊”,隨機初始化一個犄點把小于犄點的元素換到左邊、大于犄點的元素換到右邊,直到兩指針相遇。初始時的犄點是隨機取得,這里我就把它放在數組得最左邊,如圖:
在這里插入圖片描述
來看右邊right,看右邊的指針是否比初始時犄點值大,發現是49沒問題,right往左邊走一步來到27,發現27比38小,說明應該在犄點的左邊;left最初指向38,可以認為大于等于初始時犄點的值,left往右走一步來到49,49比38大,說明應該在犄點的右邊,我們應該把兩個值交換位置,注意一定要先操作右邊,找到第一個比我們最初設定的犄點值小的數,如果暫時沒有,就先一直操作右邊right–,保證右邊先找到,再去操作左邊,找到第一個比我們最初設定的犄點值大的數,如果暫時沒有,就再一直操作右移,兩者都找到了就交換位置如圖
在這里插入圖片描述
right往右一直走到13發現比38小了,left往左邊走,相碰了,我們找到了犄點所在位置,我們就交換38和13的位置。如圖,犄點左邊的值確實比犄點的值小,犄點右邊的值確實比犄點的值大,同理在新分出來的左,右邊依然可以采取這種方法直到left和right相碰,很明顯這是一種遞歸的是方法,下面我們來看怎么實現代碼
在這里插入圖片描述

2.1.1雙邊循環法的代碼實現

static int partitionDouble(SortTable *table, int startIndex, int endIndex) {int pivot = startIndex;int left = startIndex;int right = endIndex;// 隨機將startIndex和后續的一個隨機索引指向的元素進行交換while (left != right) {while (left < right && table->data[right].key > table->data[pivot].key) { right--; }while (left < right && table->data[left].key <= table->data[pivot].key) { left++; }if (left < right) {swapElement(&table->data[right], &table->data[left]);}}swapElement(&table->data[pivot], &table->data[left]);return left;
}// 用遞歸思想實現[start, end]區間的排序
static void quickSort1(SortTable *table, int startIndex, int endIndex) {if (startIndex >= endIndex) {return;}// 找到犄點int pivot = partitionDouble(table, startIndex, endIndex);quickSort1(table, startIndex, pivot - 1);quickSort1(table, pivot + 1, endIndex);
}void quickSortV1(SortTable* table) {quickSort1(table, 0, table->length - 1);
}

我們先來看大框架:static void quickSort1(SortTable *table, int startIndex, int endIndex);我們需要通過找犄點把整個序列按左邊小右邊大的思路一直分下去,所以我們需要寫一個找犄點的函數,找到后開始遞歸,把新的左右兩邊的序列再次通過犄點分成左右兩份,但是我們不能無限遞歸下去,所以我們需要寫一個遞歸終止條件,只要子區間長度 ≤ 1,即 startIndex >= endIndex,就已經有序,無需再排,然后我們在
void quickSortV1(SortTable *table)調用這個函數,并賦值starIndex和endIndex。

接下來看找犄點的代碼,我們把最初的基準pivot放到startIndex上,當左邊left小于等于右邊right的時候,開始先對右邊處理邏輯,再對左邊處理邏輯。有人可能會問,為什么外層循環已經有left<=right,內層循環為什么還要加呢?當出現如下圖所示情況時如果在內層while循環中沒有left<right的話,right就會一直減。同理處理左邊的時候也需要加上left<right這個條件。外層循環只是控制分區過程是否繼續,內層循環防止單指針移動時越界/交叉,確保每次移動后仍滿足指針有效性。前面這兩是必須的,if中的left<right避免指針重合時的無效交換,推薦使用
在這里插入圖片描述
來測試一下:

#include"bubbleSort.h"
#include"quickSort.h"
void test02() {int n = 10000;SortTable *table1 = generateRandomArray(n, 0, n + 5000);SortTable *table2 = copySortTable(table1);testSort("bubbleSortV3", bubbleSortV3, table1);testSort("quick SortV1", quickSortV1, table2);releaseSortTable(table1);}int main() {test02();return 0;
}

結果:

D:\work\DataStruct\cmake-build-debug\04_Sort\SwapSort.exe
bubbleSortV3 cost time: 0.131000s.
quick SortV1 cost time: 0.000000s.進程已結束,退出代碼為 0

能夠看出快速排序的時間比冒泡排序的時間快的多,接下來看單邊循環法

2.2單邊循環法

我們依舊需要一個犄點,犄點的左值小于犄點,犄點的右值大于犄點,只不過我們用一個指針來處理結構,我們把這個犄點重新起個名字叫mark,幫忙維護整個序列的指針我們先稱為i,依舊先把序列的最左邊當作我們的犄點。如下圖初始時
在這里插入圖片描述
我們的i不斷地往右邊走,當走到i對應的值大于基礎值38的時候我們就不管,當發現我們的i對應的值小于了38時,我們mark往右邊走一位,然后交換mark指向的值和i指向的值,為什么mark要先往右邊走一位呢,因為最終我們38會和我們最終確定的mark交換位置,我們需要保證最后交換后的mark的左邊全部小于mark對應的值。反過來說,我們找到了對應i的值小于了基礎值38后,mark要往后面走一位給我們找到的數據空一格位置出來,我們走到13的時候發現13比38小,mark往右邊移動一位,和i指向的值交換

在這里插入圖片描述
下一次找到比38小的數是27,我們依舊采用這樣的思路如圖所示:
在這里插入圖片描述
i繼續往后面走,發現mark的右邊已經全部比38大了,這時我們交換38和mark指向的27的位置即可。
在這里插入圖片描述

2.2.1單邊循環法代碼實現

static int partitionSingle(SortTable *table, int startIndex, int endIndex) {keyType tmpValue = table->data[startIndex].key;//備份一下第一個基準值int mark = startIndex;//假設第一個是犄點for (int i = startIndex + 1; i <= endIndex; i++) {if (table->data[i].key < tmpValue) {mark++;swapElement(&table->data[i], &table->data[mark]);}}swapElement(&table->data[startIndex], &table->data[mark]);return mark;
}static void quickSort2(SortTable *table, int startIndex, int endIndex) {if (startIndex >= endIndex) {return;}// 找到犄點int pivot = partitionSingle(table, startIndex, endIndex);quickSort2(table, startIndex, pivot - 1);quickSort2(table, pivot + 1, endIndex);
}void quickSortV2(SortTable* table) {quickSort2(table, 0, table->length - 1);
}

這里的邏輯就是我上述說的邏輯。

#include"bubbleSort.h"
#include"quickSort.h"void test02() {int n = 10000;SortTable *table1 = generateRandomArray(n, 0, n + 5000);SortTable *table2 = copySortTable(table1);SortTable *table3 = copySortTable(table1);testSort("bubbleSortV3", bubbleSortV3, table1);testSort("quick SortV1", quickSortV1, table2);testSort("quick SortV2", quickSortV2, table3);releaseSortTable(table1);releaseSortTable(table2);releaseSortTable(table3);
}int main() {test02();return 0;
}

結果:

D:\work\DataStruct\cmake-build-debug\04_Sort\SwapSort.exe
bubbleSortV3 cost time: 0.123000s.
quick SortV1 cost time: 0.001000s.
quick SortV2 cost time: 0.001000s.進程已結束,退出代碼為 0

大概先寫這些吧,今天的博客就先寫到這,謝謝您的觀看。

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

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

相關文章

MySQL架構和儲存引擎

MySQL服務器整體架構如下&#xff1a;連接層&#xff1a;連接層的作用是處理客戶端的連接&#xff0c;如何管理連接的。網絡端口和連接管理線程&#xff1a;網絡端口&#xff1a;一臺服務器可以連接網絡上多個端口的客戶連接&#xff0c;只需要開放多個端口&#xff0c;只需要在…

詳解flink java基礎(一)

文章目錄1.流式處理flink介紹2.Flink SQL介紹3. Flink Runtime4.使用flink集成kafka5.使用Flink SQL進行有狀態流處理6.Event time & Watermarks7. flink Checkpoints & recovery1.流式處理flink介紹 實時服務依賴流式處理: flink優點: 高性能豐富的特性&#xff1a…

Day119 持續集成docker+jenkins

Day119 dockerjenkins 1.Dockerfile Dockerfile 可以用于項目部署。通過編寫 Dockerfile&#xff0c;可以將整個項目及其所需的依賴項打包到一個 Docker 鏡像中&#xff0c;然后在任何支持 Docker 的環境中部署和運行該鏡像 Dockerfile 是用于構建 Docker 鏡像的文本文件。它包…

Vue3+Vite MPA多頁面應用開發完整指南 – 從零搭建到部署優化

什么是 MPA 多頁面應用 MPA&#xff08;Multi-Page Application&#xff09;是由多個獨立的 HTML 頁面組成的應用&#xff0c;每個頁面都有獨立的入口文件。與 SPA 不同&#xff0c;MPA 的每個頁面都是獨立的&#xff0c;頁面間通過鏈接跳轉&#xff0c;適合大型項目或需要 SE…

【企業級架構】企業戰略到技術落地的全流程【第一篇】

目錄 一、人生藍圖與企業羅盤&#xff1a;戰略視角下的成長架構 1. 大學畢業迷茫期 → 企業未制定戰略前&#xff1a;無方向、無目標? 2. 制定職業規劃 → 企業戰略制定&#xff1a;明確 “去哪” 和 “分幾步走”? 3. 盤點自身能力差距 → 業務架構梳理&#xff1a;搞清…

(二) Python + 地球信息科學與技術 = 經典案例分析

目錄 四、農業精準施肥與產量預測&#xff08;植被指數 機器學習&#xff09; 五、公共場所踩踏事故預警系統&#xff08;時空大數據 Web 開發&#xff09; 六、森林火災智能識別與救援路徑規劃&#xff08;遙感 路徑優化&#xff09; 七、海岸線侵蝕動態監測與防護&…

從需求到部署全套方案:餐飲服務許可證數據可視化分析系統的大數據技術實戰

&#x1f393; 作者&#xff1a;計算機畢設小月哥 | 軟件開發專家 &#x1f5a5;? 簡介&#xff1a;8年計算機軟件程序開發經驗。精通Java、Python、微信小程序、安卓、大數據、PHP、.NET|C#、Golang等技術棧。 &#x1f6e0;? 專業服務 &#x1f6e0;? 需求定制化開發源碼提…

Qt 關于QString和std::string數據截斷的問題- 遇到\0或者0x00如何處理?

Qt 關于QString和std::string數據截斷的問題- 遇到\0或者0x00如何處理&#xff1f;引言一、解決方案二、使用QByteArray注意事項引言 在Qt開發中&#xff0c;使用QString或std::string獲取、發送字符串時&#xff0c;遇到\0(空字符)或者0x00(十六進制表示)可能導致數據截斷&am…

Spring Cloud LoadBalancer 最佳實踐

Ribbon 曾經是 Spring Cloud 家族默認的客戶端負載均衡工具&#xff0c;而 Spring Cloud LoadBalancer (SCLB) 是官方替換 Ribbon 的新實現。表面上它們都解決 “服務調用時選哪個實例” 的問題&#xff0c;但在理念、架構和生態上差異不小。一、Ribbon vs SCLB1. 定位和生態…

【STM32】SPI 與 Flash 筆記

1?? SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外設接口&#xff09;英文解釋&#xff1a; Serial&#xff1a;串行Peripheral&#xff1a;外設Interface&#xff1a;接口用途&#xff1a;MCU 與外部設備&#xff08;Flash、傳感器等&#xff09;高速數據通…

抽象工廠設計模式 Abstract Factory

抽象工廠抽象工廠設計模式是一種創建模式&#xff0c;它提供了一個用于創建相關或從屬對象族的接口&#xff0c;而無需指定其具體類。 它在以下情況下特別有用&#xff1a; 您需要創建必須一起使用并且是一致系列的一部分的對象&#xff08;例如&#xff0c;按鈕、復選框和菜單…

WSL 下的虛擬網卡配置

第一部分&#xff1a;Windows 虛擬網卡創建指南 1. 原理 在 Windows 里&#xff0c;“虛擬網卡”本質是由網絡驅動在系統網絡棧中創建的一個 軟件網卡接口。它的作用和物理網卡類似&#xff0c;只不過不直接連接到物理硬件&#xff0c;而是通過內核網絡驅動與宿主機網絡進行交換…

Dify web前端源碼本地部署詳細教程

目錄 1. 先啟動API 2. 啟動worker服務 3. 啟動web 4. 訪問登陸地址 在前面的文章中&#xff0c;Dify源碼部署&#xff0c;搭建二次開發環境&#xff08;一&#xff09; 已經記錄了如何在本地啟動API、work、中間件。在本篇文章中&#xff0c;將概述如何啟動dify web源碼項…

CVPR 2025|英偉達聯合牛津大學提出面向3D醫學成像的統一分割基礎模型

在 2D 自然圖像和視頻的交互式分割領域&#xff0c;基礎模型已引發廣泛關注&#xff0c;這也促使人們開始構建用于醫學成像的 3D 基礎模型。然而&#xff0c;3D 醫學成像存在的領域差異以及臨床應用場景&#xff0c;要求開發一種有別于現有 2D 解決方案的專用模型。具體而言&am…

解決“Win7共享文件夾其他電腦網絡無法發現共享電腦名稱”的問題

要讓運行 Windows 7 的電腦被局域網中其他設備&#xff08;包括另一臺電腦、手機、NAS 等&#xff09;“發現”&#xff0c;必須同時滿足三個條件&#xff1a; 網絡發現功能已啟用&#xff1b;對應的后臺服務已啟動&#xff1b;防火墻規則放行。 下面給出最簡、最穩妥的 3 步設…

Python pyzmq 庫詳解:從入門到高性能分布式通信

一、前言 在現代軟件開發中&#xff0c;進程間通信&#xff08;IPC&#xff09;與分布式系統通信已經成為基礎能力。無論是構建一個微服務架構的后端&#xff0c;還是實現大規模并行計算任務&#xff0c;如何讓不同的進程或節點之間高效地傳遞消息&#xff0c;都是核心問題。 傳…

CentOS 7更換國內鏡像源

第一步&#xff1a;檢查系統版本 在修改任何配置之前&#xff0c;先確定你的 CentOS 版本&#xff0c;因為不同版本的鏡像源配置文件不同。 cat /etc/redhat-release這個命令會顯示你的 CentOS 版本信息&#xff0c;例如 CentOS Linux release 7.9.2009 (Core)。從你的錯誤日志…

詳解 doclayout_yolo:Python 文檔布局檢測

目錄一、doclayout_yolo 核心功能二、安裝方法1. 直接安裝2. 通過 PDF-Extract-Kit 安裝三、使用示例1. 快速體驗&#xff08;HuggingFace Demo&#xff09;2. 本地推理代碼3. 批量處理四、技術亮點五、應用場景六、其他說明1.相關資源2. 注意事項doclayout_yolo 是一個基于 Y…

貓頭虎AI分享|一款Coze、Dify類開源AI應用超級智能體Agent快速構建工具:FastbuildAI

貓頭虎AI分享&#xff5c;一款 Coze、Dify 類開源 AI 應用超級智能體快速構建工具&#xff1a;FastbuildAI 區別在于它的易用度和商業閉環功能 摘要&#xff1a;FastbuildAI 是一個開源的 AI 應用“快速構建 商業化閉環”工具。它讓個人開發者與小團隊用 可視化 零代碼 的方…

GitLab 安全漏洞 CVE-2025-6186 解決方案

本分分享極狐GitLab 補丁版本 18.2.2, 18.1.4, 18.0.6 的詳細內容。這幾個版本包含重要的缺陷和安全修復代碼&#xff0c;我們強烈建議所有私有化部署用戶應該立即升級到上述的某一個版本。對于極狐GitLab SaaS&#xff0c;技術團隊已經進行了升級&#xff0c;無需用戶采取任何…