【C】初階數據結構15 -- 計數排序與穩定性分析

本文主要講解七大排序算法之外的另一種排序算法 -- 計數排序?


目錄

1? 計數排序

1) 算法思想

2) 代碼?

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

(1) 時間復雜度

(2) 空間復雜度

4) 計數排序的優點與缺點

(1) 優點

(2) 缺點

2? 排序的穩定性

1) 穩定性的定義

2) 七大排序算法的穩定性分析

3) 七大排序算法時空復雜度與穩定性總結

3? 總結


1? 計數排序

????????計數排序是排序算法中最簡單的一種算法,不需要借助遞歸等算法,不過需要一點哈希表的思想(哈希表是一種數據結構,后面 C++ 部分會有相應的講解,本質就是通過一個函數將元素值轉化為其對應的映射,從而快速找到其值的一個數據結構)。


1) 算法思想

? ? ? ? 計數排序的算法思想如同其名字一樣,就是計算出其每個元素出現的次數,然后進行排序,其算法過程如下:

a. 先找出其數組中的最大值 maxnum 與 最小值 minnum,然后動態開辟一個 maxnum - minnum + 1 空間大小的數組 count

b. 然后用一個變量 i 遍歷原數組,假設原數組為 arr,然后每次讓 count[arr[i] - minnum]++

c. 再用一個變量 i 遍歷 count 數組,再創建一個 index 下標,初始為 0,如果 count[i] != 0,那就讓arr[index] = i + minnum,然后 index++,count[i]--,直到 count[i] 變為 0 為止。

其算法思想本質就是通過 arr 數組中每個元素減去最小值計算出 arr 數組中每個元素在 count 數組中的下標映射,然后越小的元素就在 count 數組中處于越前面的位置,count[i] 就記錄了每個元素出現的次數。其執行過程如下:
(1) count 數組變化的過程:

(2) arr 數組變化過程:


2) 代碼?

void CountSort(int* arr, int n)
{//先找最大值和最小值int maxnum = 0, minnum = INT_MAX;for (int i = 0; i < n; i++){if (maxnum < arr[i]) maxnum = arr[i];if (minnum > arr[i]) minnum = arr[i];}//開辟數組空間int* count = (int*)calloc(maxnum - minnum + 1, sizeof(int));if (count == NULL){perror("malloc fail!\n");exit(1);}//遍歷原數組,count記錄出現次數for (int i = 0; i < n; i++){count[arr[i] - minnum]++;}//再遍歷count數組,將元素放到 arr 數組中int index = 0;for (int i = 0; i < maxnum - minnum + 1; i++){while (count[i]){arr[index++] = i + minnum;count[i]--;}}
}

這里有個需要注意的一點,就是動態開辟 count 數組空間的時候,要使用 calloc 函數,因為 count 數組里面的值必須全都初始化為 0,如果用 malloc 函數的話里面是隨機值,是會發生錯誤的。

測試用例:

#include<stdio.h>
#include<stdlib.h>int main()
{int arr[] = { 6, 3, 10, 7, 2, 5, 12, 4, 1, 8, 11 };int n = sizeof(arr) / sizeof(arr[0]);CountSort(arr, n);for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

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

(1) 時間復雜度

? ? ? ? 從代碼來分析,盡管有里面有兩層循環,但是里面的 count[i] 循環僅有常數次,假設這里的 maxnum - minnum + 1 = k,計數排序的時間復雜度為 T(n) = O(n + k)

(2) 空間復雜度

? ? ? ? 假設 maxnum - minnum + 1 為 k,由于動態開辟了 k 個空間,所以空間復雜度為 S(n)?= O(k)


4) 計數排序的優點與缺點

(1) 優點

? ? ? ? 計數排序的優點特別明顯,就是其時間復雜度比較低,執行效率很高;前面的七大排序算法最快的時間復雜度就是 O(nlogn),所以計數排序的執行效率是比前面任何一個排序的執行效率都快。

(2) 缺點

? ? ? ? 但是計數排序也有明顯的缺點,由于在排序過程中需要動態開辟 maxnum - minnum + 1 的空間,所以如果 maxnum 與 minnum 相差很大時,需要動態開辟的空間就很大,會浪費很多空間;所以如果 arr 數組中的數據相差很大,比較離散時,計數排序的消耗就會很大。

? ? ? ? 綜合來說,計數排序的應用場景比較有限,如果 arr 數組中的數據很集中時,應用計數排序就很合適,效率很高;但如果數據比較離散的話,計數排序就不太適合了,消耗會比較大


