排序算法總結

1 排序算法

image-20231107133459995

1.1 快速排序

1.1.1 算法思想
  • 先取一個隨機數,然后和數組的最后一個數交換

  • 進行partition過程,也就是比數組最后一個數小的放在數組左邊,大的放在右邊,相等的在數組中間,最后把數組的最后一個數也要放到中間位置,然后返回相等的那一批數的最左索引和最右索引。

  • 遞歸前兩個過程

1.1.2 時間復雜度
O (N * logN)
1.1.3 代碼實現
public class QuickSort {private static void quickSort(int[] arr) {if (arr == null || arr.length < 2) {return;}process(arr, 0, arr.length - 1);}private static void process(int[] arr, int left, int right) {if (left >= right) {return;}swap(arr, left + (int)(Math.random() * (right - left + 1)), right);int[] partition = partition(arr, left, right);process(arr, left, partition[0] - 1);process(arr, partition[1] + 1, right);}private static int[] partition(int[] arr, int left, int right) {int index = left;int small = left - 1;int big = right;while (index < big) {if (arr[index] == arr[right]) {index++;} else if (arr[index] < arr[right]) {swap(arr, index++, ++small);}else {swap(arr, index, --big);}}swap(arr, right, big);return new int[] {++small, big};}private static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void main(String[] args) {int[] arr = {1,2,8,9,5};quickSort(arr);for (int i : arr) {System.out.print(i + " ");}}
}

1.2 堆排序

1.2.1 算法思想
  • 給了一個數組,把數組看成完全二叉樹結構,現在開始變成堆
  • 從完全二叉樹的最后一個值開始進行heapify過程,也就是把每一個值都要和子節點比較大小,把這個節點為頂的樹變成堆結構
  • 變成大根堆堆結構之后,將堆頂元素和數組最后一個元素互換,堆的長度減一的同時要進行heapify操作,把剩下元素的要恢復堆結構
  • 重復第三步操作,每次都取一個最大值出來放到原堆的最后,數組有序
1.2.2 時間復雜度
O (N * logN)
1.2.3 代碼實現
public class HeapSort {public static void heapSort(int[] arr) {if (arr == null || arr.length < 2) {return;}int heapSize = arr.length;for (int i = arr.length - 1; i >= 0; i--) {heapify(arr, i, heapSize);}swap(arr, 0, --heapSize);while (heapSize > 0) {heapify(arr, 0, heapSize);swap(arr, 0, --heapSize);}}private static void heapify(int[] arr, int index, int heapSize) {int left = index * 2 + 1;while (left < heapSize) {int largest = left + 1 < heapSize ? (arr[left] < arr[left + 1] ? left + 1 : left) : left;largest = arr[index] < arr[largest] ? largest : index;if (largest == index) {return;}swap(arr, largest, index);index = largest;left = index * 2 + 1;}}private static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void main(String[] args) {int[] arr = {1,9,7,3,6,4,8,2,5};heapSort(arr);for (int i : arr) {System.out.print(i + " ");}}
}

1.3 桶排序

不基于比較的排序算法,,分為兩類,但是都有約束條件

  • 計數排序:要排序的數都要是0或正整數
  • 基數排序:必須是十進制的數,而且是0或正整數

給的數越多,代價越大。一旦要升級的話,要付出的代價更加顯而易見。

要排序的最大的數越大,計數排序需要的空間就越多,要排序比如{9,1,96656412},那么此時就需要輔助數組的長度就要是96656413了,很明顯性價比不高,就需要用基數排序,基數排序只用兩個輔助數組,而且一個計數器數組長度長度固定為10,一個輔助數組長度和要排序的數組長度相同,浪費的空間小。但是如果要排序的數中最大數越小,那么此時就可以用計數排序。

1.3.1 計數排序
算法思想
  • 給定數組,范圍[0,intMax]
  • 定義一個輔助數組,輔助數組的長度就是給定數組的長度
  • 遍歷數組,給定數組的值與輔助數組的索引對應,
  • 每當有一個給定數組的值等于輔助數組的索引,那么這個索引上的值加一
  • 遍歷完成之后,再遍歷輔助數組,
  • 每當輔助數組的值不為0,就把輔助數組的索引覆蓋在給定數組中
  • 每覆蓋一次,輔助數組的值減一,直到減為0才能遍歷下一次
