【數據結構】一文了解七大排序算法

文章目錄

  • 前言
  • 一.直接插入排序
    • 插入排序思想
    • 插入排序代碼實現
    • 插入排序總結
  • 二.希爾排序
    • 希爾排序思想
    • 希爾排序代碼實現
    • 希爾排序總結
  • 三.選擇排序
    • 選擇排序思想
    • 選擇排序代碼實現
    • 選擇排序總結
  • 四.堆排序
    • 堆排序思想
    • 堆排序代碼實現
    • 堆排序總結
  • 五、冒泡排序
    • 冒泡排序思想
    • 冒泡排序代碼實現
    • 冒泡排序總結
  • 六、快速排序
    • 快速排序思想
    • 快速排序代碼實現
    • 快速排序總結
  • 七.歸并排序
    • 歸并排序思想
    • 歸并排序代碼實現
    • 歸并排序總結
  • 總結


在這里插入圖片描述

前言

所謂排序算法,即通過特定的算法因式將一組或多組數據按照既定模式進行重新排序。這種新序列遵循著一定的規則,體現出一定的規律,因此,經處理后的數據便于篩選和計算,大大提高了計算效率。對于排序,我們首先要求其具有一定的穩定性,即當兩個相同的元素同時出現于某個序列之中,則經過一定的排序算法之后,兩者在排序前后的相對位置不發生變化。換言之,即便是兩個完全相同的元素,它們在排序過程中也是各有區別的。今天,我們介紹一下常見的排序算法。
在這里插入圖片描述


一.直接插入排序

在這里插入圖片描述

插入排序思想

插入排序算法是基于某序列已經有序排列的情況下,通過一次插入一個元素的方式按照原有排序方式增加元素。這種比較是從該有序序列的最末端開始執行,即要插入序列中的元素最先和有序序列中最大的元素比較,若其大于該最大元素,則可直接插入最大元素的后面即可,否則再向前一位比較查找直至找到應該插入的位置為止。插入排序的基本思想是,每次將1個待排序的記錄按其關鍵字大小插入到前面已經排好序的子序列中,尋找最適當的位置,直至全部記錄插入完畢。執行過程中,若遇到和插入元素相等的位置,則將要插人的元素放在該相等元素的后面,因此插入該元素后并未改變原序列的前后順序。我們認為插入排序也是一種穩定的排序方法。

插入排序代碼實現

void InsertSort(int* a, int n)
{for (int i = 0; i < n-1; i++){int end = i;int tmp = a[end+1];while (end >= 0){if (a[end] > tmp){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;}
}

插入排序總結

直接插入排序的特性總結:

  1. 元素集合越接近有序,直接插入排序算法的時間效率越高
  2. 時間復雜度:O(N^2)
  3. 空間復雜度:O(1),它是一種穩定的排序算法
  4. 穩定性:穩定

二.希爾排序

在這里插入圖片描述

希爾排序思想

希爾排序的思想實際上是將數列一次又一次的預排序,讓數組趨近于有序,之后在進行插入排序得到答案。預排序就是先將數組中的數進行分組,將相隔gap距離的樹分為一組,在一組中進行插入排序使之有序,再將gap逐漸縮小,最后gap等于1時,就是插入排序。通過分組的方法可以讓后面的數更快的來到前面,讓前面的數更快的來到后面。但是gap越大,越不接近有序,gap太小效率提高就不明顯,所以經過前人的多次實驗得到,當gap處于gap=gap/3+1動態變化中時效率較高。

希爾排序代碼實現

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int i = 0; i < n-gap; i++){int end = i;int tmp = a[end + gap];while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end = end - gap;}else{break;}}a[end + gap] = tmp;}}}

希爾排序總結