2? 排序的穩定性

1) 穩定性的定義

? ? ? ? 一個排序算法是否穩定是指:如果對于一組數據,其中有相等的值,如果進行排序之后,之前相等的值的相對位置保持不變,那就稱該排序算法是穩定的,否則就是不穩定的。比如:有一組數據 1?8?5 8 7,假設第一個 8 為 num1,第二個數據為 num2,排序之前 num1 排在 num2 之前,排完序之后,該組數據變為 1 5 7 num1 num2,num1 還是排在 num2 之前,就稱該排序算法是穩定的;假如排完序之后,num1 排在了 num2 之后,那么該排序算法就是不穩定的。


2) 七大排序算法的穩定性分析

冒泡排序:假設一組數據為 8 8 2 1,第一個 8 為 num1,第二個 8 為 num2(num1 num2? 2 1),那么根據冒泡排序的算法思想,第一輪排序的結果應該為 num1 2?1?num2,第二輪為 2 1 num1 num2,第三輪排序結果為 1 2 num1 num2。經過排序之后,發現 num1 還是排在 num2 之前,所以冒泡排序算法是穩定的。

?直接插入排序:還是假設數據為 num1 num2? 2 1(同冒泡排序),經過第一輪排序,結果仍為 num1 num2 2 1,第二輪排序結果為 2 num1 num2 1,第三輪排序結果為 1 2 num1 num2。排完序之后,num1 依然排在 num2 之前,所以直接插入排序也是穩定的。

歸并排序:依然假設數據為 num1 num2? 2 1,num1 與 num2 合并之后依然是 num1 num2,2 與 1 合并之后結果為 1 2,然后兩個子數組再進行合并,結果為 1 2 num1 num2。排完序之后,num1 依然排在 num2 之前,所以歸并排序也是穩定的。

直接選擇排序:假設一組數據為 num1 8 num2? 2 9?(5 8 5 2 9),第一輪排序之后結果為 2 8 num2 num1 9,發現 num1 跑到 num2 之后了,所以直接選擇排序是不穩定的。究其原因,就是因為直接選擇排序會將最大的與每輪排序中的最后一個位置交換,將最小的和每輪排序中的第一個位置交換,就有能會使相同元素的相對位置發生變化。?

希爾排序:假設一組數據為 num1 8 2 num2??9?(5 8 2 5?9),第一輪排序 num1 2 9 一組,8 num2 一組,排完序之后結果就變為了 2? num2? num1? 8? 9,此時 num2 與 num1 相對位置發生了變化,所以希爾排序也是一種不穩定的排序算法。

堆排序:假設一組數據為 num1 ?num2? num3? num4?(2? 2? 2? 2),第一次排序會將 num1 與 num4交換(堆頂元素與最后一個元素交換),此時結果變為了 num4? num2? num3? num1,相對位置發生了變化,所以堆排序也是一種不穩定的排序算法。

快速排序:假設一組數據為 5? num1? num2? 4? num3? 8? 9? 10? 11(5? 3? 3? 4? 3? 8? 9? 10? 11),第一次排序,key值為 5,cur 在后面找比 5 小的元素然后和 ++prev 位置交換(雙指針算法找 key 值),所以第一次排序之后結果為 num3? num1? num2? 4? 5? 8? 9? 10? 11,此時相對位置發生了變化,所以快速排序算法也是一種不穩定的排序算法。


3) 七大排序算法時空復雜度與穩定性總結

?以下表格是對七大排序的時空復雜度以及穩定性的總結:
?

七大排序算法總結
排序算法時間復雜度空間復雜度穩定性
直接插入排序O(n^2)O(1)穩定
直接選擇排序O(n^2)O(1)不穩定
希爾排序O(n^1.3)O(1)不穩定
冒泡排序O(n^2)O(1)穩定
堆排序O(nlogn)O(1)不穩定
快速排序O(nlogn)O(logn) ~ O(n)不穩定
歸并排序O(nlogn)O(n)穩定

3? 總結

? ? ? ? 到這里,初階數據結構的知識就已經結束了,我們來回顧一下:在初階數據結構里面,我們學習了順序表、鏈表、棧、隊列以及二叉樹這五種數據結構,學習了 8 種排序算法;不僅通過具體代碼實現了每個數據結構,而且還通過具體題目來加深了對于數據結構的理解,相信在學習完初階數據結構之后,代碼能力肯定會提升很多。

