【C】初階數據結構14 -- 歸并排序

本篇文章主要是講解經典的排序算法 -- 歸并排序??


目錄

1? 遞歸版本的歸并排序

1) 算法思想

2)?代碼?

3) 時間復雜度與空間復雜度分析?

(1) 時間復雜度

(2) 空間復雜度

2? 迭代版本的歸并排序

1) 算法思想

2) 代碼

3? 文件的歸并排序?

1) 外排序

2) 文件的歸并排序

(1) 算法思想

(2) 代碼


1? 遞歸版本的歸并排序

1) 算法思想

? 歸并排序與快速排序相同,都是運用了分治算法思想:將規模為 n 的問題分為k個規模較小的與原問題性質一致且相互獨立的子問題,然后解決各個子問題,將子問題的解合并為大問題的解。

? ?歸并排序是利用了之前合并兩個有序鏈表的思想,每次將大問題二分,直到分到只有一個元素的子數組的情況,將只含有一個元素的子數組看作是一個有序的子數組,然后再合并兩個有序數組,這樣子問題就解決了,解決每一個子問題之后,大問題也就隨之解決了。下面是解決兩個個子問題的算法過程(這里假設排升序):

a. 首先定義 4 個整型變量 begin1, end1, begin2, end2, 這里假設要排序的整個數組為 arr,其中一個子問題,也就是要合并的第一個有序數組為 arr1;另一個子問題,也就是要合并的第二個有序數組為 arr2。begin1 與 begin2?分別指向 arr1 和 arr2 的起始下標end1 與 end2 分別指向 arr1 和 arr2 的結束下標,合并兩個有序數組還需要一個中間數組 tmp 以及一個整型變量 index,tmp 來暫時存儲合并兩個有序數組后的結果,index 用來表示 tmp 數組當前存儲結果的下標。

b. 然后依次比較 arr1[begin1] 與 arr2[begin2] 的大小關系,如果 arr1[begin1] < arr2[begin2] ,那就讓 tmp[index] = arr1[begin1],然后 ++index,++begin1否則,就讓 tmp[index] = arr2[begin2],然后 ++index,++begin2。循環上述過程,直到 begin1 > end1 或者 begin2 > end2。

c. 經歷過第二步之后,arr1 與 arr2 肯定會有一個數組還有元素,我們需要把剩下的元素也放到 tmp 里面,所以如果 begin1 <= end1,就讓 tmp[index] = arr1[begin1],然后 ++index,++begin1;如果 begin2 <= end2,就讓 tmp[index] = arr2[begin2],然后 ++index,++begin2

d. 經歷過上述兩步之后,arr1 與 arr2 的合并結果已經放到 tmp 數組中了,最后不要忘記讓合并后的結果,也就是 tmp 中的元素要放回排序的數組 arr 中

?下面是合并合并兩個有序數組的過程:

下面是歸并排序劃分子問題的過程:

注意上述過程只是描述了遞歸劃分子問題的過程,沒有進行合并,原則上是當劃分到每一條綠色的豎線左右兩邊子數組只有一個元素的時候,就應該進行合并了。


2)?代碼?

歸并排序主函數:

void MergeSort(int* arr,int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail!\n");exit(1);}_MergeSort(arr, 0, n - 1, tmp);free(tmp);tmp = NULL;
}

歸并排序子函數:?

void _MergeSort(int* arr, int left, int right, int* tmp)
{if (left >= right){return;}int mid = left + (right - left) / 2;_MergeSort(arr, left, mid, tmp);_MergeSort(arr, mid + 1, right, tmp);//合并兩個有序數組int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int index = left;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2])tmp[index++] = arr[begin1++];elsetmp[index++] = arr[begin2++];}while (begin1 <= end1)tmp[index++] = arr[begin1++];while (begin2 <= end2)tmp[index++] = arr[begin2++];//再將tmp數組的內容放回arr數組for (int i = left;i <= right;i++)arr[i] = tmp[i];
}

