【初探數據結構】歸并排序與計數排序的序曲

💬 歡迎討論:在閱讀過程中有任何疑問,歡迎在評論區留言,我們一起交流學習!
👍 點贊、收藏與分享:如果你覺得這篇文章對你有幫助,記得點贊、收藏,并分享給更多對數據結構感興趣的朋友!

文章目錄

    • 前言
    • 一、歸并排序(Merge Sort)
      • 1. 算法原理
      • 2. 遞歸實現
      • 3. 非遞歸實現
    • 二、計數排序(Count Sort)
      • 1. 算法原理
      • 2. 代碼實現
    • 三、對比與總結

前言

本文主要內容是歸并的遞歸和非遞歸以及計數排序的實現方法。文章會提及很多容易忽視的易錯點(大多是我自己踩過的坑😂),這是我在學習這塊內容時獲取的教訓和寶貴經驗。

因為自己淋過雨,希望能為你們撐把傘!共勉!😁


一、歸并排序(Merge Sort)

1. 算法原理

在這里插入圖片描述

基本思想:
歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為二路歸并。

歸并排序核心步驟:

  1. 分解:將數組遞歸分成兩半,直到子數組長度為1。
  2. 合并:將兩個有序子數組合并為一個有序數組。

從步驟可以看出,這似乎就是二叉樹的后序遍歷

在這里插入圖片描述
不知道你們在學習C語言的時候有沒有寫過這樣一道題
合并兩個有序數組
我建議沒寫過的可以去寫一下,這里可以直接抄作業了,O(∩_∩)O哈哈~

2. 遞歸實現

  1. 首先我們需要開辟一個臨時數組,來存儲合并的序列

  2. 遞歸結束條件:數組長度為1時結束
    if (left >= right) return;

  3. mid不要寫成(right - left) / 2了,再加上left才能在正確位置(因為這是在計算下標),或者直接用(right+left)/2。——易錯點

  4. 確定每次拆分的區間[left,mid] [mid + 1,right]

  5. 遞歸(后序遍歷),

  6. 歸并:在tmp上正確的位置進行賦值,不能是cur = 0,否則會覆蓋值——易錯點

  7. 拷貝,將tmp拷貝到a

void Merger(int* a, int* tmp, int left, int right)
{//遞歸結束條件if (left >= right) {return;}int mid = left + (right - left) / 2;//易錯:加上left才能在正確的位置//遞歸(后序遍歷)//[left,mid] [mid+1,right]Merger(a, tmp, left, mid);Merger(a, tmp, mid+1, right);//歸并int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int cur = left;//易錯:在tmp上正確的位置進行賦值,不能是cur = 0,否則會覆蓋值while (begin1 <= end1 && begin2 <= end2) {if (a[begin1] > a[begin2]) {tmp[cur++] = a[begin2++];}else {tmp[cur++] = a[begin1++];}}while (begin1 <= end1) {tmp[cur++] = a[begin1++];}while (begin2 <= end2) {tmp[cur++] = a[begin2++];}//將tmp拷貝到amemcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));
}void MergerSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);int begin = 0, end = n - 1;Merger(a, tmp, begin, end);free(tmp);
}

特點

  • 時間復雜度:O(n log n)
  • 空間復雜度:O(n)
  • 穩定排序,適合處理大數據量。

3. 非遞歸實現

利用迭代(循環)模擬遞歸過程:

在這里插入圖片描述
當元素個數不是gap的整數時,會發生越界問題:
設歸并的兩部分分別為[begin1,end1][begin2,end2]
那么,end1、begin2、end2都可能會越界,因此我們就需要修正邊界。

  1. end1越界時,第一部分不完整且第二部分不存在,沒必要歸并了,直接拷貝即可
  2. begin2越界時,第二部分不存在,沒必要歸并了,直接拷貝即可
  3. end2越界時,第二部分不完整,將end2修正到數組末尾即可

可以發現,1,2是一類情況,可以一起處理了。

我們需要來抉擇一個問題:

  1. 整體歸并結束后拷貝
  2. 歸并一部分拷貝一部分