希爾排序的特性總結:

  1. 希爾排序是對直接插入排序的優化。
  2. 當gap > 1時都是預排序,目的是讓數組更接近于有序。當gap == 1時,數組已經接近有序的了,這樣就
    會很快。這樣整體而言,可以達到優化的效果。我們實現后可以進行性能測試的對比。
  3. 希爾排序的時間復雜度不好計算,因為gap的取值方法很多,導致很難去計算,一般認為是O(n^1.5)
  4. 穩定性:不穩定

三.選擇排序

在這里插入圖片描述

選擇排序思想

選擇排序的思想比較簡單,首先我們需要遍歷一遍數組,找到最小的值,再將最先的值與第一個值交換,這樣就排好了第一個數。以此類推,遍歷后面的數組,再找最小的數,與前面交換,最后有序。我們也可以升級一下,遍歷一次數組,找到最大最小的兩個數,最小的放前面,最大的放后面。但是要注意當你交換完最小的數后,最大的那個數可能位置會變化,要單獨討論。

選擇排序代碼實現

void SelectSort(int* a, int n)
{int right = n - 1;int left = 0;for (right = n - 1, left = 0; right > left; left++, right--){int maxi = right;int mini = left;for (int i = left; i <= right; i++){if (a[mini] > a[i]){mini = i;}if (a[maxi] < a[i]){maxi = i;}}Swap(&a[left], &a[mini]);if (maxi == left){maxi = mini;}Swap(&a[maxi], &a[right]);}
}

選擇排序總結

  1. 直接選擇排序思考非常好理解,但是效率不是很好。實際中很少使用
  2. 時間復雜度:O(N^2)
  3. 空間復雜度:O(1)
  4. 穩定性:不穩定

四.堆排序

在這里插入圖片描述

堆排序思想

堆排序首先就是建堆,我們通過從倒數第二層開始向下調整建堆。如果排升序就建大堆,排降序建小堆。以升序為例,我們通過建堆在根節點得到最大的數,再將最大的數與最后的數交換位置,最大的數就排好了,再通過建堆找第二大的數,最后有序。

堆排序代碼實現