解釋: 歸并排序主函數的作用主要是動態開辟一個輔助數組 tmp 與釋放動態開辟的空間,防止內存泄漏,tmp 主要用來幫助完成有序數組的合并;在子函數里面,left 代表要進行排序的子數組的最左邊元素的下標,right 代表要進行排序的子數組的最右邊元素的下標;然后開始有一個遞歸的邊界條件,當 left >= right,也就是子數組中只有一個元素或者沒有元素的時候,就會停止遞歸,此時將只有一個元素的子數組視為是一個有序數組;邊界條件下面的三行代碼主要就是用來進行遞歸,劃分子問題的,首先計算出大問題的中間位置下標 mid,然后將大問題在中間數組劃分為兩個子問題,也就是對 [left, mid][mid + 1, right] 區間的數組進行遞歸;再后面的代碼就是為了解決某兩個具體的子問題也就是合并兩個有序數組的過程(上面已經講解過,這里不再贅述)。

?測試用例

int main()
{int arr[] = { 10, 2, 5, 7, 1, 4, 8, 9, 6, 20};int n = sizeof(arr) / sizeof(arr[0]);MergeSort(arr, n);Print(arr, n);return 0;
}

3) 時間復雜度與空間復雜度分析?

(1) 時間復雜度

? 與快速排序相同,帶有遞歸的函數的時間復雜度計算包括兩部分,一部分是解決子問題的時間復雜度,另一部分是遞歸的深度,T(n) = 遞歸深度 * 解決子問題的時間復雜度。

? 我們先來看解決子問題的時間復雜度,看上面解決具體解決子問題的代碼,由于只有一層循環,且循環的次數最多是 end1 - begin1 或者 end2 - begin2 次,最壞情況下是對最開始要排序的整個數組從中間劃分的兩個子數組進行排序的時候,此時循環的次數就是 n / 2 次,所以解決子問題的時間復雜度 T(n) = O(n)。

? 再來看遞歸的深度,由于每次都對數組進行二分,在中間位置劃分數組,對左邊數組進行遞歸,再對右邊數組進行遞歸,所以遞歸樹應該為:

我們假設最開始的數組元素個數為 n,那么遞歸到第二層的時候每個子數組元素個數就為 n/2,第三層就為 n/4,也就是 n/2^2,第四層就是 n/2^3,所以遞歸到第 x 層的時候元素個數就為 n/2^x,而遞歸的停止條件為元素個數為 1,所以 n/2^x = 1? ==>? x = \log_{2}n,所以總的層數應該是?\log_{2}n?+ 1 層,所以遞歸的深度為?\log_{2}n?+ 1。

? 所以歸并排序的時間復雜度 T(n) = O(nlogn + n)? ==>? T(n) = O(nlogn)

(2) 空間復雜度

? 由于在函數中使用了一個輔助數組 tmp 來幫助合并,其余都是有限的變量,所以空間復雜度?S(n) = O(n)


2? 迭代版本的歸并排序

1) 算法思想

? 在迭代版本的歸并排序中,我們依然可以借助遞歸版本歸并排序的算法思想:先將數組劃分到 1 個元素的子數組的情況,將 1 個元素的子數組看作是有序的數組,然后依次合并兩個有序數組,最終使數組有序;在迭代版本歸并排序中,我們劃分子問題是用一個 gap 變量來實現的,具體過程如下:

a. 函數會傳入兩個參數:arr(數組元素首地址)與 n (數組元素個數),先創建一個整型變量 gap 與一個輔助數組 tmp(用來合并兩個有序數組);開始先讓 gap = 1,代表每個要合并的數組里只有一個元素之后每次循環都讓 gap *= 2,代表要合并的數組由 1 個元素變為 2 個元素,之后再變為 4 個元素,依次類推,直到?gap >= n,就停止排序

