幾種排序的實現

直接插入排序

直接插入排序是一種簡單的插入排序法,其基本思想是:

把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中,直到所有的記錄插入完為止,得到一個新的有序序列 。

實際中我們玩撲克牌時,就用了插入排序的思想:
就是,第一次摸牌我們把它放在第一張,第二次就和第一張比較,比它大就放在他的后面,否則就放在他的前面,摸第三張的時候先和后面大的一張牌開始比較,依次向前。
在這里插入圖片描述
總結來說就是:
當插入第i(i>=1)個元素時,前面的array[0],array[1],…,array[i-1]已經排好序,此時用array[i]的排序碼與array[i-1],array[i-2],…的排序碼順序進行比較,找到插入位置即將array[i]插入,原來位置上的元素順序后移

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

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

下面我們對直接插入排序進行代碼的實現
插入排序很簡單
我們將第二個元素開始向后遍歷,i=1,令end=i-1,并且保存a[i]的值
當a[end]大于此前i下標的元素的值時,將其調整,將end位置的值移動到end后面一個位置,同時end–,如果是小于的,那就直接跳出循環,就代表了前面的所有值都是升序的

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

希爾排序

希爾排序法又稱縮小增量法。希爾排序法的基本思想是:先選定一個整數,把待排序文件中所有記錄分成個組,所有距離為的記錄分在同一組內,并對每一組內的記錄進行排序。
在這里插入圖片描述
下面為代碼實現:
我們開始令gap為n的三分之一+1,加一是因為gap不能等于0,一般情況下gap是數組長度的三分之一是比較合適的
后面的邏輯就和插入排序差不多了
后面的for循環時各個分組的數字同時進行排序

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 temp = a[end + gap];while (end >= 0){if (a[end] > a[temp]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = temp;}}
}

希爾排序的特性總結:

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

選擇排序

選擇排序的思想就是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完 。
代碼實現:
第一次找出最大值最小值的下標,然后放在首尾
交換值,然后begin和end分別被前進和后退