void AdjustDown(HPDataType* a, int n, int parent)
{int child = 2 * parent + 1;while (child < n){if (child+1<n && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void HeapSort(int* a, int n)
{int i = 0;for (i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);end--;AdjustDown(a, end+1, 0);}}

堆排序總結

堆排序的特性總結:

  1. 堆排序使用堆來選數,效率就高了很多。
  2. 時間復雜度:O(N*logN)
  3. 空間復雜度:O(1)
  4. 穩定性:不穩定

五、冒泡排序

在這里插入圖片描述

冒泡排序思想

冒泡排序算法是把較小的元素往前調或者把較大的元素往后調。這種方法主要是通過對相鄰兩個元素進行大小的比較,根據比較結果和算法規則對該二元素的位置進行交換,這樣逐個依次進行比較和交換,就能達到排序目的。冒泡排序的基本思想是,首先將第1個和第2個記錄的關鍵字比較大小,如果是逆序的,就將這兩個記錄進行交換,再對第2個和第3個記錄的關鍵字進行比較,依次類推,重復進行上述計算,直至完成第(n一1)個和第n個記錄的關鍵字之間的比較,此后,再按照上述過程進行第2次、第3次排序,直至整個序列有序為止。排序過程中要特別注意的是,當相鄰兩個元素大小一致時,這一步操作就不需要交換位置,因此也說明冒泡排序是一種嚴格的穩定排序算法,它不改變序列中相同元素之間的相對位置關系。

冒泡排序代碼實現

void BubbleSort(int* a, int n)
{int j = 0, i = 0;for (j = 0; j < n ; j++){for (i = 0; i < n - j - 1; i++){if (a[i] > a[i + 1]){int tmp = a[i];a[i] = a[i + 1];a[i + 1] = tmp;}}}
}

冒泡排序總結

冒泡排序的特性總結:

  1. 冒泡排序是一種非常容易理解的排序
  2. 時間復雜度:O(N^2)
  3. 空間復雜度:O(1)
  4. 穩定性:穩定

六、快速排序

在這里插入圖片描述

快速排序思想

快速排序采用的是分治思想,即在一個無序的序列中選取一個任意的基準元素pivot,利用pivot將待排序的序列分成兩部分,前面部分元素均小于或等于基準元素,后面部分均大于或等于基準元素,然后采用遞歸的方法分別對前后兩部分重復上述操作,直到將無序序列排列成有序序列。

快速排序算法通過多次比較和交換來實現排序,其排序流程如下:
1、首先設定一個分界值,通過該分界值將數組分成左右兩部分。
2、將大于或等于分界值的數據集中到數組右邊,小于分界值的數據集中到數組的左邊。此時,左邊部分中各元素都小于分界值,而右邊部分中各元素都大于或等于分界值。
3、然后,左邊和右邊的數據可以獨立排序。對于左側的數組數據,又可以取一個分界值,將該部分數據分成左右兩部分,同樣在左邊放置較小值,右邊放置較大值。右側的數組數據也可以做類似處理。
4、重復上述過程,可以看出,這是一個遞歸定義。通過遞歸將左側部分排好序后,再遞歸排好右側部分的順序。當左、右兩個部分各數據排序完成后,整個數組的排序也就完成了。

快速排序代碼實現

void QiuckSort(int* a, int left, int right)
{if (left >= right){return;}int keyi = left;int begin = left, end = right;while (end > begin){while(end > begin && a[end] >= a[keyi]){end--;}while (end > begin && a[begin] <= a[keyi]){begin++;}Swap(&a[begin], &a[end]);}Swap(&a[begin], &a[keyi]);QiuckSort(a, left, begin - 1);QiuckSort(a, begin + 1, right);
}

快速排序總結

  1. 快速排序整體的綜合性能和使用場景都是比較好的,所以才敢叫快速排序
  2. 時間復雜度:O(N*logN)
  3. 空間復雜度:O(logN)
  4. 穩定性:不穩定

七.歸并排序

在這里插入圖片描述

歸并排序思想

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

歸并操作的工作原理如下:
第一步:申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合并后的序列
第二步:設定兩個指針,最初位置分別為兩個已經排序序列的起始位置
第三步:比較兩個指針所指向的元素,選擇相對小的元素放入到合并空間,并移動指針到下一位置
重復步驟3直到某一指針超出序列尾
將另一序列剩下的所有元素直接復制到合并序列尾

歸并排序代碼實現

void _MergeSort(int* a, int* tmp, int begin, int end)
{if (begin >= end){return;}int mid = (begin + end) / 2;_MergeSort(a, tmp, begin, mid);_MergeSort(a, tmp, mid + 1, end);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a+begin, tmp+begin, (end - begin + 1) * sizeof(int));
}
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc");return;}_MergeSort(a, tmp, 0, n - 1);free(tmp);tmp == NULL;
}

歸并排序總結

歸并排序的特性總結:

  1. 歸并的缺點在于需要O(N)的空間復雜度,歸并排序的思考更多的是解決在磁盤中的外排序問題。
  2. 時間復雜度:O(N*logN)
  3. 空間復雜度:O(N)
  4. 穩定性:穩定

總結

以上就是今天要講的內容,本文僅僅簡單介紹了幾種常見的排序算法,實際上還有計數排序,桶排序等許多排序算法。如果喜歡這篇文章,期待你的一鍵三連。

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

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

相關文章

Dify 與 Xinference 最佳組合 GPU 環境部署全流程

背景介紹 在前一篇文章 RAG 項目對比 之后&#xff0c;確定 Dify 目前最合適的 RAG 框架。本次就嘗試在本地 GPU 設備上部署 Dify 服務。 Dify 是將模型的加載獨立出去的&#xff0c;因此需要選擇合適的模型加載框架。調研一番之后選擇了 Xinference&#xff0c;理由如下&…

易我分區大師18.8.0更新:兩大功能改進