b. 然后在每次循環里面,由于在大數組里我們要尋找要合并的兩個子數組,所以我們還要用一個變量 i 來遍歷數組,尋找要合并的兩個子數組;在循環過程中,i 每次會指向要合并的兩個子數組中第一個子數組的首元素由于每次首次要合并的第一個子數組總是以 0 下標元素開頭的子數組,所以 i 總是以 0 開頭然后合并完兩個有序子數組之后,i 會指向下一次要合并的兩個有序子數組的第一個子數組首元素,所以 i 在遍歷過程中會跳過上一次排序的兩個子數組,也就是 2 * gap 個元素,即 i += 2 * gap;停止條件也很簡單,就是 i >= n 越界時,就會停止兩個子數組的合并。

c. 在合并兩個子數組的過程中需要找到兩個子數組,這里用 begin1, end1 代表第一個要合并的子數組的起始和結束位置,begin2 和 end2 代表第二個要合并的子數組的起始和結束位置,根據 i 與 gap 就可以推算出 begin1、end1、begin2、與 end2:begin1 = i,end1 = i + gap - 1,begin2 = i + gap,end2 = begin1 + gap - 1 = i + 2 * gap - 1

d. 再創建一個?index 來記錄要放到 tmp 數組中的位置,開始先讓 index = begin1,之后進行兩個有序數組的合并(上面遞歸版本講解過,這里不再贅述),最后不要忘記讓 tmp 中的元素放到 arr 數組中。

?當 gap = 1 時排序過程如圖所示:?

在上述的合并過程中,我們可以發現 begin2 與 end2 是可能發生越界的,所以當發生越界情況時,我們需要特殊處理一下:當 begin2 越界時,此時代表 begin1 的子數組后面是沒有 begin2 子數組與其合并的,也就是此時只有一個有序子數組,就代表此次不需要合并了,跳出循環即可;當end2 越界時,會在 gap = 2 中出現,下面我們再詳細討論。?

?當 gap = 2?時排序過程如圖所示:

通過上述合并過程,可以看到當 end2 出現越界行為時,我們讓其回到了最后一個位置,也就是 end2 = n - 1,此時就可以避免越界行為的發生

? 接下來 gap 會繼續 gap *= 2,變為4,之后會再變為 8,最后變為 16 的時候由于大于 n,會退出循環,排序就完成了,如果你有興趣可以自己畫一下圖模擬一下過程,在這里就不再畫圖。


2) 代碼

void MergeSortNorR(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail!\n");exit(1);}//每組元素的個數int gap = 1;while (gap < n){//遍歷每兩組,進行兩組之間的合并// i 每次指向要合并兩組的第一組的第一個元素for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;int index = begin1;//為了防止要合并第二個數組越界,需要特殊處理一下//begin2 如果越界,代表第一組沒有要合并的第二組了,不用合并了,直接跳出循環if (begin2 >= n){break;}//如果要合并的第二組元素不滿gap個,那就有多少合并多少if (end2 >= n){end2 = n - 1;}//合并兩個有序數組while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[index++] = arr[begin1++];}else{tmp[index++] = arr[begin2++];}}while (begin1 <= end1){tmp[index++] = arr[begin1++];}while (begin2 <= end2){tmp[index++] = arr[begin2++];}//把tmp中的數據放回原數組memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));}gap *= 2;}//最后不要忘記釋放tmp數組free(tmp);tmp = NULL;
}

測試用例:

#include<stdio.h>
#include<stdlib.h>void MergeSortNorR_Test()
{//奇數個元素的情況//int arr[] = { 2, 1, 10, 4, 7, 3, 8, 5, 11 };//偶數個元素的情況int arr[] = { 2, 1, 10, 4, 7, 3, 8, 5 };int n = sizeof(arr) / sizeof(arr[0]);MergeSortNorR(arr, n);for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}int main()
{MergeSortNorR_Test();return 0;
}

3? 文件的歸并排序?

1) 外排序

