【筆試題心得】排序算法總結整理

?排序算法匯總

常用十大排序算法_calm_G的博客-CSDN博客

在這里插入圖片描述?

?以下動圖參考?十大經典排序算法 Python 版實現(附動圖演示) - 知乎

冒泡排序

排序過程如下圖所示:

image.png

  1. 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
  2. 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最后一對。這步做完后,最后的元素會是最大的數。
  3. 針對所有的元素重復以上的步驟,除了最后一個。
  4. 持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
// arr: 需要排序的數組; length: 數組長度 
//注: int cnt = sizeof(a) / sizeof(a[0]);獲取數組長度
void BubbleSort(int arr[], int length) 
{for (int i = 0; i < length; i++){for (int j = 0; j < length -  i - 1; j++){if (arr[j] > arr[j + 1])swap(arr[j],arr[j+1]);}}
}

選擇排序

排序過程如下圖所示:

動圖

  1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
  2. 從剩余未排序元素中繼續尋找最小(大)元素,然后放到已排序序列的末尾
  3. 以此類推,直到所有元素均排序完畢
  4. 時間負復雜度:O(n^2),空間O(1),非穩定排序,原地排序
void selectSort(vector<int>& nums) {int len = nums.size();int minIndex = 0;for (int i = 0; i < len; ++i) {minIndex = i;for (int j = i + 1; j < len; ++j) {if (nums[j] < nums[minIndex]) minIndex = j;}swap(nums[i], nums[minIndex]);}
}

插入排序

排序過程如下圖所示:

動圖

  1. 從第一個元素開始,該元素可以認為已經被排序

  2. 取出下一個元素,在已經排序的元素序列中從后向前掃描

  3. 如果該元素(已排序)大于新元素,將該元素移到下一位置

  4. 重復步驟3,直到找到已排序的元素小于或者等于新元素的位置

  5. 將新元素插入到該位置后

  6. 重復步驟2~5

void insertionSort(vector<int>& a, int n) {//{ 9,1,5,6,2,3 }for (int i = 1; i < n; ++i) {if (a[i] < a[i - 1]) {   //若第i個元素大于i-1元素,直接插入。小于的話,移動有序表后插入int j = i - 1;int x = a[i];     //復制為哨兵,即存儲待排序元素//a[i] = a[i - 1];           //先后移一個元素,可以不要這一句,跟循環里面的功能重復了while (j >= 0 && x < a[j]) {   //查找在有序表的插入位置,還必須要保證j是>=0的 因為a[j]要合法a[j + 1] = a[j];j--;     //元素后移}a[j + 1] = x;     //插入到正確位置}}
}

快速排序

?排序過程如下圖所示:

動圖

動圖看起來有點復雜,下面放一個分解圖https://blog.csdn.net/qq_38082146/article/details/115453732

我們以[ 8,2,5,0,7,4,6,1 ]這組數字為例來進行演示

首先,我們隨機選擇一個基準值(雖然圖中選擇了隨機元素,但是一般上會以第一個元素為基準值):

快速排序1

與其他元素依次比較,大的放右邊,小的放左邊:

快速排序2

然后我們以同樣的方式排左邊的數據:

快速排序3

繼續排 0 和 1 :

快速排序4

由于只剩下一個數,所以就不用排了,現在的數組序列是下圖這個樣子:

快速排序5

?右邊以同樣的操作進行,即可排序完成。

1、選取第一個數為基準

2、將比基準小的數交換到前面,比基準大的數交換到后面

3、對左右區間重復第二步,直到各區間只有一個數

void quickSort(vector<int>&numbers, int low, int high) {//  numbers = {10,8,4,6,9,10,123,6,2,14,3,8,5};if (low >= high) return;int first = low, last = high, key = numbers[low];cout << low << " " << high << " "<<key << endl;for (int i = 0; i < numbers.size(); ++i) {cout << numbers[i] << " ";}cout << endl;while (first < last) {//從后往前找比他小的放前面,從前往后找比他大的放在后面,//以第一個數為基準,必須先從后往前走,再從前往后走while (first < last && numbers[last] >= key)last--;if (first < last) numbers[first++] = numbers[last];while (first < last && numbers[first] <= key)first++;if (first < last) numbers[last--] = numbers[first];}numbers[first] = key;cout << "the index " << first << "  value " << key << endl;quickSort(numbers, low, first - 1);quickSort(numbers, first + 1, high);
}