時間復雜度
O (N)
代碼實現
public class CountSort {public static void countSort(int[] arr) {if (arr == null || arr.length < 2) {return;}int max = arr[0];for (int i = 1; i < arr.length; i++) {max = Math.max(max, arr[i]);}int[] bucket = new int[max + 1];for (int a : arr) {bucket[a]++;}int index = 0;for (int i = 0; i < bucket.length; i++) {while (bucket[i]-- > 0) {arr[index++] = i;}}}// 寫比較器驗證public static void comparator(int[] arr) {if (arr == null || arr.length < 2) {return;}Arrays.sort(arr);}public static int[] generateRandomArr(int arrLen) {int[] ans = new int[arrLen];for (int i = 0; i < arrLen; i++) {int num = (int) (Math.random() * 1000 + 1);ans[i] = num;}return ans;}public static void main(String[] args) {int arrLength = 1000;int testTimes = 1000000;for (int i = 0; i < testTimes; i++) {int arrLen = (int) (Math.random() * arrLength + 1);int[] arr1 = generateRandomArr(arrLen);int[] arr2 = new int[arr1.length];for (int j = 0; j < arr1.length; j++) {arr2[j] = arr1[j];}countSort(arr1);comparator(arr2);for (int j = 0; j < arr1.length; j++) {if (arr1[j] != arr2[j]) {System.out.println("Oops!");}}}System.out.println("Finish!");}
}
1.3.2 基數排序
算法思想

算法步驟:

  • 給定數組的最大數有幾位就遍歷幾遍(最外層的遍歷),先從個位數字開始遍歷

    • 目的是從個位數字開始,先把數組中的每個數的個位數字排序,之后再排十位,以此類推。

    • 第一次遍歷

      • 遍歷每個數組,遍歷的過程中,只看現在遍歷的數的個位數字,也就是不管數組有多大,每次看的數字只有[0,9]

      • 定義一個計數器數組,每個數字出現一個,計數器數組的與這個數字相等的索引上的值加一

    • 第二次遍歷

      • 遍歷計數器數組,數組中的每個數等于前面自己的值和前一個數的值相加
      • 目的是找出比這個數小的數字有多少個
    • 第三次遍歷

      • 定義一個輔助數組,長度和給定數組的長度相同
      • 從給定數組的末尾開始往前遍歷
      • 看計數器數字中,和給定數組的末尾數字的個為數字相同的數字有幾個,也就是找比這個數字小的或者等于有多少個
      • 這個數字減一就是輔助數組的索引,索引上放的數字就是給定數組的現在遍歷到的數。
      • 這個理解就相當于隊列,小的肯定在前面,相同的先進的先出(第一次遍歷中,先遍歷的在前面,后遍歷的在后面,那么最后一個遍歷的肯定在最后面)
    • 第四次遍歷

      • 交換輔助數組和給定數組的每一個值
      • 接下來就要結束整個大的個位數的遍歷,開始遍歷十位上的數
時間復雜度
O(N)
代碼實現
public class RadixSort {public static void radixSort(int[] arr) {if (arr == null || arr.length < 2) {return;}radixSort(arr, 0, arr.length - 1, maxBits(arr));}// 求數組中最大的數有幾位:1000  --->  4位private static int maxBits(int[] arr) {int max = arr[0];for (int i = 1; i < arr.length; i++) {max = Math.max(max, arr[i]);}int ans = 0;while (max != 0) {max /= 10;ans++;}return ans;}// 基數排序的實現public static void radixSort(int[] arr, int left, int right, int digit) {final int radix = 10;int[] help = new int[right - left + 1];for (int d = 1; d <= digit; d++) {int[] count = new int[radix];int i = 0;int j = 0;for (i = left; i <= right; i++) {j= getDigit(arr[i], d);count[j]++;}for (i = 1; i < radix; i++) {count[i] += count[i - 1];}for (i = right; i >= left; i--) {j = getDigit(arr[i], d);help[count[j] - 1] = arr[i];count[j]--;}for (i = left, j = 0; i <= right; i++, j++) {arr[i] = help[j];}}}// num這個數的digit位的數字:(123,1) ---> 3private static int getDigit(int num, int digit) {return ((num / (int) Math.pow(10, digit - 1)) % 10);}// 對數器測試public static void comparator(int[] arr) {if (arr == null || arr.length < 2) {return;}Arrays.sort(arr);}public static int generateRandomNum(int num) {return (int) (Math.random() * num + 1);}public static int[] generateRandomArr(int arrLen, int num) {int length = (int) (Math.random() * arrLen + 1);int[] ans = new int[length];for (int i = 0; i < length; i++) {ans[i] = generateRandomNum(num);}return ans;}public static void main(String[] args) {int num = 1000;int arrLen = 100;int testTimes = 1000000;for (int i = 0; i < testTimes; i++) {int[] arr1 = generateRandomArr(arrLen, num);int[] arr2 = new int[arr1.length];for (int j = 0; j < arr1.length; j++) {arr2[j] = arr1[j];}radixSort(arr1);comparator(arr2);for (int j = 0; j < arr1.length; j++) {if (arr2[j] != arr1[j]) {System.out.println("Oops!");}}}System.out.println("Finish!");}
}