? ? ? ? 不同于內排序,外排序是進行文件與磁盤內數據的排序,也就是不是直接對存儲在內存中的數據進行排序,而是先將外存中的數據先調入內存,排完序之后再將數據放回文件或者磁盤中,就是外排序。

? ? ? ? 那么什么時候會用到外排序呢?一般都是數據量很多時,比如一個文件里面有 10G 的數據,無法全部調入內存,還想要對文件內的數據進行排序,此時就需要進行外排序。

2) 文件的歸并排序

(1) 算法思想

? ? ? ? 如果想要排序的數據量較大時,我們一般都會先把數據保存在文件中,然后通過 C 語言中文件的相關操作,將文件中的數據排序好后,再放入文件之中,而在七大排序算法中,不需要內存的隨機訪問而又效率比較快的排序算法就是歸并排序了(堆排序、快速排序、希爾排序都需要對內存中的數據進行隨機訪問),所以歸并排序算法既可以用于實現內排序,也可以實現外排序,以下是對文件進行歸并排序的算法過程:

a. 先在要進行排序的文件 data.txt 中取出 n?個數據,將這 n 個數據排好序后,放到 file1.txt 里面;再取出 n 個數據,排好序之后,放到 file2.txt 文件里面。

b. 然后對 file1.txt 和 file2.txt 中的數據進行歸并(就是前面歸并排序中合并兩個有序子數組的過程),將歸并后的數據放到 mfile.txt 里面。

c. 此時,file1.txt 與 file2.txt 已經沒用了,刪除 file1,txt 與 file2.txt 文件,將 mfile.txt 文件重命名為 file1.txt 文件。

d. 然后再取出 n 個數據放到 file2.txt 里面,再將 file1.txt(之前的 mfile.txt 文件)與 file2.txt 文件歸并,將歸并后的數據放到新的 mfile.txt 文件里面;如此循環,直到 data.txt 文件中沒有數據為止。最終,排好序的數據會存儲在 file1.txt 文件里面。

上述算法過程如下圖所示:
?

? ? ? ? 在上述算法思想的實現過程中,有三個函數需要我們了解一下,第一個就是刪除文件的函數,第二個就是對文件名重命名的函數,還有一個就是對數據進行排序的函數,接下來我們來一次了解一下。

a.? 刪除文件的函數:

刪除文件的函數的函數名字叫做 remove 函數,與 printf 和 scanf 函數相同,其都被包含在 stdio.h 頭文件下,傳入的參數僅有一個,就是要刪除文件的文件名字符指針即可。所以刪除 file1.txt 文件與 file2.txt 文件,我們可以直接 remove("file1.txt") 與 remove("file2.txt")。

?b. 重命名的函數:

對文件進行重命名的函數叫做 rename 函數,傳入的參數也很簡單,第一個參數為要修改的文件的文件名的字符指針,也就是 oldname,第二個參數為修改后的文件名的字符指針,也就是 newname。所以將 mfile 重命名為 file1.txt 可以寫為 rename("mfile.txt", "file1.txt")。

c. 對數據進行排序的函數:這里可以使用我們之前學習過的七大排序算法,比如:快速排序、堆排序、希爾排序都可以,當然這里也可以直接使用 qsort 函數:

可以看到 qsort 函數是需要四個參數的,第一個是需要進行排序的首元素的指針,第二個參數是進行排序的元素的個數,第三個參數是需要進行排序的元素的大小(單位為字節),第四個參數是一個函數指針,其指向的函數的返回值為 int, 兩個參數類型為 const void*。對于第四個參數 compare 我們具體講解一下:

從下面的表格我們可以看出其對返回值是有要求的,如果第一個參數想排在第二個參數之前,那就返回小于 0 的數字;如果相等返回 0;否則返回大于 0 的數字,由于我們這里排的都是整形,且升序排序,所以我們可以這樣設計 compare 函數:

int compare(const void* a, const void* b)
{return (*(int*)a - *(int*)b);
}

?注意,一定要對 a 和 b 進行強轉,因為 void* 類型的指針無法進行解引用的