?希爾排序

?排序過程如下圖所示:

?

希爾排序是插入排序的一種變種。無論是插入排序還是冒泡排序,如果數組的最大值剛好是在第一位,要將它挪到正確的位置就需要 n - 1 次移動。

也就是說,原數組的一個元素如果距離它正確的位置很遠的話,則需要與相鄰元素交換很多次才能到達正確的位置,這樣是相對比較花時間了。

希爾排序就是為了加快速度簡單地改進了插入排序,交換不相鄰的元素以對數組的局部進行排序。

希爾排序的思想是采用插入排序的方法,先讓數組中任意間隔為 h 的元素有序,剛開始 h 的大小可以是 h = n / 2,接著讓 h = n / 4,讓 h 一直縮小,當 h = 1 時,也就是此時數組中任意間隔為1的元素有序,此時的數組就是有序的了。


void shellSortCore(vector<int>& nums, int gap, int i) {int inserted = nums[i];int j;//  插入的時候按組進行插入for (j = i - gap; j >= 0 && inserted < nums[j]; j -= gap) {nums[j + gap] = nums[j];}nums[j + gap] = inserted;
}void shellSort(vector<int>& nums) {int len = nums.size();//進行分組,最開始的時候,gap為數組長度一半for (int gap = len / 2; gap > 0; gap /= 2) {//對各個分組進行插入分組for (int i = gap; i < len; ++i) {//將nums[i]插入到所在分組正確的位置上shellSortCore(nums,gap,i);}}}

歸并排序

?排序過程如下圖所示:

1、把長度為n的輸入序列分成兩個長度為n/2的子序列;

2、對這兩個子序列分別采用歸并排序;

3、 將兩個排序好的子序列合并成一個最終的排序序列。

?

void mergeSortCore(vector<int>& data, vector<int>& dataTemp, int low, int high) {if (low >= high) return;int len = high - low, mid = low + len / 2;int start1 = low, end1 = mid, start2 = mid + 1, end2 = high;mergeSortCore(data, dataTemp, start1, end1);mergeSortCore(data, dataTemp, start2, end2);int index = low;while (start1 <= end1 && start2 <= end2) {dataTemp[index++] = data[start1] < data[start2] ? data[start1++] : data[start2++];}while (start1 <= end1) {dataTemp[index++] = data[start1++];}while (start2 <= end2) {dataTemp[index++] = data[start2++];}for (index = low; index <= high; ++index) {data[index] = dataTemp[index];}
}void mergeSort(vector<int>& data) {int len = data.size();vector<int> dataTemp(len, 0);mergeSortCore(data, dataTemp, 0, len - 1);
}

堆排序

分為創建堆和堆排序兩個部分

創建堆(這里假定是大根堆)時,要保證每個父節點的值比左右子節點的值大

當每次堆排序完成后,最頂端的即是當前堆的最大值,隨后可以將堆的最大值與堆的倒數第一個元素互換,因為此時當前最大值已經完成排序,將其趕出堆內,堆的size減1,剩下的元素進行堆重構。

堆重構的過程就是維持堆每個父節點的值大于左右子節點值的過程

#include <iostream>
#include <algorithm>
#include <vector>using namespace std;//i位置的數,向上調整大根堆
void heapInsert(vector<int>& arr, int i)
{while (arr[i] > arr[(i - 1) / 2])    //子節點比父節點大{swap(arr[i], arr[(i - 1) / 2]);i = (i - 1) / 2;}}//i位置的數發生了變化,又想維持住大根堆的結構
void heapify(vector<int>& arr, int i, int size)
{int l = 2 * i + 1;  //左孩子while (l < size){int best = l + 1 < size && arr[l + 1] > arr[l] ?  l + 1 : l;best = arr[best] > arr[i] ? best : i;if (best == i)break;swap(arr[i], arr[best]);i = best;l = 2 * i + 1;}}//從頂到底建立大根堆
//依次彈出堆內的最大值,并重新排好序
void heapSort(vector<int>& arr)
{int size = arr.size();for (int i = 0; i < size; i++)    //建立大根堆{heapInsert(arr, i);}while (size > 1){swap(arr[0], arr[size - 1]);  size--;cout<< arr[size] <<endl;heapify(arr, 0, size);}
}int main()
{vector<int> arr = { 3,2,1,5,6,4 };heapSort(arr);
}

計數排序

計數排序用于元素大小范圍有限的數值排序。

  • 如果 k(待排數組的最大值) 過大則會引起較大的空間復雜度,一般是用來排序 0 到 100 之間的數字的最好的算法,但是它不適合按字母順序排序人名。

統計小于等于該元素值的元素的個數i,于是該元素就放在目標數組的索引i位(i≥0)

計數排序

?

  1. 找出待排序的數組中最大和最小的元素;
  2. 統計數組中每個值為 i 的元素出現的次數,存入數組 C 的第 i 項;
  3. 對所有的計數累加(從 C 中的第一個元素開始,每一項和前一項相加);
  4. 向填充目標數組:將每個元素 i 放在新數組的第 C[i] 項,每放一個元素就將 C[i] 減去 1
#include <iostream>
#include <vector>
#include <algorithm>using namespace std;// 計數排序
void CountSort(vector<int>& vecRaw, vector<int>& vecObj)
{// 確保待排序容器非空if (vecRaw.size() == 0)return;// 使用 vecRaw 的最大值 + 1 作為計數容器 countVec 的大小int vecCountLength = (*max_element(begin(vecRaw), end(vecRaw))) + 1;vector<int> vecCount(vecCountLength, 0);// 統計每個鍵值出現的次數for (int i = 0; i < vecRaw.size(); i++)vecCount[vecRaw[i]]++;// 后面的鍵值出現的位置為前面所有鍵值出現的次數之和for (int i = 1; i < vecCountLength; i++)vecCount[i] += vecCount[i - 1];// 將鍵值放到目標位置for (int i = vecRaw.size(); i > 0; i--)	// 此處逆序是為了保持相同鍵值的穩定性vecObj[--vecCount[vecRaw[i - 1]]] = vecRaw[i - 1];
}int main()
{vector<int> vecRaw = { 0,5,7,9,6,3,4,5,2,8,6,9,2,1 };vector<int> vecObj(vecRaw.size(), 0);CountSort(vecRaw, vecObj);for (int i = 0; i < vecObj.size(); ++i)cout << vecObj[i] << "  ";cout << endl;return 0;
}

桶排序

?排序過程如下圖所示:

桶排序

  1. 設置一個定量的數組當作空桶子。
  2. 尋訪序列,并且把項目一個一個放到對應的桶子去。
  3. 對每個不是空的桶子進行排序。
  4. 從不是空的桶子里把項目再放回原來的序列中。
#include<stdio.h>
int main() {int book[1001],i,j,t;//初始化桶數組for(i=0;i<=1000;i++) {book[i] = 0;}//輸入一個數n,表示接下來有n個數scanf("%d",&n);for(i = 1;i<=n;i++) {//把每一個數讀到變量中去scanf("%d",&t);//計數  book[t]++;}//從大到小輸出for(i = 1000;i>=0;i--) {for(j=1;j<=book[i];j++) {printf("%d",i);}}getchar();getchar();//getchar()用來暫停程序,以便查看程序輸出的內容//也可以用system("pause");來代替return 0;
}

基數排序

基數排序

  1. 取得數組中的最大數,并取得位數;
  2. arr為原始數組,從最低位開始取每個位組成radix數組;
  3. 對radix進行計數排序(利用計數排序適用于小范圍數的特點)
int maxbit(int data[], int n) //輔助函數,求數據的最大位數
{int maxData = data[0];		///< 最大數/// 先求出最大數,再求其位數,這樣有原先依次每個數判斷其位數,稍微優化點。for (int i = 1; i < n; ++i){if (maxData < data[i])maxData = data[i];}int d = 1;int p = 10;while (maxData >= p){//p *= 10; // Maybe overflowmaxData /= 10;++d;}return d;
}
void radixsort(int data[], int n) //基數排序
{int d = maxbit(data, n);int *tmp = new int[n];int *count = new int[10]; //計數器int i, j, k;int radix = 1;for(i = 1; i <= d; i++) //進行d次排序{for(j = 0; j < 10; j++)count[j] = 0; //每次分配前清空計數器for(j = 0; j < n; j++){k = (data[j] / radix) % 10; //統計每個桶中的記錄數count[k]++;}for(j = 1; j < 10; j++)count[j] = count[j - 1] + count[j]; //將tmp中的位置依次分配給每個桶for(j = n - 1; j >= 0; j--) //將所有桶中記錄依次收集到tmp中{k = (data[j] / radix) % 10;tmp[count[k] - 1] = data[j];count[k]--;}for(j = 0; j < n; j++) //將臨時數組的內容復制到data中data[j] = tmp[j];radix = radix * 10;}delete []tmp;delete []count;
}

?

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

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

相關文章

【LeetCode-簡單】劍指 Offer 29. 順時針打印矩陣(詳解)

題目 輸入一個矩陣&#xff0c;按照從外向里以順時針的順序依次打印出每一個數字。 示例 1&#xff1a; 輸入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 輸出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 輸入&#xff1a;matrix [[1,2,3,4],[5,6,7,8],[9,10,1…

互聯網發展歷程:速度與效率,交換機的登場

互聯網的演進就像一場追求速度與效率的競賽&#xff0c;每一次的技術升級都為我們帶來更快、更高效的網絡體驗。然而&#xff0c;在網絡的初期階段&#xff0c;人們面臨著數據傳輸速度不夠快的問題。一項關鍵的技術應運而生&#xff0c;那就是“交換機”。 速度不足的困境&…

CloudEvents—云原生事件規范

我們的系統中或多或少都會用到如下兩類業務技術&#xff1a; 異步任務&#xff0c;用于降低接口時延或削峰&#xff0c;提升用戶體驗&#xff0c;降低系統并發壓力&#xff1b;通知類RPC&#xff0c;用于微服務間狀態變更&#xff0c;用戶行為的聯動等場景&#xff1b; 以上兩種…

Go和Java實現解釋器模式

Go和Java實現解釋器模式 下面通過一個四則運算來說明解釋器模式的使用。 1、解釋器模式 解釋器模式提供了評估語言的語法或表達式的方式&#xff0c;它屬于行為型模式。這種模式實現了一個表達式接口&#xff0c;該接口 解釋一個特定的上下文。這種模式被用在 SQL 解析、符…

規劃性和可擴展性,助力企業全面預算管理的推進

對于當今社會經濟市場的不穩定狀況和不斷變化的消費者行為&#xff0c;企業業務也從未像今天這樣不可預測過。面對變化和變革&#xff0c;企業需要具備規劃性的預測能力&#xff0c;才能使得自身在競爭中保持領先地位。那些具備前瞻性的企業都嘗試在現階段通過更好的規劃不斷提…

基于Mysqlrouter+MHA+keepalived實現高可用半同步 MySQL Cluster項目

目錄 項目名稱&#xff1a; 基于Mysqlrouter MHA keepalived實現半同步主從復制MySQL Cluster MySQL Cluster&#xff1a; 項目架構圖&#xff1a; 項目環境&#xff1a; 項目環境安裝包&#xff1a; 項目描述&#xff1a; 項目IP地址規劃&#xff1a; 項目步驟: 一…

windows11下配置vscode中c/c++環境

本文默認已經下載且安裝好vscode&#xff0c;主要是解決環境變量配置以及編譯task、launch文件的問題。 自己嘗試過許多博客&#xff0c;最后還是通過這種方法配置成功了。 Linux(ubuntu 20.04)配置vscode可以直接跳轉到配置task、launch文件&#xff0c;不需要下載mingw與配…

寬度有限搜索BFS搜索數及B3625 迷宮尋路 P1451 求細胞數量 B3626 跳躍機器人

寬度有限搜索BFS搜索 B3625 迷宮尋路 題面 題目描述 機器貓被困在一個矩形迷宮里。 迷宮可以視為一個 nm 矩陣&#xff0c;每個位置要么是空地&#xff0c;要么是墻。機器貓只能從一個空地走到其上、下、左、右的空地。 機器貓初始時位于 (1,1) 的位置&#xff0c;問能否…

localhost:8080 is already in use

報錯原因&#xff1a;本機的8080端口號已經被占用。因為機器的空閑端口號是隨機分配的&#xff0c;而idea默認啟動的端口號是8080,所以是存在這種情況。 對于這個問題&#xff0c;我們只需要重啟idea或者修改項目的啟動端口號即可。 更推薦第二種。對于修改項目啟動端口號&…

Python 程序設計入門(020)—— 循環結構程序設計(1):for 循環

Python 程序設計入門&#xff08;020&#xff09;—— 循環結構程序設計&#xff08;1&#xff09;&#xff1a;for 循環 目錄 Python 程序設計入門&#xff08;020&#xff09;—— 循環結構程序設計&#xff08;1&#xff09;&#xff1a;for 循環一、for 循環的語法二、for …

ZDH-wemock模塊

本次介紹基于版本v5.1.1 目錄 項目源碼 預覽地址 安裝包下載地址 wemock模塊 wemock模塊前端 配置首頁 配置mock wemock服務 下載地址 打包 運行 效果展示 項目源碼 zdh_web: https://github.com/zhaoyachao/zdh_web zdh_mock: https://github.com/zhaoyachao/z…

TCGA數據下載推薦:R語言easyTCGA包

#使用easyTCGA獲取數據 #清空 rm(listls()) gc() # 安裝bioconductor上面的R包 options(BioC_mirror"https://mirrors.tuna.tsinghua.edu.cn/bioconductor") if(!require("BiocManager")) install.packages("BiocManager") if(!require("TC…

怎樣讓音頻速度變慢?請跟隨以下方法進行操作

怎樣讓音頻速度變慢&#xff1f;在會議錄音過程中&#xff0c;經常會遇到主講人語速過快&#xff0c;導致我們無法清晰聽到對方說的內容。如果我們能夠減慢音頻速度&#xff0c;就能更好地記錄對方的講話內容。此外&#xff0c;在聽到快速播放的外語或方言時&#xff0c;我們也…

LA@2@1@線性方程組和簡單矩陣方程有解判定定理

文章目錄 矩陣方程有解判定定理線性方程組有解判定特化:齊次線性方程組有解判定推廣:矩陣方程 A X B AXB AXB有解判定證明推論 矩陣方程有解判定定理 線性方程組有解判定 線性方程組 A x b A\bold{x}\bold{b} Axb有解的充分必要條件是它的系數矩陣A和增廣矩陣 ( A , b ) (A,…

機器人的運動范圍

聲明 該系列文章僅僅展示個人的解題思路和分析過程&#xff0c;并非一定是優質題解&#xff0c;重要的是通過分析和解決問題能讓我們逐漸熟練和成長&#xff0c;從新手到大佬離不開一個磨練的過程&#xff0c;加油&#xff01; 原題鏈接 機器人的運動范圍https://leetcode.c…

高等數學教材重難點題型總結(二)導數與微分

本章重點題目較少&#xff0c;除了*標題頁沒什么特別難的&#xff0c;本帖出于總結性的角度考慮并未囊概全部的*標&#xff0c;最后會出一期*標題的全部內容整理&#xff0c;在攻克重難點的基礎上更上一層樓。 1.根據定義求某點處的導數值 2.通過定義證明導數 3.左右導數的相關…

【數據庫】P4 過濾數據 WHERE

過濾數據 WHERE 簡介WHERE 子句操作符檢測單個值案例范圍值檢查 BETWEEN AND空值檢查 NULL 簡介 數據庫表一般包含大量的數據&#xff0c;很少需要檢索表中的所有行。我們只檢索所需數據需要指定搜索條件(search criteria)&#xff0c;搜索條件也稱為過濾條件(filter conditio…

完全備份、增量備份、差異備份、binlog日志

Top NSD DBA DAY06 案例1&#xff1a;完全備份與恢復案例2&#xff1a;增量備份與恢復案例3&#xff1a;差異備份與恢復案例4&#xff1a;binlog日志 1 案例1&#xff1a;完全備份與恢復 1.1 問題 練習物理備份與恢復練習mysqldump備份與恢復 1.2 方案 在數據庫服務器192…

問AI一個嚴肅的問題

chatgpt的問世再一次掀起了AI的浪潮&#xff0c;其實我一直在想&#xff0c;AI和人類的關系未來會怎樣發展&#xff0c;我們未來會怎樣和AI相處&#xff0c;AI真的會完全取代人類嗎&#xff0c;帶著這個問題&#xff0c;我問了下chatgpt&#xff0c;看一看它是怎么看待這個問題…

Modbus工業RFID設備在自動化生產線中的應用

傳統半自動化生產線在運作的過程&#xff0c;因為技工的熟練程度&#xff0c;專業素養的不同&#xff0c;在制造過程中過多的人為干預&#xff0c;工廠將很難對每條生產線的產能進行標準化管理和優化。如果半自動化生產線系統是通過前道工序的作業結果和檢測結果來決定產品在下…