【排序】插入排序,希爾排序

前面我們講述了冒泡排序和選擇排序,我們本章講的排序方法是插入排序,插入排序是希爾排序實現的基礎函數,大家一定要好好理解插入排序的邏輯,這樣才能在后面學習希爾排序的時候,更容易的去理解,我們直接開始。

目錄

插入排序(以升序為例)

基本思想:

思路

代碼實現:

總結

希爾排序

基本思想:

一組一組依次排序代碼實現

多組同時排序

希爾排序的時間復雜度分析

總結

總結


插入排序(以升序為例)

基本思想:

直接插入排序是一種簡單的插入排序法,其基本思想是:
把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中,直到所有的記錄插入完為止,得到一個新的有序序列 。

就和我們打牌時,從小到大排牌序,當拿到一張新牌時,我們從后往前找,當最后的牌大于此時的牌,那么就讓最后一張牌向后挪動一位,繼續和倒數第二張比較,若倒數第二張小于此時的牌,就說明找到了位置,將此時的牌插入即可。

如上圖中,此時的牌為7,那么我們從后往前找,發現10>7,那么10就往后挪動,繼續向前找,發現是5,而5<7,說明找到了合適的位置將7放入5的后面即完成了插入排序。

思路

當插入第i(i>=1)個元素時,前面的array[0],array[1],…,array[i-1]已經排好序,此時用array[i]的排序碼與array[i-1],array[i-2],…的排序碼順序進行比較,找到插入位置即將array[i]插入,原來位置上的元素順序后移

由于插入排序插入第i個元素時,需要前i-1個元素都是有序的,因此我們仍然需要從第1個元素開始排序

假設我們目前前i個是有序的,我們排序的就是第i+1個元素,我們用tmp記錄a[i+1]的值,然后從后往前開始依次比較,由下標i到下標0,我們再創建循環,用變量(j=i , j >= 0 , j - -)控制循環

當 a[j] > tmp時,a[j]就向后挪動,即a[j+1] = a[ j ]??

當a[j] < tmp 時,說明已經找到了合適的位置,直接跳出循環,并將j+1的位置賦值為tmp即可

以下便是邏輯圖:?

以上是找到比tmp小正常插入的情況 ,還有一種情況,當數組在tmp前內沒有比tmp小的元素時,那么就會將小數放到數組首位,邏輯圖如下,還是上面數組的例子。

動態邏輯圖

代碼實現:

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

小結

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

希爾排序

希爾排序法又稱縮小增量法。希爾排序已經算是是排序中的大哥了,所以也比較難以理解,他是與快速排序,堆排序,歸并排序在同一條賽道上的排序算法,十分的厲害。

基本思想:

希爾排序法的基本思想是:先選定一個整數,把待排序文件中所有記錄分成個組,所有距離為的記錄分在同一組內,并對每一組內的記錄進行排序。然后,取,重復上述分組和排序的工作。當到達=1時,所有記錄在統一組內排好序。

可能比較難理解,希爾排序分為兩個部分,首先進行預排序,再進行插入排序

預排序:跨元素進行分組排序,讓數組更接近有序,這樣再進行插入排序的時候,基本都是在有序的情況下,那么再進行插入排序就減少了數組挪動的次數,效率更高了。

我們假設跳的距離為gap,gap初始值為3

看一下邏輯圖,我們就明白進行預排序后的效果

下面我們來單獨實現代碼,我們可以將代碼拆分成幾個小部分,依次實現,這樣會讓代碼實現變得更加容易實現,這便是由小及大的思想

我們先來實現對單個分組排序的實現,即對紅色排序的實現

代碼實現的底層邏輯,依然是插入排序,只不過在進行遍歷和比較的時候是一次跳躍gap個元素

大家看一下代碼實現應該就能理解

部分代碼實現

int gap = 3;
for (size_t i = 0; i < n - gap; i+=gap)
{int tmp = a[i + gap];int j = 0;for (j = i; j >= 0; j-= gap){if (a[j] > tmp){a[j + 1] = a[j];}else{break;}}a[j + gap] = tmp;
}

在完成單趟邏輯后,然后我們再建一個for循環,讓gap組依次進行排序,即完成了一組一組依次排序的邏輯實現

一組一組依次排序代碼實現

	int gap = 3;for (int k = 0; k < gap; k++){for (size_t i = k; i < n - gap; i += gap){int tmp = a[i + gap];int j = 0;for (j = i; j >= 0; j -= gap){if (a[j] > tmp){a[j + 1] = a[j];}else{break;}}a[j + gap] = tmp;}}

還有一種實現方法,是令多組同時進行排序,只需要修改一下邏輯代碼即可

多組同時排序

int gap = 3;
for (size_t i = 0 ; i < n - gap; i++)
{int tmp = a[i + gap];int j = 0;for (j = i; j >= 0; j -= gap){if (a[j] > tmp){a[j + 1] = a[j];}else{break;}}a[j + gap] = tmp;
}

二者的邏輯圖如圖所示

希爾排序的時間復雜度分析

希爾排序的時間復雜度比較難計算,因為gap的取值方法很多,導致很難去計算