(2) 代碼

#include<stdio.h>
#include<stdlib.h>
#include<time.h>void CreateData()
{const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen fail!\n");exit(1);}srand(time(0));const int n = 1000000;for (int i = 0; i < n; i++){fprintf(fin, "%d\n", rand() + i);}fclose(fin);
}int Compare(const void* a, const void* b)
{return (*(int*)a - *(int*)b);
}//返回讀取到的數據個數
int SortNValeToFile(FILE* fout, int n, const char* file)
{int x = 0;int* a = (int*)malloc(sizeof(int) * n);if (a == NULL){perror("malloc error");return 0;}// 想讀取n個數據,如果遇到文件結束,應該讀到j個int j = 0;for (int i = 0; i < n; i++){if (fscanf(fout, "%d", &x) == EOF)break;a[j++] = x;}if (j == 0){free(a);return 0;}// 排序qsort(a, j, sizeof(int), Compare);FILE* fin = fopen(file, "w");if (fin == NULL){free(a);perror("fopen error");return 0;}// 寫回file1文件for (int i = 0; i < j; i++){fprintf(fin, "%d\n", a[i]);}free(a);fclose(fin);return j;
}void MergeFile(const char* file1, const char* file2, const char* mfile)
{FILE* fout1 = fopen(file1, "r");if (fout1 == NULL){perror("fopen1 fail!\n");return;}FILE* fout2 = fopen(file2, "r");if (fout2 == NULL){perror("fopen2 fail!\n");return;}FILE* fin = fopen(mfile, "w");if (fin == NULL){perror("fin fail!\n");return;}//對文件進行歸并排序int x1 = 0;int x2 = 0;int ret1 = fscanf(fout1, "%d", &x1);int ret2 = fscanf(fout2, "%d", &x2);while (ret1 != EOF && ret2 != EOF){//如果 file1 的數據小于 file2 的數據,就將 file1 的數放到 mfile 里面if (x1 < x2){fprintf(fin, "%d\n", x1);ret1 = fscanf(fout1, "%d", &x1);}else{fprintf(fin, "%d\n", x2);ret2 = fscanf(fout2, "%d", &x2);}}while (ret1 != EOF){fprintf(fin, "%d\n", x1);ret1 = fscanf(fout1, "%d", &x1);}while (ret2 != EOF){fprintf(fin, "%d\n", x2);ret2 = fscanf(fout2, "%d", &x2);}fclose(fout1);fclose(fout2);fclose(fin);
}int main()
{CreateData();//創建三個文件const char* file1 = "file1.txt";const char* file2 = "file2.txt";const char* mfile = "mfile.txt";//從data.txt中取出n個數據放到file1與file2中FILE* fout = fopen("data.txt", "r");if (fout == NULL){perror("fopen fail!\n");exit(1);}int N = 100000;SortNValeToFile(fout, N, file1);SortNValeToFile(fout, N, file2);while (1){//將兩個文件歸并到 mfile 文件MergeFile(file1, file2, mfile);//刪除file1 與 file2 文件remove(file1);remove(file2);//將mfile 重命名為 file1rename(mfile, file1);//再從data.txt中取出n個數據放到file2 里面//如果取不到數據說明歸并結束if (SortNValeToFile(fout, N, file2) == 0)break;}return 0;
}

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

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

相關文章

【相機標定】OpenCV 相機標定中的重投影誤差與角點三維坐標計算詳解

摘要&#xff1a; 本文將從以下幾個方面展開&#xff0c;結合典型代碼深入解析 OpenCV 中的相機標定過程&#xff0c;重點闡述重投影誤差的計算方法與實際意義&#xff0c;并通過一個 calcBoardCornerPositions() 函數詳細講解棋盤格角點三維坐標的構建邏輯。 在計算機視覺領域…

RabbitMQ-運維