這兩個問題看似不起眼,實則不然,它會影響你控制邊界的難度。可以試試兩種方式都寫寫,會特別爽(狗頭)

  1. 歸并結束后再拷貝,需精密控制邊界越界情況,容易出錯。——不推薦該寫法
void MergerSortNonR1(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap) {//歸并//[i,i+gap-1] [i+gap,i+2*gap-1]int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;int cur = i;if (end1 >= n) {//修正end1end1 = n - 1;//使得begin2 > end2,終止歸并begin2 = n;end2 = n - 1;}else if (begin2 >= n) {//使得begin2 > end2,終止歸并begin2 = n;end2 = n - 1;}else if (end2 >= n) {//修正end2,繼續歸并end2 = n - 1;}while (begin1 <= end1 && begin2 <= end2) {if (a[begin1] > a[begin2]) {tmp[cur++] = a[begin2++];}else {tmp[cur++] = a[begin1++];}}while (begin1 <= end1) {tmp[cur++] = a[begin1++];}while (begin2 <= end2) {tmp[cur++] = a[begin2++];}}//歸并結束后再打印memcpy(a, tmp, sizeof(int) * n);gap *= 2;}free(tmp);
}
  1. 歸并一次拷貝一次,若end1begin2有越界情況,直接跳出循環(退出歸并)即可無需控制邊界情況,操作簡單易理解
void MergerSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap) {//歸并//[i,i+gap-1] [i+gap,i+2*gap-1]int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;int cur = i;if (end1 >= n || begin2 >= n) {break;//直接終止歸并}else if (end2 >= n) {//修正end2end2 = n - 1;}while (begin1 <= end1 && begin2 <= end2) {if (a[begin1] > a[begin2]) {tmp[cur++] = a[begin2++];}else {tmp[cur++] = a[begin1++];}}while (begin1 <= end1) {tmp[cur++] = a[begin1++];}while (begin2 <= end2) {tmp[cur++] = a[begin2++];}//歸并一次打印一次memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));}//printf("\n");gap *= 2;}free(tmp);
}

關鍵點

  • gap 控制合并步長,從1開始逐步擴大。
  • 邊界處理:若子數組越界,直接終止合并。

二、計數排序(Count Sort)

思想:計數排序又稱為鴿巢原理,是對哈希直接定址法的變形應用。 操作步驟:

  1. 統計相同元素出現次數
  2. 根據統計的結果將序列回收到原來的序列中

1. 算法原理

  1. 確定范圍:找出數組的最小值 min 和最大值 max
  2. 統計頻率:創建計數數組 countA,統計每個元素出現的次數。
  3. 重建數組:根據計數數組將元素按順序寫回原數組。
    在這里插入圖片描述

2. 代碼實現