近日&#xff0c;易我分區大師18.8.0更新上線。此次更新重點改進了系統克隆功能&#xff0c;支持從第二塊系統盤&#xff08;從盤&#xff09;克隆系統&#xff1b;同時&#xff0c;軟件支持將分區的文件系統格式從FAT轉換成exFAT。 01、系統克隆 系統克隆功能旨在幫助用戶在…

pinia學習

conuter.ts <template><div><!-- 顯示當前的計數 --><p>Count: {{ count }}</<!-- 顯示計算的雙倍計數 --><p>Double Count: {{ doubleCount }}</p><!-- 點擊按鈕以增加計數 --><button click"increment">…

基于紅黑樹對map和set的封裝

前言 前面我們已經對紅黑樹做了介紹和實現&#xff0c;本期我們來對紅黑樹進一步改造&#xff0c;然后基于改造后的紅黑樹封裝出map和set&#xff01; 本期內容介紹 ? 紅黑樹的改造 ? 紅黑樹的迭代器實現 ? map的封裝 ? set的封裝 ? 全部源碼 ● 紅黑樹的改造 我們目前…

未來互聯網的新篇章:深度解析Facebook的技術與戰略

隨著科技的飛速發展和社會的不斷變遷&#xff0c;互聯網作為全球信息交流的重要平臺&#xff0c;正經歷著前所未有的變革和演進。作為全球最大的社交媒體平臺之一&#xff0c;Facebook不僅是人們溝通、分享和互動的重要場所&#xff0c;更是科技創新和數字化進程的推動者。本文…

音視頻開發—FFmpeg 從MP4文件中抽取視頻H264數據

文章目錄 MP4文件存放H264數據方式MP4 文件結構概述H.264 數據在 MP4 中的存儲1. ftyp 盒子2. moov 盒子3. mdat 盒子 H.264 數據在 stsd 盒子中的存儲&#xff08;AVC1&#xff09;AVC1與Annex-B 格式&#xff08;裸 H.264 流&#xff09;的區別 從MP4文件中提取H264裸流步驟&…

java使用easypoi模版導出word詳細步驟

文章目錄 第一步、引入pom依賴第二步、新建導出工具類WordUtil第三步、創建模版word4.編寫接口代碼5.導出結果示例 第一步、引入pom依賴 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><…

怎么壓縮視頻?推薦7款必備視頻壓縮軟件免費版(強烈建議收藏)

如今&#xff0c;視頻內容日益豐富&#xff0c;并占據了許多人的日常娛樂和工作生活。然而&#xff0c;隨著高清和超高清視頻的普及&#xff0c;視頻文件的體積也越來越大&#xff0c;給存儲和傳輸帶來了挑戰。因此&#xff0c;學會如何壓縮視頻文件成為了許多人的需求之一。本…

小米官網的數據是怎么優化的?

小米PC端官網首頁的“全部商品分類”功能是用戶瀏覽和選擇商品的重要入口。為了優化這一功能的數據展示和用戶體驗&#xff0c;可以采取以下幾個步驟&#xff1a; 數據加載優化&#xff1a; 懶加載&#xff08;Lazy Loading&#xff09;&#xff1a;當鼠標劃過“全部商品分類”…

實現前端登錄注冊功能(有源碼)

引言 用戶登錄和注冊是任何現代Web應用程序的基本功能。在前端開發中&#xff0c;實現一個安全且用戶友好的登錄注冊系統至關重要。本文將介紹如何使用HTML、CSS和JavaScript&#xff08;包括Vue.js&#xff09;來實現前端的登錄和注冊功能。 1. 項目結構 首先&#xff0c;我們…

軟設之訪問者模式

設計模式中訪問者模式的意圖是&#xff1a; 表示一個作用于某對象結構中的各元素的操作&#xff0c;使得在不改變各元素的類的前提下定義作用于這些元素的新操作。 舉個例子&#xff0c;比如說有個游客想去幾個景點&#xff0c;去每個景點都想按統一的流程。但是每個景點都有…