文章目錄 前言運維-集群介紹多機多節點單機多節點 多機多節點下載配置hosts?件配置Erlang Cookie啟動節點構建集群查看集群狀態 單機多節點安裝啟動兩個節點再啟動兩個節點驗證RabbitMQ啟動成功搭建集群把rabbit2, rabbit3添加到集群 宕機演示仲裁隊列介紹raft算法協議 raft基…

JVM之內存管理(一)

部分內容來源&#xff1a;JavaGuide二哥Java 圖解JVM內存結構 內存管理快速復習 棧幀&#xff1a;局部變量表&#xff0c;動態鏈接&#xff08;符號引用轉為真實引用&#xff09;&#xff0c;操作數棧&#xff08;存儲中間結算結果&#xff09;&#xff0c;方法返回地址 運行時…

無線射頻模塊如何通過CE RED認證?關鍵規范與準備策略詳解

隨著無線通信設備在歐洲市場的廣泛應用&#xff0c;CE RED認證已成為模塊類產品進入歐盟的強制通行證。作為專注于LoRa模塊、對講模塊與FSK射頻模塊研發的技術企業&#xff0c;我們深知從設計、測試到量產&#xff0c;每一個環節都需緊扣合規底線。本文將圍繞CE RED認證核心要求…

Golang中集合相關的庫

一切編程語言的底層結構都是數組&#xff0c;其它復雜數據結構如Map, Stack&#xff0c;Heap和Queue都是基于數組建立起來的。 Go語言主流工具庫推薦&#xff08;含常用數據結構實現&#xff09; 以下是目前Go生態中最主流且活躍的工具庫&#xff0c;包含隊列、棧、優先級隊列…

ABAP 導入Excel形成內表

文章目錄 創建導入模板程序實現代碼代碼解析運行結果 創建導入模板 程序實現 代碼 *&---------------------------------------------------------------------* *& Report Z_EXCEL_UPLOAD_LHY *&--------------------------------------------------------------…

特殊配合力(SCA)作為全基因組關聯分析(GWAS)的表型,其生物學意義和應用價值

生物學意義 解析非加性遺傳效應 特殊配合力(SCA)主要反映特定親本組合的雜交優勢,由非加性遺傳效應(如顯性、超顯性、上位性)驅動。顯性效應涉及等位基因間的顯性互作,上位性效應則涉及不同位點間的基因互作。通過SCA-GWAS,可以定位調控這些非加性效應的關鍵基因組區域…

應急響應基礎模擬靶機-security1

PS:杰克創建在流量包(result.pcap)在根目錄下&#xff0c;請根據已有信息進行分析 1、攻擊者使用的端口掃描工具是? 2、通過流量及日志審計&#xff0c;攻擊者上傳shell的時訪問web使用IP地址是多少? 3、審計流量日志&#xff0c;攻擊者反彈shell的地址及端口? 4、攻擊者…

uniapp-商城-47-后臺 分類數據的生成(通過數據)

在第46章節中&#xff0c;我們為后臺數據創建了分類的數據表結構schema&#xff0c;使得可以通過后臺添加數據并保存&#xff0c;同時使用云函數進行數據庫數據的讀取。文章詳細介紹了如何通過前端代碼實現分類管理功能&#xff0c;包括獲取數據、添加、更新和刪除分類。主要代…

ClickHouse的基本操作說明

說明 文章內容包括數據庫管理、表操作及查詢等核心功能 創建數據庫 -- 默認引擎&#xff08;Atomic&#xff09; CREATE DATABASE IF NOT EXISTS test_db; -- MySQL引擎&#xff08;映射外部MySQL數據庫&#xff09; CREATE DATABASE mysql_db ENGINE MySQL(host:port, m…

Nacos源碼—7.Nacos升級gRPC分析四

大綱 5.服務變動時如何通知訂閱的客戶端 6.微服務實例信息如何同步集群節點 6.微服務實例信息如何同步集群節點 (1)服務端處理服務注冊時會發布一個ClientChangedEvent事件 (2)ClientChangedEvent事件的處理源碼 (3)集群節點處理數據同步請求的源碼 (1)服務端處理服務注冊…