? ? ? ? 在之后,我們會開啟新的模塊的學習,包括 C++語言、Linux操作系統以及高階數據結構和各種經典算法,比如遞歸、回溯、動態規劃、雙指針算法等,在后面的文章中會交叉更新不同內容,后面的難度也肯定會呈不斷遞增的趨勢,但是只要繼續學下去,肯定就會收獲滿滿,所以不要放棄哦!

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

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

相關文章

mysql的一個缺點

最近再移植一個從oracle轉mysql的項目&#xff0c;喜提一個報錯&#xff1a; You cant specify target table A016 for update in FROM clause 對應的程序代碼&#xff1a; public void setCurrent(String setId, String pk, String userId) throws SysException {String[]…

Ubuntu 上安裝 FTP 服務、開放指定端口并創建用戶

一、安裝 FTP 服務&#xff08;vsftpd&#xff09; sudo apt update sudo apt install vsftpd -y二、修改 vsftpd 配置&#xff0c;使用 21000 端口 編輯配置文件&#xff1a; sudo nano /etc/vsftpd.conf修改或添加以下配置&#xff1a; 使用以下配置文件需要修改的地方:l…

用自寫的jQuery庫+Ajax實現了省市聯動

1. 省市聯動&#xff1a;在網頁上&#xff0c;選擇對應的省份之后&#xff0c;動態的關聯出該省份對應的市。選擇對應的市之后&#xff0c;動態地關聯出城市對應的區。 2. 設計數據庫表 t_area &#xff08;區域表&#xff09; id(PK-自增) code name pcode ------------…

【行為型之迭代器模式】游戲開發實戰——Unity高效集合遍歷與場景管理的架構精髓

文章目錄 &#x1f504; 迭代器模式&#xff08;Iterator Pattern&#xff09;深度解析一、模式本質與核心價值二、經典UML結構三、Unity實戰代碼&#xff08;背包系統遍歷&#xff09;1. 定義迭代器與聚合接口2. 實現具體聚合類&#xff08;背包物品集合&#xff09;3. 實現具…

18前端項目----Vue項目收尾優化|重要知識

收尾/知識點匯總 項目收尾二級路由未登錄全局路由守衛路由獨享守衛圖片懶加載路由懶加載打包上線 重要知識點匯總組件通信方式1. props2. 自定義事件3. 全局事件總線4. 訂閱與發布pubsub5. Vuex6. 插槽 sync修飾符attrs和listeners屬性children和parent屬性mixin混入作用域插槽…

【Linux】基礎指令(Ⅱ)

目錄 1. mv指令 2. cat指令 3.echo指令 補&#xff1a;輸出重定向 4. more指令 5. less指令 6. head指令和tail指令 7.date指令 時間戳&#xff1a; 8. cal指令 9. alias指令 10.grep指令 1. mv指令 語法&#xff1a;mv [選項]... 源文件/目錄 目標文件/目錄 …

docker及docker-compose安裝及使用

docker compose &#x1f517;官網地址 一、為什么要使用docker compose 1. 簡化管理 ? 通過一個 YAML 文件定義和管理多容器應用。 ? 簡化服務間的編排與協調&#xff0c;方便環境的管理與復制。 2. 提升協作效率 ? 配置文件易于共享&#xff0c;便于開發、運維等團隊協…

JVM學習專題(二)內存模型深度剖析

目錄 1.JVM結構體系 ?編輯 2.跨平臺特性 3.JVM整體結構及內存模型 1.棧內存 1、棧幀&#xff1a; 1.局部變量表 2.操作數棧 3.動態鏈接 4.方法出口 2、創建對象 2.程序計數器&#xff1a; 3.方法區 ?4.堆 5.本地方法區 6.總結 1.JVM結構體系 JDK、JRE 和 JVM…

Flink之Table API

Apache Flink 的 Table API 是 Flink 提供的一種高級抽象&#xff0c;用于以聲明式方式處理批處理和流處理數據。它是基于關系模型的 API&#xff0c;用戶可以像編寫 SQL 一樣&#xff0c;以簡潔、類型安全的方式編寫數據處理邏輯。 一、基本概念 1. 什么是 Table API&#xf…

基于Vue3.0的高德地圖api教程005:實現繪制線并編輯功能

文章目錄 6、繪制多段線6.1 繪制多段線6.1.1 開啟繪制功能6.1.2 雙擊完成繪制6.1.3 保存到數據庫6.2 修改多段線6.2.1 點擊線,進入編輯模式6.2.2 編輯線6.3 完整代碼6、繪制多段線 6.1 繪制多段線 6.1.1 開啟繪制功能 實現代碼: const changeSwitchDrawPolyline = ()=>…

