排序算法(Java版)

目錄

  • 1、直接插入排序
  • 2、希爾排序
  • 3、直接選擇排序
  • 4、堆排序
  • 5、冒泡排序
  • 6、快速排序
    • 6.1 遞歸實現
    • 6.2 非遞歸實現
  • 7、歸并排序
    • 7.1 遞歸實現
    • 7.2 非遞歸實現
  • 8、性能分析

今天我們學習一種算法:排序算法(本文的排序默認是從小到大順序)!!!

1、直接插入排序

算法原理: 每次將無序序列中的第一個插入到有序序列當中,使有序序列仍為有序,第一趟排序默認第一個元素是有序的,類比于生活中的摸牌,每次將新的排插入已有的牌當中。直接插入排序的算法原理很簡單,我們只需要找到每個元素該插入到哪個位置即可。
在這里插入圖片描述

代碼實現:

    public void InsertSort(int[] array) {for (int i = 1; i < array.length; i++) {int tmp = array[i];int j = i - 1;for (; j >= 0; j--) {if (array[j] > tmp) {array[j + 1] = array[j];} else {array[j + 1] = tmp;break;}}array[j + 1] = tmp;}}

代碼圖解:
在這里插入圖片描述

2、希爾排序

算法原理: 希爾排序又稱縮小增量排序,原理是先選定一個數作為分組的組數,將數組進行分組,接著分別對每個組進行排序,每組排序好之后,縮小分組的組數,重復上述步驟,直到組數為1。對每個組進行排序,我們使用插入排序的方法進行排序。
在這里插入圖片描述