排序算法總結

1 總結
  1. 不基于比較的排序(桶排序),對樣本數據有嚴格的要求,不易改寫
  2. 基于比較的排序,只要規定好兩個樣本怎么比大小就可以直接復用
  3. 基于比較的排序,時間復雜度的極限是O(N*logN)
  4. 時間復雜度O(N*logN),額外空間復雜度低于O(N)且穩定的基于比較的排序是不存在
  5. 為了絕對的速度選擇快排,為了省空間選堆排,為了穩定性選歸并
2 常見的坑
  1. 歸并排序的額外空間復雜度可以變成O(1),“歸并排序內部緩存法”,但是將變得不穩定。(還不如用堆排)
  2. “原地歸并排序”不好,會讓時間復雜度變成O(N*2)。(不如用插入排序)
  3. 快速排序穩定性改進,論文:“01 stable sort”,但是會對樣本數據要求更多。(不如用桶排序)
    • 題目:在整型數組中,請把奇數放在數組左邊,偶數放在數組右邊,要求所有基數之間原始的相對次序不變,所有偶數之間原始相對次序不變,要求時間復雜度O(N),額外空間復雜度O(1)
3 排序優化
  1. 穩定性的考慮:數據是值傳遞直接快排,引用傳遞用歸并排序
  2. 充分利用O(N*logN)O(N^2)排序各自的優勢:小樣本量直接插入排序

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

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

相關文章

【LeetCode刷題-回溯】-- 46.全排列

46.全排列 方法&#xff1a;回溯法 一種通過探索所有可能的候選解來找出所有的解的算法&#xff0c;如果候選解被確認不是一個解&#xff0c;回溯法會通過在上一步進行一些變化拋棄該解&#xff0c;即回溯并且再次嘗試 使用一個標記數組表示已經填過的數 class Solution {pu…

【前端】yarn介紹和使用

yarn介紹和使用 一、什么是yarn&#xff1f;二、安裝yarn三、yarn用法四、yarn更多用法 一、什么是yarn&#xff1f; yarn是快速、可靠、安全的依賴管理。 yarn官網&#xff1a;https://yarn.nodejs.cn/ Yarn 是代碼的包管理器。 它允許你與世界各地的其他開發者使用和共享&am…

如何設置實現本地JumpServer遠程訪問管理界面

文章目錄 前言1. 安裝Jump server2. 本地訪問jump server3. 安裝 cpolar內網穿透軟件4. 配置Jump server公網訪問地址5. 公網遠程訪問Jump server6. 固定Jump server公網地址 前言 JumpServer 是廣受歡迎的開源堡壘機&#xff0c;是符合 4A 規范的專業運維安全審計系統。JumpS…

C語言for循環結構經典練習

文章目錄 一、for循環基本知識二、經典例題及解析1.水仙花數2.求規定范圍內的完數3.求規定范圍內質數4.計算階乘之和5.計算55555555555555(類型)6.計算112123123412345(類型)7.判斷用戶輸入正整數的位數8.判斷某正整數是否為回文數9.九九乘法表10.統計用戶輸入的字符中&#xf…

PTA 公路村村通

現有村落間道路的統計數據表中&#xff0c;列出了有可能建設成標準公路的若干條道路的成本&#xff0c;求使每個村落都有公路連通所需要的最低成本。 輸入格式: 輸入數據包括城鎮數目正整數N&#xff08;≤1000&#xff09;和候選道路數目M&#xff08;≤3N&#xff09;&…

JVM 之 javac、java、javap 命令詳解

目錄 一. 前言 二. javac 命令 三. java 命令 四. javap 命令 一. 前言 在日常工作中&#xff0c;我們新建 Java工程&#xff0c;寫好代碼后&#xff0c;編譯和運行幾乎都是通過 IDE&#xff08;如idea、eclipse&#xff09;工具完成。但作為 Java開發者還是要了解下 Java虛…

Modbus RTU協議及modbus庫函數使用

一、與Modbus TCP的區別 在一般工業場景使用modbus RTU的場景還是更多一些&#xff0c;modbus RTU基于串行協議進行收發數據&#xff0c;包括RS232/485等工業總線協議。 與modbus TCP不同的是RTU沒有報文頭MBAP字段&#xff0c;但是在尾部增加了兩個CRC檢驗字節&#xff08;CRC…

Android之在RecyclerView列表中實現單選

一、實現效果 單選、可取消選中、列表數據可更新&#xff08;選擇狀態清空&#xff0c;可重新選擇&#xff09; RecyclerView列表單選 二、實現步驟 僅展示部分核心代碼&#xff0c;請主要參考適配器的定義 1、Item布局 selected_tip_list_item.xml文件 包含一個TextView和…