我們通過上面的邏輯分析,發現 在預排序階段

gap越大,大的數可以更快的跳到后面,小的數可以更快的跳到前面,越不接近有序

gap越小,大的數跳到后面越慢,小的數跳到前面越慢,但越接近有序

因此控制gap的大小是增加效率的直接辦法

但是如何取最適合的gap呢,根據大量數據統計,我們發現當gap = n/3時效率最高,但是我們需要+1,保證gap最后等于1

代碼如下

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){// +1保證最后一個gap一定是1// gap > 1時是預排序// gap == 1時是插入排序gap = gap / 3 + 1;for (size_t i = 0; i < n - gap; ++i){int end = i;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

我們以n/3為例,以gap對時間復雜度的影響進行分析

如下

?代碼實現

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){// +1保證最后一個gap一定是1// gap > 1時是預排序// gap == 1時是插入排序gap = gap / 3 + 1;for (size_t i = 0; i < n - gap; ++i){int end = i;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

小結

1. 希爾排序是對直接插入排序的優化。


2. 當gap > 1時都是預排序,目的是讓數組更接近于有序。當gap == 1時,數組已經接近有序的了,這樣就會很快。這樣整體而言,可以達到優化的效果。我們實現后可以進行性能測試的對比。


3. 希爾排序的時間復雜度不好計算,因為gap的取值方法很多,導致很難去計算,因此在好些樹中給出的希爾排序的時間復雜度都不固定,通過數據統計,希爾排序的時間復雜度大概為O(n^1.3)

4. 穩定性:不穩定

總結

以上是對插入排序和希爾排序的分析,是一種新的排序思想,其中的種種知識點也很碎很多,希望大家能夠有所收獲。

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

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

相關文章

關于無法通過腳本啟動Kafka集群的解決辦法

啟動Kafka集群時&#xff0c;需要在每臺個節點上啟動啟動服務&#xff0c;比較麻煩&#xff0c;通過寫了以下腳本來進行啟停&#xff1b;發現能正常使用停止功能&#xff0c;不能正常啟動Kafka&#xff1b; Kafka啟停腳本&#xff1a; ## 以防不能通過shell腳本啟動Kafka服務…

富格林:揭露黑幕平臺保障安全

富格林指出&#xff0c;很多黑幕平臺都會將自己包裝得光鮮亮麗后&#xff0c;再出來誘惑投資者&#xff0c;使得投資者資金安全得不到保障&#xff0c;有苦說不出。富格林表示&#xff0c;黑幕平臺的套路其實是非常常見的&#xff0c;只要投資者熟知并能夠分辨出&#xff0c;就…

C盤擴容——只能刪除C盤右邊的磁盤對C盤進行擴展

winR彈出命令框 輸入&#xff1a;compmgmt.msc 進入磁盤管理頁面 注意&#xff1a;被刪除盤如果有重要數據信息&#xff0c;請備份。 或者刪除之前轉移至其他盤&#xff0c;否則刪除之后&#xff0c;則無法找回。 尤其是安裝的軟件。 規范安裝目錄十分重要。 將C盤右邊的磁盤&a…

最全 Inno Setup 教程-[FILE] Flag參數

【1】此參數是一個附加選項的集合。可以使用空格將多個選項分隔開。 【2】支持以下選項&#xff1a; 32位 當在“Source”和“DestDir”參數中使用{sys}常量時&#xff0c;將該常量映射到32位系統目錄。將“regserver”和“regtypelib”標志設置為將文件視為32位&#xff0c;…

安防綜合管理系統EasyCVR視頻匯聚平臺GA/T 1400協議中的關鍵消息交互示例

在當今的信息化時代&#xff0c;公共安全防范日益成為保障社會和諧穩定的關鍵。視頻監控系統作為現代安全防范的重要手段&#xff0c;正不斷在公安、交通、城市管理等領域發揮著越來越重要的作用。而GA/T 1400協議視圖庫&#xff0c;作為公安視頻圖像信息應用系統的標準&#x…

Vue3 子組件訪問父組件的方法 - 父組件訪問子組件的屬性或方法 - 子組件修改父組件的值

一。子組件訪問父組件的方法 //父組件 <DialogEditing close-dialog"handleClose" /> const handleClose () > {};//子組件 const emit defineEmits(["closeDialog"]); const close () > {emit("closeDialog"); // 使用 };二。父…

健身日記之倒立俯臥撐學習——起始日2024.6.4

文章目錄 前言 自我介紹 昔日計劃 新目標計劃 瓶頸突破嘗試 參考視頻及文章 前言 有輕微健身基礎&#xff0c;正式接觸街健五大神技&#xff0c;立志在兩年內解鎖全部&#xff0c;將有機會的進行日常訓練和目標肌群鍛煉&#xff0c;這里向大家展示我的計劃和安排&#xf…

opencv-python(五)

opencv的顏色通道中順序是B&#xff0c;G&#xff0c;R。 圖像屬性 import cv2img cv2.imread(jk.jpg) print(fshape{img.shape}) print(fsize{img.size}) print(fdtype{img.dtype}) shape&#xff1a;圖像像素的行&#xff0c;列&#xff0c;通道 size&#xff1a;行數 X …

YonSuite收款通,助力企業618更快收款

隨著電商節日“618”的臨近&#xff0c;各大企業紛紛摩拳擦掌&#xff0c;準備在這場年中大促中大展身手。然而&#xff0c;隨著銷售額的激增&#xff0c;收款管理問題也愈發凸顯&#xff0c;成為制約企業快速發展的重要瓶頸。在這個關鍵時刻&#xff0c;YonSuite收款通憑借其卓…

Python實現登錄到遠程主機,然后在遠程主機上繼續連接遠程主機

實現功能 登錄到遠程主機&#xff0c;然后在遠程主機上繼續連接遠程主機&#xff0c;執行命令。 import paramiko import time# 第二個遠程主機的連接信息&#xff08;在第一個遠程主機上執行SSH連接時使用&#xff09; second_remote_host 192.168.xx.xxx # 創建SSH客…

通過命令行將tar壓縮文件解壓縮到指定目錄|Linux

要將all.tar文件解壓縮到指定目錄下&#xff0c;你可以使用Linux命令行中的tar命令。以下是具體步驟&#xff1a; 打開終端&#xff08;Terminal&#xff09;。 使用cd命令切換到你想要解壓縮文件的目標目錄。例如&#xff1a; cd /path/to/your/directory將/path/to/your/dir…

echarts圖例formatter配置添加百分比

echarts圖例如何添加百分比 const pieChart async () > {const myChart echarts.init(piepic.value)const piedata await getPieData(); // 等待數據返回myChart.setOption({title: {},grid: {},tooltip: {trigger: item,},legend: {top: middle,align:left,icon: circl…

都可以寫好后端接口

在后端工程師的日常開發中&#xff0c;我們都曾想過 怎么設計一個良好的接口呢&#xff1f;需要考慮的點有哪些。來 給您。 1、請求參數校驗 這個是大家都能想到的&#xff0c;也是一個良好的接口必備的前提條件&#xff0c;通過入參的校驗我們可以過濾掉許多無效的請求&…

零基礎學Java第二十七天之前端-HTML5詳解

前端-HTML5詳解 一、概述 HTML5是HTML的第五個版本&#xff0c;它對HTML進行了許多改進和擴展&#xff0c;使得網頁開發更加豐富和便利。HTML5是Web標準的重要組成部分&#xff0c;旨在提高瀏覽器兼容性&#xff0c;統一網頁開發標準。HTML5不僅包括了HTML的基本元素和標簽&am…

前端js解析websocket推送的gzip壓縮json的Blob數據

主要依賴插件pako https://www.npmjs.com/package/pako 1、安裝 npm install pako 2、使用&#xff0c; pako.inflate(reader.result, {to: "string"}) 解壓后的string 對象&#xff0c;需要JSON.parse轉成json this.ws.onmessage (evt) > {console.log("…

vue使用html2canvas截圖下載時,存在svg或者img時截圖不全的解決辦法

使用html2canvas進行div截圖時&#xff0c;存在svg和img的解決辦法 寫在前面&#xff1a;vue使用html2canvas截圖時&#xff0c;存在svg或者img時截圖時空白&#xff0c;或者不全解決辦法如下第一步&#xff0c;svg或者img先轉base64第二步&#xff0c;將轉換后的base64設置為新…

電源小白入門學習10——浪涌、防浪涌器件、浪涌保護芯片

浪涌、防浪涌器件、浪涌保護芯片 浪涌浪涌保護器件的分類與原理保險絲TVS二極管新防護電路 浪涌 浪涌&#xff0c;相信不少學習過電子的同學或多或少都通過這個詞&#xff0c;但是到底什么是浪涌呢&#xff0c;GPT給我的答案是這樣的&#xff1a; 浪涌&#xff0c;也稱為瞬態…

【雜記-IDS入侵檢測系統、IPS入侵防御系統】

一、IDS概述、分類 IDS概述 IDS&#xff0c;intrusion detection system&#xff0c;入侵檢測系統&#xff0c;其對網絡傳輸進行即時監視&#xff0c;在發現可疑傳輸時發出警報或者采取主動反應措施的網絡安全設備&#xff0c;是一種積極主動的安全防護技術。與防火墻不同的是…

【深度學習】【機器學習】支持向量機,網絡入侵檢測,KDD數據集

文章目錄 環境加載數據歸一化數據訓練模型用測試數據集給出評估指標準確率召回率預測某個輸入數據隨便取一行數據加載訓練好的SVM支持向量機模型并預測 全部數據和代碼下載 環境 之前介紹過用深度學習做入侵檢測&#xff0c;這篇用向量機。 環境Python3.10 requirements.txt…

【miniconda】安裝miniconda

☆ 問題描述 ubuntu環境下安裝miniconda ★ 解決方案 ubuntu環境下安裝miniconda 下載miniconda 包 miniconda官網地址&#xff1a;https://docs.conda.io/en/latest/miniconda.html 清華大學鏡像地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/anaconda/minicon…