void CountSort(int* a, int n) {int min = a[0], max = a[0];for (int i = 0; i < n; i++) {   // 確定范圍if (a[i] < min) min = a[i];if (a[i] > max) max = a[i];}int range = max - min + 1;int* countA = (int*)calloc(range, sizeof(int));  // 分配計數數組for (int i = 0; i < n; i++) countA[a[i] - min]++; // 統計頻率// 重建數組int cur = 0;for (int i = 0; i < range; i++) {while (countA[i]--) a[cur++] = i + min;}free(countA);
}

特點

  • 時間復雜度:O(n + k),k 為數據范圍。
  • 空間復雜度:O(k)
  • 非比較排序,適合數據范圍小且為整數的情況。

三、對比與總結

算法時間復雜度空間復雜度穩定性適用場景
歸并排序O(n log n)O(n)穩定大數據量、需穩定排序
計數排序O(n + k)O(k)穩定小范圍整數、非比較排序

希望這篇文章對你有所幫助🌹🌹🌹

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

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

相關文章

算法刷題記錄——LeetCode篇(8.7) [第761~770題](持續更新)

更新時間&#xff1a;2025-03-30 算法題解目錄匯總&#xff1a;算法刷題記錄——題解目錄匯總技術博客總目錄&#xff1a;計算機技術系列博客——目錄頁 優先整理熱門100及面試150&#xff0c;不定期持續更新&#xff0c;歡迎關注&#xff01; 763. 劃分字母區間 給你一個字…

Pod 網絡與 CNI 的作用

在 Kubernetes 中&#xff0c;Pod 網絡 是實現容器間通信的核心機制&#xff0c;每個 Pod 擁有獨立的 IP 地址&#xff0c;可直接跨節點通信。CNI&#xff08;Container Network Interface&#xff09; 是 Kubernetes 的網絡插件標準&#xff0c;負責為 Pod 分配 IP、配置網絡規…

使用keepalived結合tomcat和nginx搭建三主熱備架構

角色主機名軟件IP地址用戶client172.25.250.90keepalivedVIP172.25.250.100keepalivedVIP172.25.250.101keepalivedVIP172.25.250.102masterserverAkeepalived, nginx172.25.250.30backupserverBkeepalived, nginx172.25.250.31backupserverCkeepalived, nginx172.25.250.32web…

STRUCTBERT:將語言結構融入預訓練以提升深度語言理解

【摘要】最近&#xff0c;預訓練語言模型BERT&#xff08;及其經過穩健優化的版本RoBERTa&#xff09;在自然語言理解&#xff08;NLU&#xff09;領域引起了廣泛關注&#xff0c;并在情感分類、自然語言推理、語義文本相似度和問答等各種NLU任務中達到了最先進的準確率。受到E…

leetcode_977. 有序數組的平方_java

977. 有序數組的平方https://leetcode.cn/problems/squares-of-a-sorted-array/ 1.題目 給你一個按 非遞減順序 排序的整數數組 nums&#xff0c;返回 每個數字的平方 組成的新數組&#xff0c;要求也按 非遞減順序 排序。 示例 1&#xff1a; 輸入&#xff1a;nums [-4,-1…

Nginx—nginx.conf 配置結構詳解

一、nginx.conf 配置結構 函數 說明 main 全局配置 event 配置工作模式以及連接數 http http模塊相關配置 server 虛擬主機配置&#xff0c;可以有多個 location 路由規則&#xff0c;表達式 upstream 集群、內網服務器&#xff08;負載均衡也在這里邊配&#xff…

斐波那契數列----C語言

關于斐波那契 已知&#xff1a; 問題背景&#xff1a;一對兔子從第3個月開始每月生一對新兔子&#xff0c;新兔子同樣在第3個月開始繁殖。 關鍵觀察&#xff1a; 第1個月&#xff1a;1對&#xff08;初始兔子&#xff09;。 第2個月&#xff1a;1對&#xff08;未成熟&#…

vulhub靶場—— Tomcat8

目錄 一、漏洞描述 二、靶場搭建 三、漏洞復現 1、弱密碼 2、文件上傳 一、漏洞描述 環境描述&#xff1a; Tomcat 支持后臺部署 war 文件&#xff0c;可以直接將 webshell 部署到 web 目錄下。tomcat 默認的管理頁面 manager 使用 basic 認證用戶名和密碼登錄&#xff0…

使用 Spring AI Aliabab Module RAG 構建 Web Search 應用

使用 Spring AI Alibaba 構建大模型聯網搜索應用 Spring AI 實現了模塊化 RAG 架構&#xff0c;架構的靈感來自于論文“模塊化 RAG&#xff1a;將 RAG 系統轉變為類似樂高的可重構框架”中詳述的模塊化概念。 Spring AI 模塊化 RAG 體系 總體上分為以下幾個步驟&#xff1a; …

一些練習 C 語言的小游戲

一些練習 C 語言的小游戲 — 1. 猜數字游戲 描述&#xff1a;程序隨機生成一個數字&#xff0c;玩家需要猜測這個數字&#xff0c;并根據提示&#xff08;太高或太低&#xff09;調整猜測&#xff0c;直到猜中為止。 功能點&#xff1a; 隨機數生成 (rand() 函數)。循環和…

關于中文編程的一些思考

隨著信息化與數字化的發展&#xff0c;工業4.0時代亦將徐徐到來。當計算機的普及程度越來越高&#xff0c;數據的產生、傳輸、處理等變得越來越快、越來越大量的時候&#xff0c;人們想要自動化辦公的愿望也越來越強烈&#xff0c;希望能將自身從耗費腦力但是重復繁瑣的工作中解…

golang 日志log與logrus

目錄 一、Go 標準庫 log 詳解 1. 功能特點 2. 常用函數 3. 示例代碼 4. 優勢和局限 二、第三方庫 logrus 詳解 1. 功能特點 2. 核心功能 3. 示例代碼 4. 優勢和擴展性 三、總結 1. 何時選擇 log&#xff1f; 2. 何時選擇 logrus&#xff1f; 3. 對比總結 一、Go 標…

消費品行業創新創業中品類創新與數字化工具的融合:以開源 AI 智能客服、AI 智能名片及 S2B2C 商城小程序為例

摘要&#xff1a; 本文聚焦于消費品行業的創新與創業&#xff0c;深入探討“選擇大于努力”這一觀點&#xff0c;強調品類選擇在品牌發展中的關鍵作用。同時&#xff0c;詳細分析了品類創新對于新消費品牌崛起以及傳統品牌轉型的重要意義。在此基礎上&#xff0c;引入開源 AI 智…

Razer macOS v0.4.10快速安裝

鏈接點這里下載最新的 .dmg 文件。將下載的 .dmg 映像文件拖入 應用程序 文件夾中。若首次打開時出現安全警告【什么扔到廢紙簍】&#xff0c;這時候點擊 Mac 的“系統偏好設置”-> “安全性與隱私”-> “通用”&#xff0c;然后點擊底部的 “打開”。【或者仍然打開】 對…

Flask項目部署:Flask + uWSGI + Nginx

目錄 1,網絡架構 2,環境安裝 2.1,安裝yum:Shell軟件包管理器 2.2 安裝python 2.3 安裝uWSGI 2.4 安裝Flask 3,上傳工程包到服務器,打包Flask項目 4,創建和配置 uwsgi 配置文件 uwsgi.ini 4.1配置文件 4.2配置文件注釋詳解 5,啟動服務 6,安裝nginx 7,nginx配置 8,…

[FPGA基礎學習]實現流水燈與按鍵暫停

FPGA實現LED流水燈 1.vscode的安裝和使用 vscode下載 Visual Studio Code - Code Editing. Redefined vscode插件&#xff08;Verilog-HDL/SystemVerilog&#xff09;下載 quartus綁定vscode 2.用6個LED完成周期為1秒的跑馬燈效果 流水燈模塊設計 時鐘輸入 DE2-115開發板…

【TensorRT】TensorRT從安裝到推理——Python 環境下 MobileNetV4 三分類任務

我想開發一個基于深度學習的分類小軟件&#xff0c;逐漸了解到了TensorRT在模型推理速度上的優勢&#xff0c;經過一下午資料的查找實現了將onnx模型轉為TensorRT格式模型的推理及測試過程。將實現過程記錄下來方便日后查看。 本文實驗設備是MX350顯卡 2G顯存 一 、安裝Tenso…

1.兩數之和(Java)

1. 題目描述 LeetCode 1. 兩數之和&#xff08;Two Sum&#xff09; 給定一個整數數組 nums 和一個目標值 target&#xff0c;請你在該數組中找出和為目標值的那兩個整數&#xff0c;并返回它們的索引。 示例 1&#xff1a; 輸入&#xff1a;nums [2,7,11,15], target 9 …

《深入探索 Python 數據分析:用 Pandas 高效處理與可視化大型數據集》

《深入探索 Python 數據分析:用 Pandas 高效處理與可視化大型數據集》 引言:從零到分析高手 數據是當代社會最寶貴的資源,而數據分析技能是現代職業人不可或缺的一部分。在數據科學的領域中,Python 已成為當之無愧的“首選語言”,其強大的生態系統和簡潔的語法讓人如虎添…

將樹莓派5當做Ollama服務器,C#調用generate的API的示例

其實完全沒這個必要&#xff0c;性能用腳后跟想都會很差。但基于上一篇文章的成果&#xff0c;來都來了就先簡單試試吧。 先來看看這個拼夕夕上五百多塊錢能達到的效果&#xff1a; 只要對速度沒要求&#xff0c;那感覺就還行。 Ollama默認只在本地回環&#xff08;127.0.0…