Spring Boot集成MyBatis實現多數據源訪問的“秘密”

文章目錄 為什么需要多數據源&#xff1f;Spring Boot集成MyBatis的基礎配置使用多數據源小結 &#x1f389;Spring Boot集成MyBatis實現多數據源訪問的“秘密” ☆* o(≧▽≦)o *☆嗨~我是IT陳寒&#x1f379;?博客主頁&#xff1a;IT陳寒的博客&#x1f388;該系列文章專欄&…

力扣:178. 分數排名(Python3)

題目&#xff1a; 表: Scores ---------------------- | Column Name | Type | ---------------------- | id | int | | score | decimal | ---------------------- 在 SQL 中&#xff0c;id 是該表的主鍵。 該表的每一行都包含了一場比賽的分數。Score …

TCP /UDP協議的 socket 調用的過程

在傳輸層有兩個主流的協議 TCP 和 UDP&#xff0c;socket 程序設計也是主要操作這兩個協議。這兩個協議的區別是什么呢&#xff1f;通常的答案是下面這樣的。 TCP 是面向連接的&#xff0c;UDP 是面向無連接的。TCP 提供可靠交付&#xff0c;無差錯、不丟失、不重復、并且按序…

Selenium介紹及基本使用方法

Selenium是一個開源、免費、簡單、靈活&#xff0c;對Web瀏覽器支持良好的自動化測試工具&#xff0c;在UI自動化、爬蟲等場景下是十分實用的&#xff0c;能夠熟練掌握并使用Selenium工具可以大大的提高效率。 Selenium簡介 Selenium支持多平臺、多瀏覽器、多語言去實現自動化…

深入理解強化學習——馬爾可夫決策過程:動作價值函數

分類目錄&#xff1a;《深入理解強化學習》總目錄 不同于馬爾可夫獎勵過程&#xff0c;在馬爾可夫決策過程中&#xff0c;由于動作的存在&#xff0c;我們額外定義一個動作價值函數&#xff08;Action-value Function&#xff09;。我們用 Q π ( s , a ) Q^\pi(s, a) Qπ(s,a)…

線程提交線程到線程池,有幾種方式,哪一種方式是工作中不能使用的,無法捕捉異常,線程池的拒絕策略,線程池的提交方式

線程池的工作原理 JDK中提交線程到線程池&#xff0c;有幾種方式&#xff0c;哪一種方式是工作中不能使用的&#xff0c;無法捕捉異常 兩種提交任務的方法 ExecutorService 提供了兩種提交任務的方法&#xff1a; execute()&#xff1a;提交不需要返回值的任務 submit()&a…

【C語言】多組輸入

C系列文章目錄 目錄 C系列文章目錄 一、什么是多組輸入&#xff1f; 二、如何使用多組輸入 2.1&#xff0c;試題舉例講解 2.2&#xff0c;錯誤解法 2.3&#xff0c;我們實現多組輸入的思路 2.4&#xff0c;第一種正確的解法 2.5&#xff0c;第二種正確的解法 2.6&…

Python入門教程 | Python3 字典(dict)

Python3 字典 字典是另一種可變容器模型&#xff0c;且可存儲任意類型對象。 Python3中的字典是一種無序、可變、可迭代的數據結構&#xff0c;它由鍵&#xff08;key&#xff09;和對應的值&#xff08;value&#xff09;組成。字典在Python中被視為可變對象&#xff0c;這意…

ES ElasticSearch安裝、可視化工具kibana安裝

1、安裝ES docker run -d --name es9200 -e "discovery.typesingle-node" -p 9200:9200 elasticsearch:7.12.1訪問測試&#xff1a; http://域名:9200/ 2、安裝kibana對es進行可視化操作 執行命令 docker run -d --name kibana5601 -p 5601:5601 kibana:7.1.12.修…

如何實現在公網下使用navicat圖形化工具遠程連接本地內網的MariaDB數據庫

公網遠程連接MariaDB數據庫【cpolar內網穿透】 文章目錄 公網遠程連接MariaDB數據庫【cpolar內網穿透】1. 配置MariaDB數據庫1.1 安裝MariaDB數據庫1.2 測試局域網內遠程連接 2. 內網穿透2.1 創建隧道映射2.2 測試隨機地址公網遠程訪問3. 配置固定TCP端口地址3.1 保留一個固定的…

Redis深入理解-Socket連接建立流程以及文件事件處理機制

Redis Server 運行原理圖 Redis 服務器中 Socket 網絡建立以及文件事件模型 一個 redis 單機&#xff0c;可以抗幾百上千的并發&#xff0c;這里的并發指的就是同時可以有幾百個 client 對這個 redis server 發起請求&#xff0c;都需要去建立網絡連接&#xff0c;同時間可能會…