《Overlapping Experiment Infrastructure: More, Better, Faster》論文閱讀筆記

文章目錄 1 背景2 三個核心概念3 Launch層&#xff1a;特性發布的專用機制4 流量分發策略和條件篩選4.1 四種流量分發類型4.2 條件篩選機制 5 工具鏈與監控體系6 實驗設計原則7 培訓參考與推薦 1 背景 谷歌&#xff08;Google&#xff09;以數據驅動著稱&#xff0c;幾乎所有可…

國芯思辰| 醫療AED可使用2通道24位模擬前端SC2946(ADS1292)

生物電信號監測技術在醫療健康行業中發展迅速&#xff0c;成為評估人體生理健康狀況的關鍵手段。心電&#xff08;ECG&#xff09;、腦電&#xff08;EEG&#xff09;和肌電&#xff08;EMG&#xff09;等信號&#xff0c;通過精密模擬前端芯片捕捉和處理&#xff0c;對醫療診斷…

數據結構【二叉搜索樹(BST)】

二叉搜索樹 1. 二叉搜索樹的概念2. 二叉搜索樹的性能分析3.二叉搜索樹的插入4. 二叉搜索樹的查找5. 二叉搜索樹的刪除6.二叉搜索樹的實現代碼7. 二叉搜索樹key和key/value使用場景7.1 key搜索場景&#xff1a;7.2 key/value搜索場景&#xff1a; 1. 二叉搜索樹的概念 二叉搜索…

RDMA高性能網絡通信實踐

RDMA高性能網絡通信實踐 一、背景介紹二、方法設計A.實現方案B.關鍵技術點 三、代碼及注釋四、注意事項 一、背景介紹 遠程直接內存訪問&#xff08;RDMA&#xff09;技術通過繞過操作系統內核和CPU直接訪問遠程內存&#xff0c;實現了超低延遲、高吞吐量的網絡通信。該技術廣…

ndarray數組掩碼操作,True和False獲取數據

#數組掩碼的表示方法 def testht05():a np.arange(1,10)mask [True,False,True,True,False,True,False,True,True]print(a[mask]) 另外的用法&#xff1a; #掩碼操作獲取子集 def testht06():a np.arange(1,100)print(a[a%3 0 & (a%7 0)] )b np.array([A,"B&qu…

索引工具explain

EXPLAIN 是 MySQL 中一個非常有用的工具,用于分析查詢的執行計劃。通過 EXPLAIN,你可以了解 MySQL 是如何執行查詢的,包括它如何使用索引、表的掃描方式等。這有助于優化查詢性能。以下是 EXPLAIN 輸出的各個字段的詳細解釋: 基本用法 EXPLAIN SELECT * FROM table_name …

Git回顧

參考視頻:【GeekHour】一小時Git教程 一句話定義&#xff1a;Git是一個免費開源的分布式版本控制系統。 版本控制系統可以分為兩種&#xff0c;1.集中式&#xff08;SVN&#xff0c;CVS&#xff09;&#xff1b;2.分布式&#xff08;git&#xff09; git的工作區域和文件狀態…

python打卡day20

特征降維------特征組合&#xff08;以SVD為例&#xff09; 知識點回顧&#xff1a; 奇異值的應用&#xff1a; 特征降維&#xff1a;對高維數據減小計算量、可視化數據重構&#xff1a;比如重構信號、重構圖像&#xff08;可以實現有損壓縮&#xff0c;k 越小壓縮率越高&#…

GuPPy-v1.2.0安裝與使用-生信工具52

GuPPy&#xff1a;Python中用于光纖光度數據分析的免費開源工具 01 背景 Basecalling 是將原始測序信號轉換為堿基序列的過程&#xff0c;通俗地說&#xff0c;就是“把堿基識別出來”。這一過程在不同代測序技術中各不相同&#xff1a; 一代測序是通過解析峰圖實現&#xff1…