vue3 學習筆記04 -- axios的使用及封裝

vue3 學習筆記04 – axios的使用及封裝 安裝 Axios 和 TypeScript 類型定義 npm install axios npm install -D types/axios創建一個 Axios 實例并封裝成一個可復用的模塊&#xff0c;這樣可以在整個應用中輕松地進行 API 請求管理。 在 src 目錄下創建一個 services 文件夾&…

關于鋰電池的充電過程

鋰電池的充電階段大概可以分為四個階段&#xff1a;涓流充電、恒流充電、恒壓充電以及充電終止。 涓流充電&#xff1a;這是充電過程的第一階段&#xff0c;主要用于對完全放電的電池單元進行預充&#xff08;恢復性充電&#xff09;。當電池電壓低于大概3V時&#xff0c;采用最…

【學習css1】flex布局-頁面footer部分保持在網頁底部

中間內容高度不夠屏幕高度撐不開的頁面時候&#xff0c;頁面footer部分都能保持在網頁頁腳&#xff08;最底部&#xff09;的方法 1、首先上圖看顯示效果 2、奉上源碼 2.1、html部分 <body><header>頭部</header><main>主區域</main><foot…

PaintsUndo - 一張照片一鍵生成繪畫過程視頻 本地一鍵整合包下載

這就是ControlNet作者張呂敏大佬的新作&#xff0c;PaintsUndo。只要你有一張圖片&#xff0c;PaintsUndo 就能讓它變成完整的繪畫過程視頻。這科技&#xff0c;絕了。 你有沒有想過&#xff0c;一張靜態圖片也能變成一個繪畫教程? PaintsUndo 就是這么神奇。你只需要提供一…

通過手機供網、可修改WIFI_MAC的網絡設備

一、修改WIFI mac&#xff08;bssid&#xff09; 取一根網線&#xff0c;一頭連著設備黃色網口、一頭連著電腦按住設備reset按鍵&#xff0c;插入電源線&#xff0c;觀察到藍燈閃爍后再松開reset按鍵 打開電腦瀏覽器&#xff0c;進入192.168.1.1&#xff0c;選擇“MAC 地址修改…

【Spring Boot】Spring原理:Bean的作用域和生命周期

目錄 Spring原理一. 知識回顧1.1 回顧Spring IOC1.2 回顧Spring DI1.3 回顧如何獲取對象 二. Bean的作用域三. Bean的生命周期 Spring原理 一. 知識回顧 在之前IOC/DI的學習中我們也用到了Bean對象&#xff0c;現在先來回顧一下IOC/DI的知識吧&#xff01; 首先Spring IOC&am…

可視化學習:如何用WebGL繪制3D物體

在之前的文章中&#xff0c;我們使用WebGL繪制了很多二維的圖形和圖像&#xff0c;在學習2D繪圖的時候&#xff0c;我們提過很多次關于GPU的高效渲染&#xff0c;但是2D圖形的繪制只展示了WebGL部分的能力&#xff0c;WebGL更強大的地方在于&#xff0c;它可以繪制各種3D圖形&a…

C語言之數據在內存中的存儲(2),浮點數在內存中的存儲

目錄 前言 一、引例 二、浮點型在內存中的存儲 三、浮點數在內存中的存和取過程 1.浮點數的存儲過程 2.浮點數的取過程 四、引例解析 總結 前言 想知道浮點數在內存中是如何存儲的嗎&#xff0c;本文就告訴你答案&#xff0c;雖然一般情況題目還是面試涉及到浮點數在內…

新華三H3CNE網絡工程師認證—ACL使用場景

ACL主要用于實現流量的過濾&#xff0c;業務中網絡的需求不止局限于能夠連同。 一、過略工具 你的公司當中有研發部門&#xff0c;包括有財務部門&#xff0c;財務部門的訪問是要做到控制的&#xff0c;防止被攻擊。 這種的過濾方法為&#xff0c;在設備側可以基于訪問需求來…