“redis 目標計算機積極拒絕,無法連接” 解決方法,每次開機啟動redis

如果遇到以上問題 先打開“服務” 找到App Readiness 右擊-啟動 以管理員身份運行cmd&#xff0c;跳轉到 安裝redis的目錄 運行&#xff1a;redis-server.exe redis.windows.conf 以管理員身份打開另一cmd窗口&#xff0c;跳轉到安裝redis的目錄 運行&#xff1a;redis-…

Java 大視界——Java 大數據在智慧交通智能停車誘導系統中的數據融合與實時更新

面對城市停車資源錯配導致的30%以上交通擁堵問題&#xff0c;本文以某新一線城市智慧交通項目為藍本&#xff0c;深度解析Java大數據技術如何實現多源停車數據融合、動態路徑規劃與誘導策略優化。通過構建“感知-計算-決策”全鏈路系統&#xff0c;實現車位狀態更新延遲<200…

牛客周賽 Round 92(再現京津冀藍橋杯???)

1. 小紅的簽到題 現在小紅希望你寫出一個長度為 nnn 的、使用了下劃線命名法命名的變量。為了顯出特征&#xff0c;請保證該變量至少由兩個單詞組成。 輸入描述: 輸入一個正整數 n(3≦n≦100)&#xff0c;代表需要構造的變量長度。 輸出描述: 輸出一個長度為 n 的字符串&#x…

2025-05-11 Unity 網絡基礎11——UnityWebRequest

文章目錄 1 UnityWebRequest 介紹2 搭建 HTTP 服務器3 常用操作3.1下載資源3.1.1 下載文本3.1.2 下載圖片3.1.3 下載 AB 包 3.2 上傳資源3.2.1 上傳數據類3.2.2 POST 上傳3.3.3 PUT 上傳 4 自定義操作4.1 下載資源4.1.1 Unity 內置 Handler4.1.2 自定義 Handler 4.2 上傳資源4.…

GitHub 趨勢日報 (2025年05月09日)

本日報由 TrendForge 系統生成 https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日整體趨勢 Top 10 排名項目名稱項目描述今日獲星總星數語言1voideditor/void? 1879? 15214TypeScript2ruanyf/weekly科技愛好者周刊&…

.NET MAUI 基礎知識

文章目錄 什么是 .NET MAUI&#xff1f;MAUI的核心特點與Xamarin.Forms的區別 開發環境搭建安裝Visual Studio 2022安裝必要組件配置Android開發環境配置iOS開發環境驗證安裝 創建第一個MAUI應用創建新項目MAUI項目結構解析理解關鍵文件運行應用程序簡單修改示例使用熱重載 MAU…

卷積神經網絡全連接層詳解:特征匯總、FCN替代與性能影響分析

【內容摘要】 本文聚焦卷積神經網絡&#xff08;CNN&#xff09;的全連接層&#xff0c;詳細介紹其將二維特征圖轉化為一維向量的過程&#xff0c;闡述全卷積網絡&#xff08;FCN&#xff09;如何通過轉置卷積替代全連接層以實現像素級分類&#xff0c;并分析全連接層對圖像分類…

在C++中進行套接字編程時,主要使用以下頭文件

目錄 一.基本套接字頭文件<sys/socket.h><netinet/in.h><arpa/inet.h><unistd.h><netdb.h> 二. 完整示例頭文件包含三. 注意事項 在C中進行套接字編程時&#xff0c;主要使用以下頭文件&#xff1a; 一.基本套接字頭文件 <sys/socket.h>…

【Linux網絡】HTTP

應用層協議 HTTP 前置知識 我們上網的所有行為都是在做IO&#xff0c;&#xff08;我的數據給別人&#xff0c;別人的數據給我&#xff09;圖片。視頻&#xff0c;音頻&#xff0c;文本等等&#xff0c;都是資源答復前需要先確認我要的資源在哪臺服務器上&#xff08;網絡IP&…

JAVA異常體系

在 Java 里&#xff0c;異常體系是其錯誤處理機制的核心內容&#xff0c;它能夠幫助開發者有效應對程序運行時出現的各種意外狀況。 異常體系的基本架構 它主要包含兩個重要分支&#xff1a; Error&#xff08;錯誤&#xff09;&#xff1a;這類異常是程序自身無法處理的嚴重…