void SelectSort(int* a, int n)
{assert(a);int begin = 0, end = n - 1;while (begin < end){int min = begin, max = begin;for (int i = begin; i <= end; i++){if (a[i] >= a[max])max = i;if (a[i] < a[min])min = i;}Swap(&a[begin], &a[min]);//如果最大的位置在begin位置//說明min是和最大的交換位置//這個時候max的位置就發生了變換//max變到了min的位置//所以要更新max的位置if (begin == max)max = min;Swap(&a[end], &a[max]);++begin;--end;}

快速排序

快速排序是Hoare于1962年提出的一種二叉樹結構的交換排序方法,其基本思想為:
任取待排序元素序列中的某元素作為基準值,按照該排序碼將待排序集合分割成兩子序列,左子序列中所有元素均小于基準值,右子序列中所有元素均大于基準值,然后最左右子序列重復該過程,直到所有元素都排列在相應位置上為止

總結下來就是:
我們將小于中間位置的值的放在左邊,大于的放在右邊,然后再對左邊進行一樣的劃分,右邊也是,用遞歸實現即可

在實現快排前我們先定義一個找中間下標的函數:
也就是常說的三數取中,有利于更好更快得完成快排

int getmidindex(int* a, int left, int right)
{int midi = (left + right) / 2;if (a[left] < a[midi]){if (a[midi] < a[right]){return midi;}else if (a[left] < a[right]){return right;}elsereturn left;}else//a[left] >=a[midi]{if (a[midi] > a[right]){return midi;}else if (a[left] > a[right]){return right;}elsereturn left;}
}

快速排序一共有三種方法:

  1. hoare版本
    這種方法我們統稱為霍爾法:
    就是我們將數組的第一個元素的值賦值給key,然后分別從左右 開始遍歷,右邊先走,一旦找到比key小的就停下來,然后左邊開始走,左邊找到大的就停下來,然后兩個位置的值互換,知道二者相遇,將key位置的值和他們相遇位置的值交換,最后返回這個位置的下標
    在這里插入圖片描述
    代碼實現:
int partsort1(int* a, int left, int right)
{int midi = getmidindex(a, left, right);swap(&a[left], &a[midi]);int keyi = left;while (left < right){while (left < right && a[right] >= a[keyi]){right--;}while (left < right && a[left] <= a[keyi]){left++;}swap(&a[left], &a[right]);}swap(&a[keyi], &a[left]);return left;
}
void quicksort(int* a, int begin, int end)
{if (begin >= end)return;int midi = partsort1(a, begin, end);quicksort(a, begin, midi - 1);quicksort(a, midi + 1, end);
}
  1. 挖坑法版本
    挖坑法就是把第一個元素存放到臨時變量key中,形成一個坑位,然后右邊先走,右邊遇到比key小的,就把它給此位置的值放入坑位中,此位置就是新的坑位,然后左邊開始找大的,如果出現大的就把值填入坑位中,然后此位置就是新的坑位,一直到left和right相遇時,就把挖出來的key值填入坑位中,并且返回這個坑位的下標
    在這里插入圖片描述
    過程如下圖:
    最后省略了一部分,依次類推即可
    在這里插入圖片描述

代碼實現如下:

int partsort2(int* a, int left, int right)
{int midi = getmidindex(a, left, right);swap(&a[left], &a[midi]);int hole = left;int key = a[left];while (left < right){while (left < right && a[right] >= key){right--;}a[hole] = a[right];hole = right;while (left < right && a[left] <= key){left++;}a[hole] = a[left];hole = left;}a[hole] = key;return hole;
}
void quicksort(int* a, int begin, int end)
{if (begin >= end)return;int midi = partsort1(a, begin, end);quicksort(a, begin, midi - 1);quicksort(a, midi + 1, end);
}
  1. 前后指針版本
    我們首先令第一個位置的下標為prev,他的下一個位置為cur,并且記錄第一個位置的值為key
    然后cur先后遍歷,當cur遇到小于key的值時,將prev和cur位置的值交換,并且再prev+1不等于cur的情況下prev進行+1操作(如果是等于的話就是自己和自己交換,沒有什么意義),同時cur++,當遍歷完成時,最后交換prev位置的值和key的值,返回prev位置的下標
    在這里插入圖片描述
    遍歷過程如下:
    在這里插入圖片描述

代碼實現:

int partsort3(int* a, int left, int right)
{int midi = getmidindex(a, left, right);swap(&a[left], &a[midi]);int prev = left;int cur = left + 1;int keyi = left;while (cur <= right){if (a[keyi] > a[cur] && ++prev != cur){swap(&a[prev] ,&a[cur]);}cur++;}swap(&a[prev] ,&a[keyi]);keyi = prev;return keyi;
}
void quicksort(int* a, int begin, int end)
{if (begin >= end)return;int midi = partsort1(a, begin, end);quicksort(a, begin, midi - 1);quicksort(a, midi + 1, end);
}

歸并排序

歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide andConquer)的一個非常典型的應用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為二路歸并。
他的大概步驟如下:
在這里插入圖片描述
歸并排序的遞歸很簡單:
就是將區間逐一劃分
并且得開辟一塊新的空間,最后將temp直接全部memcpy到目標空間a中

void _mergesort(int* a, int begin, int end, int* temp)
{if (begin >= end)return;int midi = (begin + end) / 2;_mergesort(a,begin, midi,temp);_mergesort(a,midi + 1, end,temp);int begin1 = begin;int begin2 = midi + 1;int end1 = midi;int end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){temp[i++] = a[begin1++];}else{temp[i++] = a[begin2++];}}while (begin1 <= end1){temp[i++] = a[begin1++];}while (begin2 <= end2){temp[i++] = a[begin2++];}memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}
void mergesort(int* a, int n)
{int* temp = (int*)malloc(sizeof(int)*n);_mergesort(a, 0, n-1, temp);free(temp);
}

非遞歸就有點難了:

void mergesortnonr(int* a, int n)
{int* temp =(int*)malloc(sizeof(int) * n);if (temp == NULL){perror("malloc");}int gap = 1;while (gap < n){int j = 0;for (int i = 0; i < n; i += 2*gap){int begin1 = i;int begin2 = i + gap;int end1 = i + gap-1;int end2 = i + 2 * gap - 1;if (end1 >= n || begin2 >= n){break;}if (end2 >= n){end2 = n - 1;//修正}while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){temp[j++] = a[begin1++];}else{temp[j++] = a[begin2++];}}while (begin1 <= end1){temp[j++] = a[begin1++];}while (begin2 <= end2){temp[j++] = a[begin2++];}//每歸并完一組就拷貝一組memcpy(a + i, temp + i, sizeof(int) * (end2 - i + 1));}gap *= 2;}free(temp);
}

歸并排序的特性總結:

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

計數排序

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

  1. 統計相同元素出現次數
  2. 根據統計的結果將序列回收到原來的序列中
    其實計數排序就是用到了數組的映射,當數組元素過多時就不適用了,但是效率很高:
void countsort(int* a, int n)
{int i = 0;int j = 0;int max = a[0];int min = a[0];for (i = 0; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}int range = max - min + 1;int* count = (int*)malloc(sizeof(int) * n);memset(count, 0, sizeof(int) * range);for (i = 0; i < n; i++){count[a[i] - min]++;}int k = 0;for (j = 0; j < range; j++){while (count[j]--){a[k++] = j + min;}}
}

計數排序的特性總結:

  1. 計數排序在數據范圍集中時,效率很高,但是適用范圍及場景有限。
  2. 時間復雜度:O(MAX(N,范圍))
  3. 空間復雜度:O(范圍)

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

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

相關文章

交付《啤酒游戲經營決策沙盤》的項目

感謝首富客戶連續兩年的邀請&#xff0c;交付《啤酒游戲經營決策沙盤》的項目&#xff0c;下周一JSTO首席學習官Luna想讓我分享下系統思考與投資理財&#xff0c;想到曾經看過的一本書《深度思維》&#xff0c;看到一些結構來預判未來。不僅僅可以應用在企業經營和組織發展上&a…

Uncaught SyntaxError: Unexpected end of input (at manage.html:1:21) 的一個解

關于Uncaught SyntaxError: Unexpected end of input (at manage.html:1:21)的一個解 問題復現 <button onclick"deleteItem(${order.id},hire,"Orders")" >delete</button>報錯 原因 函數參數的雙引號和外面的雙引號混淆了&#xff0c;改成…

【vuex】

vuex 1 理解vuex1.1 vuex是什么1.2 什么時候使用vuex1.3 vuex工作原理圖1.4 搭建vuex環境1.5 求和案例1.5.1 vue方式1.5.2 vuex方式 2 vuex核心概念和API2.1 getters配置項2.2 四個map方法的使用2.2.1 mapState方法2.2.2 mapGetters方法2.2.3 mapActions方法2.2.4 mapMutations…

買賣股票的最佳時機算法(leetcode第121題)

題目描述&#xff1a; 給定一個數組 prices &#xff0c;它的第 i 個元素 prices[i] 表示一支給定股票第 i 天的價格。你只能選擇 某一天 買入這只股票&#xff0c;并選擇在 未來的某一個不同的日子 賣出該股票。設計一個算法來計算你所能獲取的最大利潤。返回你可以從這筆交易…

“HALCON error #2454:HALCON handle was already cleared in operator set_draw“

分析&#xff1a;錯誤提示是窗口句柄已經被刪除&#xff0c;這是因為前邊的一句 HOperatorSet.CloseWindow(hWindowControl1.HalconWindow); 關掉了窗口&#xff0c;屏蔽或刪除即可。

UDS診斷 10服務的肯定響應碼后面跟著一串數據的含義,以及診斷報文格式定義介紹

一、首先看一下10服務的請求報文和肯定響應報文格式 a.診斷儀發送的請求報文格式 b.ECU回復的肯定響應報文格式 c.肯定響應報文中參數定義 二、例程數據解析 a.例程數據 0.000000 1 725 Tx d 8 02 10 03 00 00 00 00 00 0.000806 1 7A5 Rx d 8 06 50 03 00 32 01 F4 CC …

Brushed DC mtr--PIC

PIC use brushed DC mtr fundmental. Low-Cost Bidirectional Brushed DC Motor Control Using the PIC16F684 DC mtr & encoder

《opencv實用探索·八》圖像模糊之均值濾波、高斯濾波的簡單理解

1、前言 什么是噪聲&#xff1f; 該像素與周圍像素的差別非常大&#xff0c;導致從視覺上就能看出該像素無法與周圍像素組成可識別的圖像信息&#xff0c;降低了整個圖像的質量。這種“格格不入”的像素就被稱為圖像的噪聲。如果圖像中的噪聲都是隨機的純黑像素或者純白像素&am…

TailwindCSS 如何設置 placeholder 的樣式

前言 placeholder 在前端多用于 input、textarea 等任何輸入或者文本區域的標簽&#xff0c;它用戶在用戶輸入內容之前顯示一些提示。瀏覽器自帶的 placeholder 樣式可能不符合設計規范&#xff0c;此時就需要通過 css 進行樣式美化。 當項目中使用 TailwindCSS 處理樣式時&a…

JAVA程序如何打jar和war問題解決

背景: 近期研究一個代碼審計工具 需要jar包 jar太多了 可以將jar 打成war包 首先看下程序目錄結構 pom.xml文件內容 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"ht…

Android12 WIFI 無法提供互聯網連接

平臺 RK3588 Android 12 問題描述 ConnectivityService是Android系統中負責處理網絡連接的服務之一。它負責管理設備的網絡連接狀態&#xff0c;包括Wi-Fi、移動數據、藍牙等。 在Android系統中&#xff0c;ConnectivityService提供了一些關鍵功能&#xff0c;包括但不限于…

Spring Boot Async:從入門到精通,原理詳解與最佳實踐

Spring Boot 的異步功能&#xff08;Async&#xff09;允許我們將某些任務異步執行&#xff0c;而不會阻塞主線程。這對于處理耗時的操作非常有用&#xff0c;如發送電子郵件、生成報表、調用外部 API 等。通過異步處理&#xff0c;我們可以釋放主線程&#xff0c;讓它繼續處理…

低多邊形游戲風格3D模型紋理貼圖

在線工具推薦&#xff1a; 3D數字孿生場景編輯器 - GLTF/GLB材質紋理編輯器 - 3D模型在線轉換 - Three.js AI自動紋理開發包 - YOLO 虛幻合成數據生成器 - 三維模型預覽圖生成器 - 3D模型語義搜索引擎 當談到游戲角色的3D模型風格時&#xff0c;有幾種不同的風格&#xf…

區塊鏈實驗室(29) - 關閉或刪除FISCO日志

1. FISCO日志 缺省情況下&#xff0c;FISCO啟動日志模塊&#xff0c;日志記錄的位置在節點目錄中。以FISCO自帶案例為例&#xff0c;4節點的FISCO網絡&#xff0c;24個區塊產生的日志大小&#xff0c;見下圖所示。 2.關閉日志模塊 當節點數量增大&#xff0c;區塊高度增大時&…

總結:服務器批量處理http請求的大致流程

總結&#xff1a;服務器批量處理http請求的大致流程 一客戶端發起請求&#xff1a;可以多個請求同時發送二Web服務器解析請求&#xff08;如&#xff1a;Nginx&#xff09;&#xff1a;可以多個請求同時解析三Servlet容器接收請求&#xff08;如&#xff1a;tomcat&#xff09;…

【EI會議征稿中】第三屆信號處理與通信安全國際學術會議(ICSPCS 2024)

第三屆信號處理與通信安全國際學術會議&#xff08;ICSPCS 2024&#xff09; 2024 3rd International Conference on Signal Processing and Communication Security 信號處理和通信安全是現代信息技術應用的重要領域&#xff0c;近年來這兩個領域的研究相互交叉促進&#xf…

SpringBoot集成Elasticsearch8.x(9)|(RestClient實現Elasticsearch DSL操作)

SpringBoot集成Elasticsearch8.x&#xff08;9&#xff09;|&#xff08;RestClient curl實現Elasticsearch DSL的操作&#xff09; 文章目錄 SpringBoot集成Elasticsearch8.x&#xff08;9&#xff09;|&#xff08;RestClient curl實現Elasticsearch DSL的操作&#xff09;[T…

InsCode:CSDN的創新代碼分享平臺,融合AI技術提升編程體驗

InsCode AI Chat 能夠讓你通過聊天的方式幫你優化代碼。 一&#xff1a;前言 InsCode 是csdn推出的一個代碼分享網站 二、使用 AI 輔助完成代碼 下面我們就從實踐出發&#xff0c;基于 InsCode 的 AI輔助編程&#xff0c;寫Python實現的計算器。 1.基于模板創建項目 這里我…

關于SQL注入問題及解決--小記

1.SQL注入問題 SQL 注入是一種常見的安全漏洞&#xff0c;它發生在應用程序未正確驗證和處理用戶提供的輸入數據時。攻擊者可以通過惡意構造的輸入&#xff0c;將額外的 SQL 代碼注入到應用程序的查詢語句中&#xff0c;從而執行未經授權的數據庫操作。 SQL 注入問題通常出現…

行業地位失守,業績持續失速,科沃斯的故事不好講

特勞特曾在《定位》一書中提到&#xff0c;為了在容量有限的消費者心智中占據品類&#xff0c;品牌最好的差異化就是成為第一&#xff0c;做品類領導者或開創者&#xff0c;銷量遙遙領先&#xff1b;其次分化品類&#xff0c;做到細分品類的唯一&#xff0c;即細分品類的第一。…