代碼實現:

    public void ShellSort(int[] array) {int gap = array.length;//分成gap組,對每一組進行插入排序while (gap > 1) {gap /= 2;shell(array, gap);}}//對每組進行插入排序public void shell(int[] array, int gap) {for (int i = gap; i < array.length; i++) {int tmp = array[i];int j = i - gap;for (; j >= 0; j -= gap) {if (array[j] > tmp) {array[j + gap] = array[j];} else {array[j + gap] = tmp;break;}}array[j + gap] = tmp;}}

3、直接選擇排序

算法原理: 每次待排序序列中選擇最小的元素和待排序的第一個元素交換
代碼實現:

    public void SelectSort(int[] array) {for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i + 1; j < array.length; j++) {if (array[j] < array[minIndex]) {minIndex = j;}}//交換minIndex下標和i下標的值int tmp = array[minIndex];array[minIndex] = array[i];array[i] = tmp;}}

4、堆排序

算法原理: 堆排序是借用堆這種數據結構來實現的一種排序算法,如果升排序,建立大根堆;如果排降序,建立小根堆 。建堆之后:
1、交換0下標元素和最后一個元素的值
2、然后重新將數組進行向下調整為大根堆
重復這兩個步驟,直到全部有序
在這里插入圖片描述

代碼實現:

    public void HeapSort(int[] array) {//先創建大堆createBigHeap(array);int end = array.length - 1;while (end >= 0) {//交換int tmp = array[0];array[0] = array[end];array[end] = tmp;ShiftDown(array, 0, end);end--;}}public void createBigHeap(int[] array) {for (int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--) {ShiftDown(array, parent, array.length);}}public void ShiftDown(int[] array, int parent, int end) {int child = parent * 2 + 1;while (child < end) {if (child + 1 < end && array[child] < array[child + 1]) {child++;}if (array[child] > array[parent]) {//交換int tmp = array[parent];array[parent] = array[child];array[child] = tmp;parent = child;child = parent * 2 + 1;} else {break;}}}    

5、冒泡排序

算法原理: 遍歷數組,每次比較相鄰兩個元素的大小,如果大的數字在前則交換兩個元素的位置,這樣就完成了一趟冒泡排序,此時最大的數到了最后,然后對前n-1個數進行相同的操作,直到有序。
代碼實現:

    public void BubbleSort(int[] array) {for (int i = 0; i < array.length-1; i++) {for (int j = i; j < array.length - i - 1; j++) {if (array[j] > array[j + 1]) {//交換int tmp = array[j];array[j] = array[j+1];array[j+1] = tmp;}}}}

問題:如果遍歷一遍數組已經有序了,就不用再繼續比較下去了,因此對上面代碼進行優化
優化后:

    public void BubbleSort(int[] array) {boolean flg = false;for (int i = 0; i < array.length - 1; i++) {for (int j = i; j < array.length - i - 1; j++) {if (array[j] > array[j + 1]) {//交換int tmp = array[j];array[j] = array[j+1];array[j+1] = tmp;flg = true;}}if (!flg) {break;}}}

6、快速排序

算法原理: 快速排序的基本思想就是:選定一個基準,通過一趟快速排序之后,能把數據分割為兩部分,左邊部分比基準的值小,右邊的部分比基準的值大,接著再按照這個方法分別對基準左邊部分和右邊部分進行遞歸,重復這個步驟直到整個序列都有序。快速排序的最重要部分就是如何將序列分割成兩部分,常見的分割方法有hoare法和挖坑法
Hoare法分割: 先選定一個基準(默認是第一個元素),定義left、right下標,left從序列最右邊開始找比基準小的值(升序排序),找到之后停下來,接著讓left從最左邊開始找比基準大的值,找到之后停下來,將找到的這兩個值交換,當left和right相遇時(left=right),交換基準的值和left/right下標的值,這樣left/right下標左邊的元素全都比left/right下標的值小,右邊的元素都比它大,這樣就分割好了。
圖解:
在這里插入圖片描述

挖坑法:
和Hoare法的區別是:挖坑法是邊找邊交換,如圖
在這里插入圖片描述

6.1 遞歸實現

代碼實現:

    public void QuickSort(int[] arr) {quick(arr, 0, arr.length - 1);}public void quick(int[] arr, int left, int right) {//遞歸結束的條件if (left >= right) {return;}//進行分割int pio = partition(arr, left, right);quick(arr, 0, pio - 1);quick(arr, pio + 1, right);}

hoare法分割

    public int partition(int[] arr, int left, int right) {int tmp = arr[left];int i = left;while (left < right) {while (left < right && arr[right] >= tmp) {right--;}while (left < right && arr[left] <= tmp) {left++;}//交換int tmp = array[right];array[right] = array[left];array[left] = tmp;}//交換int tmp = array[i];array[i] = array[left];array[left] = tmp;return left;}

挖坑法分割

    public int partition(int[] arr, int left, int right) {int tmp = arr[left];while (left < right) {while (left < right && arr[right] >= tmp) {right--;}arr[left] = arr[right];while (left < right && arr[left] <= tmp) {left++;}array[right] = array[left];}arr[left] = tmp;return left;}

優化: 如果待排序序列是:1、2、3、4、5這種有序的序列,假如還是取第一個元素為基準,就會出現左邊沒有小于基準的值,如何讓每次分割都是均勻分割?方法很簡單,取序列最左邊、最右邊和中間位置的三個元素的中位數作為基準,再進行Hoare法或者挖坑法分割,此時每次都能均勻分割,如圖
在這里插入圖片描述

優化后:

    public void QuickSort(int[] arr) {quick(arr, 0, arr.length - 1);}public void quick(int[] arr, int left, int right) {//遞歸if (left >= right) {return;}//中位數的值作為基準int midIndex = midThreeIndex(arr, left, right);//交換int tmp = arr[left];arr[left] = arr[midIndex];arr[midIndex] = tmp;    int pio = partition(arr, left, right);quick(arr, 0, pio - 1);quick(arr, pio + 1, right);}public int partition(int[] arr, int left, int right) {int tmp = arr[left];int i = left;while (left < right) {while (left < right && arr[right] >= tmp) {right--;}while (left < right && arr[left] <= tmp) {left++;}swap(arr, right, left);}swap(arr, i, left);return left;}        

6.2 非遞歸實現

原理: 利用棧這個數據結構來實現。首先先對序列進行一次分割(Hoare法或者挖坑法都可以),將基準左邊部分的left、right下標入棧,再將右邊部分的left、right下標入棧,然后出棧兩個元素作為新的left、right來進行分割,重復上述步驟,直到棧為空
在這里插入圖片描述

代碼實現:

    public void QuickSortNoRecursion(int[] arr) {Stack<Integer> stack = new Stack<>();int left = 0;int right = arr.length - 1;int pio = partition(arr, left, right);if (pio > left + 1) {stack.push(left);stack.push(pio - 1);}if (pio < right - 1) {stack.push(pio + 1);stack.push(right);}while (!stack.isEmpty()) {right = stack.pop();left = stack.pop();pio = partition(arr, left, right);if (pio > left + 1) {stack.push(left);stack.push(pio - 1);}if (pio < right - 1) {stack.push(pio + 1);stack.push(right);}}}

7、歸并排序

原理: 歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法的一個非常典型的應用。將已有序的子序列合并,得到完全有序的序列;歸并排序的思想是:先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為二路歸并。
在這里插入圖片描述
在這里插入圖片描述

7.1 遞歸實現

遞歸思路: 先將序列進行分解,直到分解為單個元素為一組,然后再進行合并。合并:開辟新的數組,新的數組存儲的是合并之后且有序的子序列,再開辟的新數組的元素拷貝回原數組

    public void mergeSort(int[] arr) {merge(arr, 0, arr.length - 1);}public void merge(int[] arr, int left, int right) {if (left >= right) {return;}int mid = (left + right) / 2;//分解merge(arr, left, mid);merge(arr, mid + 1, right);//合并mergeFun(arr, left, mid, right);}//合并public void mergeFun(int[] arr, int left,int mid, int right) {int s1 = left;int e1 = mid;int s2 = mid + 1;int e2 = right;int k = 0;int[] tmp = new int[right - left + 1];//開辟新的數組while (s1 <= e1 && s2 <= e2) {if (arr[s1] < arr[s2]) {tmp[k++] = arr[s1++];} else {tmp[k++] = arr[s2++];}}while (s1 <= e1) {tmp[k++] = arr[s1++];}while (s2 <= e2) {tmp[k++] = arr[s2++];}//此時tmp有序了,拷回到原數組for (int i = 0; i < k; i++) {arr[left + i] = tmp[i];}}

7.2 非遞歸實現

非遞歸省去了分解的步驟,直接對數組進行合并

    //非遞歸public void mergeSortN(int[] arr) {mergeN(arr);}//沒有分解的過程private void mergeN(int[] arr) {int gap = 1;while (gap <= arr.length) {for (int i = 0; i < arr.length; i = i + 2 * gap) {int mid = i + gap - 1;if (mid >= arr.length) {mid = arr.length - 1;}int right = mid + gap;if (right >= arr.length) {right = arr.length - 1;}mergeFun(arr, i, mid, right);}gap *= 2;}}public void mergeFun(int[] arr, int left,int mid, int right) {int s1 = left;int e1 = mid;int s2 = mid + 1;int e2 = right;int k = 0;int[] tmp = new int[right - left + 1];while (s1 <= e1 && s2 <= e2) {if (arr[s1] < arr[s2]) {tmp[k++] = arr[s1++];} else {tmp[k++] = arr[s2++];}}while (s1 <= e1) {tmp[k++] = arr[s1++];}while (s2 <= e2) {tmp[k++] = arr[s2++];}//此時tmp有序了,拷回到原數組for (int i = 0; i < k; i++) {arr[left + i] = tmp[i];}}

8、性能分析

性能包括:時間復雜度、空間復雜度、穩定性

排序算法平均時間復雜度空間復雜度穩定性
插入排序O(n^2)O(1)穩定
希爾排序O(和增量有關)O(1)不穩定
選擇排序O(n^2)O(1)不穩定
堆排序O(n*logn)O(1)不穩定
冒泡排序O(n^2)O(1)穩定
快速排序O(n*logn)O(logn)不穩定
歸并排序O(n*logn)O(n)穩定

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

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

相關文章

C++純C實現貪吃蛇小游戲

公眾號&#xff1a;編程驛站 #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <time.h>//描述蛇的節點信息 typedef struct SnakeNode {int x;int y; } Snode;//箱子&#xff1a;放置蛇的所有節點 Snode snakes[100]; //保存…

滲透思考題

一&#xff0c;嘗試登錄。 客戶端對密碼進行哈希處理并緩存密碼hash&#xff0c;丟棄實際的明文密碼&#xff0c;然后將用戶名發送到服務器&#xff0c;發起認證請求 密文存儲位置&#xff1a;數據庫文件位于C:WindowsSystem32configsam&#xff0c;同時掛載在注冊表中的HKLMSA…

C語言【文件操作 1】

文章目錄 1.為什么使用文件2.文件是什么&#xff1f;2.1程序文件2.2數據文件 3.二進制文件和文本文件4.文件的打開和關閉4.1流和標準流流標準流 4.2文件指針4.3文件的打開和關閉 結語 1.為什么使用文件 很簡單 長久的存儲數據 如果沒有文件&#xff0c;我們寫程序所產生的數據…

商米-android-使用NFC讀IC卡,身份證云解和IC卡同時兼容

商米介紹地址&#xff1a;https://www.sunmi.com/ 商米是一個提供手持PDA的一個很好的解決方案廠商&#xff0c; 也有其他的一些桌面設備。 其中商米提供的軟件服務中&#xff0c;比較特別的是 身份證云解功能。 此處重點說明一下&#xff0c;身份證云解功能。 以往市面上的身…

Vue學習JSON.stringify()將Object類型轉換成String類型

Vue學習JSON.stringify&#xff08;&#xff09;將Object類型轉換成String類型 一、前言1、基本用法2、復雜對象轉換3、過濾器函數4、序列化函數 一、前言 JSON.stringify() 是一個 JavaScript 函數&#xff0c;用于將 JavaScript 值轉換為 JSON 字符串。它接受一個 JavaScrip…

深入探索MySQL視圖

前言 在數據庫的世界里&#xff0c;MySQL視圖作為數據抽象的一把利劍&#xff0c;為我們提供了一種靈活而高效的方式來管理和查詢數據。它不僅能夠簡化復雜的查詢邏輯&#xff0c;還能在不改動底層數據結構的前提下&#xff0c;實現數據的定制化展示與訪問控制。本文旨在深入解…

【小紅書采集工具】根據搜索關鍵詞批量采集小紅書筆記,含筆記正文、筆記鏈接、發布時間、轉評贊藏等

一、背景介紹 1.1 爬取目標 熟悉我的小伙伴都了解&#xff0c;我之前開發過2款軟件&#xff1a; 【GUI軟件】小紅書搜索結果批量采集&#xff0c;支持多個關鍵詞同時抓取&#xff01; 【GUI軟件】小紅書詳情數據批量采集&#xff0c;含筆記內容、轉評贊藏等&#xff0c;支持…

【C++】string類的使用①(默認成員函數 || 迭代器接口begin,end,rbegin和rend)

&#x1f525;個人主頁&#xff1a; Forcible Bug Maker &#x1f525;專欄&#xff1a; STL || C 目錄 前言&#x1f308;關于string類&#x1f308;string類的成員函數&#x1f525;默認成員函數string類對象的構造(constructor)string類對象的析構string類對象的賦值運算符…

NPOI生成word浮動圖標

1、NPOI版本2.7.0, net框架4.8 2、安裝OpenXMLSDKToolV25.msi 3、先創建一個word文檔&#xff0c;并設置圖片為浮于文字之上 4、OpenXML顯示的結果 5、實際代碼如下&#xff1a; public class GenerateWordDemo {public GenerateWordDemo(){}//https://blog.fileformat.co…

js由那三部分組成

JavaScript 主要由三部分組成&#xff1a;ECMAScript、DOM&#xff08;文檔對象模型&#xff09;和 BOM&#xff08;瀏覽器對象模型&#xff09;。 1、ECMAScript ECMAScript 是 JavaScript 的核心&#xff0c;描述了語言的基本語法&#xff08;變量、函數、條件語句、循環、…

前端筆記-day03

文章目錄 01-初始CSS02-CSS引入方式03-標簽選擇器04-類選擇器05-id選擇器06-通配符選擇器07-畫盒子08-字體大小09-文字粗細10-字體傾斜11-行高12-行高垂直居中13-字體族14-font復合屬性15-文本縮進16-文本對齊方式17-圖片對齊方式18-文本修飾線19-文字顏色20-調試工具21-綜合案…

Dual Aggregation Transformer for Image Super-Resolution論文總結

題目&#xff1a;Dual Aggregation Transformer&#xff08;雙聚合Transformer&#xff09; for Image Super-Resolution&#xff08;圖像超分辨&#xff09; 論文&#xff08;ICCV&#xff09;&#xff1a;Chen_Dual_Aggregation_Transformer_for_Image_Super-Resolution_ICCV…

IM 是什么?

在當今數字化的時代&#xff0c;即時通訊&#xff08;IM&#xff09;已經滲透到人們的日常生活和企業的工作環境中。IM技術的快速i發展為人們提供了一種高效、便捷的溝通方式&#xff0c;不僅推動了社會的信息化進程&#xff0c;也提升了企業的協同效率和競爭力。 作為企業級I…

【GD32】01-GPIO通用輸入輸出

GD32 閑話說在前頭 這里又開一個系列啦。 原因就是之前買了立創開發板的9.9的GD32E230C8T6的板子&#xff0c;買都買了就跟著立創開發板學習一下&#xff08;屬于是一次性支持了兩個國產品牌了&#xff0c;立創和兆易創新&#xff09;。并且我還買了GD32F407VET6的板子&…

資金流分析下的企業供貨關系強度模型

圖技術 利用neo4j、networkx、dgl、python做圖分析挖掘 【1】最短路徑算法dijkstra 【2】基于networkx的隱性集團關系識別模型 【3】基于Neo4j的擔保社群型態分析挖掘 【4】基于python求有向無環圖中target到其他節點全路徑 【5】有向圖中任意兩點的路徑 【6】圖基礎入門 【7】…

項目管理中控制質量的工具與技術

項目管理中控制質量的工具與技術 控制質量的工具與技術包括多種方法&#xff0c;旨在確保產品或服務達到既定的質量標準。關于具體的工具格式和樣式&#xff0c;以下是一些示例&#xff1a; 統計技術&#xff1a; 這是一種將質量控制要素的數據轉化為實際控制手段的技術。通…

Visual Studio和Visual Studio Code適用于哪些編程語言

Visual Studio和Visual Studio Code都適用于多種編程語言&#xff0c;它們的適用編程語言如下&#xff1a; Visual Studio適用于&#xff1a; C#Visual Basic .NETF#CJavaScriptTypeScriptPythonHTML/CSSJava&#xff08;通過插件支持&#xff09; Visual Studio Code適用于…

Jtti:哪些方法可以降低美國CN2服務器的延遲?

降低美國CN2服務器的延遲可以采取多種方法&#xff0c;以下是一些常用的方法&#xff1a; 1.選擇優質的網絡提供商和服務商&#xff1a;選擇具有高質量網絡和優質服務的網絡提供商和服務商是降低延遲的關鍵。確保您選擇的網絡提供商具有可靠的基礎設施和優質的網絡連接&#xf…

C++:關于圓形魚眼半全景圖轉為等距圓柱投影圖

C&#xff1a;空間坐標映射到球面坐標/全景圖_如何將球體坐標映射到球面uv-CSDN博客 C&#xff1a;關于360全景圖像和立方體6面全景圖像的相互轉換_彩色全景拆解正方體6個面-CSDN博客 之前記錄了立方體和360全景之間的轉換&#xff0c;這次記錄下魚眼圖與360全景圖之間的轉換…

C++ STL的鎖介紹

在 C Standard Template Library (STL) 中&#xff0c;有幾個鎖的實現&#xff0c;這些都位于 <mutex> 頭文件。以下是一些常見的鎖及其功能&#xff1a; std::mutex&#xff1a;最基本的互斥鎖&#xff0c;不可遞歸使用。該鎖提供了獨占的非公平鎖定能力。 std::mutex…