【Java算法】八大排序

八大排序算法

目錄

注意:以下排序均屬于內部排序


排序總結分析表

在這里插入圖片描述


一、插入排序

在這里插入圖片描述

1. 直接插入排序

(1)整體思路

通過動圖可以形象的理解到

說明:(慣用思想)初始時視第一個元素是有序的,之后通過排序逐漸增大有序序列的長度

(2)代碼實現

第一種寫法:while 循環更規范

public static void insert_sort(int[] arr) {/*插入排序的思想:從無序的序列中拿一個數,通過比較的方式插入到有序序列中初始狀態:假設第一個數是有序的,從第二個元素開始,和有序序列比較,然后插入*/// 在無序序列中抽取一張牌for (int i = 1; i < arr.length; i++) {// 記錄要插入的元素值,位置位于有序序列的末尾int insertvalue = arr[i];// 在有序序列中從后往前和插入元素比較,找到插入位置int j = i - 1;/*1 2 3 9 10 15 5插入5:需要插入在3的后面。所以只要插入元素比當前比較元素小,就往后移*/// 推薦這種寫法,更規范while (j >= 0 && insertvalue < arr[j]) {arr[j + 1] = arr[j]; //  元素后裔j--;}// 插入元素(插入到  比當前插入元素小的 元素  的后面)arr[j + 1] = insertvalue;}
}

第二種寫法:使用for 循環

public static void insert_sort_1(int[] arr) {// 第二種寫法:使用for循環for (int i = 1; i < arr.length; i++) {int insertvalue = arr[i];int j = i - 1;for (; j >= 0; j--) {if (insertvalue < arr[j]) {arr[j + 1] = arr[j];}else{break; // 如果 insertvalue >= arr[j] 就退出循環}}arr[j + 1] = insertvalue;}
}

2. 折半插入排序

改進點:使用折半查找提高效率,使用循環遍歷逐個匹配的效率太差

    // 查找插入位置的方法采用二分思想(由于查找位置的序列本身就是有序的,所以可以使用二分)
public static void binary_insert_sort(int[] arr) {for (int i = 1; i < arr.length; i++) {// 初始時:把第一個元素看成是有序的,然后進行插入排序int insertvalue = arr[i];int left = 0;int right = i - 1; // 和 j = i -1 是等價的while (left <= right) {int mid = left + ((right - left) / 2);if (arr[mid] < insertvalue) {left = mid + 1;} else {right = mid - 1;}}// 找到了插入位置,移動元素為插入做準備// 為了維持穩定性,應該插入到 right 的后邊// 插入位置為 right + 1 , 需要把這個位置空出來才可以插入,所以要取等for (int j = i - 1; j >= right + 1; j--) {arr[j + 1] = arr[j]; //元素后移}arr[right + 1] = insertvalue;}
}

3. 希爾排序

動圖演示

在這里插入圖片描述

使用間隔 gap,gap 逐漸遞減,最后 gap 的值必須是一,每一輪排序對 gap 產生的序列進行排序

快速寫希爾排序:把直接插入排序中 “ 1 ” 的位置全部替換“ gap ”

/*
快速寫希爾排序算法代碼:只要把直接插入排序中為 1 的地方全部改成 gap 即可*/
public static void shell_sort(int[] arr){// 增量序列取中間值(常用方法)/*增量序列是遞減的,并且最后一個值一定是一*/int gap = arr.length / 2; // 向下取整while (gap >= 1) {shell(arr, gap);gap /= 2;}
}// 一趟寫入排序的過程
public static void shell(int[] arr, int gap){// 思想和直接插入排序,不同點就在原來 “加/減一” 的位置全部變成 “gap”// 由于是分組排,這里需要包含分組的第一個元素,所以不加一for (int i = gap; i < arr.length; i++) {int insertvalue = arr[i];int j = i - gap;// 移動元素while(j >= 0 && insertvalue < arr[j]){arr[j + gap] = arr[j];j -= gap;}arr[j + gap] = insertvalue;}
}

二、交換排序

1. 冒泡排序

動圖演示

在這里插入圖片描述

(1)普通版本

public static void bubble_sort(int[] arr){for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {// 前面的比后面大,交換位置if(arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}

(2)改進版本

亮點:通過變量標記的方式標記是否執行了交換操作,可以一定程度上減少比較次數

// 改進版本:如果本身就有序,則無序交換,減少比較次數
public static void bubble_sort_improve(int[] arr){for (int i = 0; i < arr.length - 1; i++) {int flag = 0;  // 每次進入循環都標記為0,如果有序就不交換,flag = 0for (int j = 0; j < arr.length - 1 - i; j++) {// 前面的比后面大,交換位置if(arr[j] > arr[j + 1]){flag = 1; // 交換了就標記為一int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}if(flag == 0){/* 在一趟遍歷之后,如果都沒有發生交換,說明元素已經有序了,后面的比較沒有意義了,直接退出*/break;}}
}

2. 快速排序

動圖演示

在這里插入圖片描述

主要思想:遞歸,雙指針(對撞指針)

思路分析

 /*快速排序是冒泡排序的改進版本,核心在于遞歸和雙指針思想說明1.選取數組的第一個元素為樞紐2.left,right為數組下標3.延申:可以對任意區間排序*/public static int partition(int[] arr, int left, int right) {/*雙指針思想1.left:指向數組的 第一個 元素,從 左往右 找,如果比中間值 大,就搬到后面(high的位置)2.right:指向數組的 最后一個 元素,從 左右往左 找,如果比中間值 小,就搬到前面(left的位置)*/int pivot = arr[left];// 兩個指針的移動逐漸靠近,當兩個指針重合時,退出循環// 此時指向的位置就是樞紐的位置while (left < right) {/*注意:指針的移動可能會越界,需要加上判斷條件 left < right易錯點:先找小的,后找大的*/// 首先在后面找小的往前搬(那對立面就是不符合要求,right指針往前移)while (arr[right] >= pivot && left < right) {right--;}arr[left] = arr[right];// 然后在前面找大的往后搬(那對立面就是不符合要求,left指針往后移)while (arr[left] <= pivot && left < right) {left++;}arr[right] = arr[left];}// 此時 left = right,指向中間樞紐的位置,放入樞紐值,返回樞紐的位置arr[left] = pivot;return left;
}public static void quicksort(int[] arr, int left, int right) {/*遞歸易錯的地方:需要有一個遞歸出口*/if(left < right){int pivot = partition(arr,left,right); // 首先計算樞紐值// 遞歸遞歸左子區間quicksort(arr,left,pivot - 1);// 遞歸排序右子區間quicksort(arr,pivot + 1,right);}
}

三、選擇排序

1. 簡單選擇排序

動圖演示

在這里插入圖片描述

基本思路:選一個數,在這個數的后面找有沒有比本身還小的,有就交換位置

優化點:在后面找一個最小的數,避免重復的覆蓋,減少比較次數

區別冒泡排序的優化

(1)普通版本

public static void select_sort(int[] arr){for (int i = 0; i < arr.length; i++) {for (int j = i + 1; j < arr.length; j++){if(arr[j] < arr[i]){int temp = arr[j];arr[j] = arr[i];arr[i] = temp;}}}
}

(2)改進版本

public static void select_sort_improve(int[] arr){// 比較 n-1 趟for (int i = 0; i < arr.length; i++) {int min_index = i; // 假設當前元素是最小的,記錄下標// 在當前元素的后面找有沒有更小的,有就交換位置for (int j = i + 1; j < arr.length; j++){// 如果找到更小的,就更新下標if(arr[j] < arr[min_index]){min_index = j;}}// 如果最小元素不是本身(找到了更小的),就交換位置if(min_index != i){int temp = arr[i];arr[i] = arr[min_index];arr[min_index] = temp;}}
}

2. 堆排序(二叉堆)

(1)基本介紹

補充:關于樹中節點的序號和數組下標的關系

方法:從左到右,從上到下依次標號

圖例(對應數組下標

       0/   \1      2/ \    / \3   4  5   6

大根堆示例

       10/    \8      6/ \    / \5   3  2

小根堆示例

       1/    \3      4/ \    / \6   8  9

(2)堆排序思想

堆排序代碼

/*
堆排序思想(又叫二叉堆)
分類:大頂堆,小頂堆堆符合二叉樹的性質說明:數組的下標在樹中是:從上到下,從左到右依次編號的排序過程說明1. 構建一個大頂堆,每次交換最小和最大的,并且堆大小縮小減一,
2. 交換的過程:把最大的放在有序區,但是破壞了大頂堆的結構,需要重新調整堆3. 有序的過程:把最大的放在有序區,數組從后往前一次放入有序元素完成排序*/// 堆調整(大頂堆)
// n:表示數組的大小;i:表示最大值的下標索引
public static void heapify(int[] arr, int n, int i) {/*易錯:這里表示的下標值,然而二叉樹中的性質指的是物理位置數組是從0開始編號的,舉例說明7/   \6     57:下標索引是06:按照物理位置計算方法(左孩子:2 * i = 0),結果還是0,但是下標索引是1得出的關系:在物理位置的基礎上加一才是索引下標*/int max_index = i; // 初始化最大值下標索引int left = 2 * i + 1; // 左孩子的下標索引int right = 2 * i + 2; // 右孩子的下標索引// 和左右孩子比較,更新最大值下標索引// 注意:防止越界,需要加上限制條件if (left < n && arr[left] > arr[max_index]) {max_index = left;}if (right < n && arr[right] > arr[max_index]) {max_index = right;}// 如果最大值不是初始化的值,說明找到了更大的值,把最大值放到根節點if (max_index != i) {int temp = arr[i];arr[i] = arr[max_index];arr[max_index] = temp;// 遞歸調整左右子樹(max_index在這個過程中做了更新)heapify(arr, n, max_index);}
}//堆排序
public static void heap_sort(int[] arr) {/*7/   \6     5/ \   / \4   3 2   1總節點數:7循環起點:7/2 - 1 = 3 - 1 = 2,即下標為2的元素開始(元素5)*/// 構建大頂堆(如果每一個子樹都是大頂堆,則整個二叉堆就是大頂堆)int n = arr.length;// 從最后一個非葉子節點開始向上進行堆調整for (int i = n / 2 - 1; i >= 0; i--) {heapify(arr, n, i);}// 排序過程:交換元素,調整堆,進行 n - 1 趟排序// 初值:每交換一次,可以理解為排序一個元素,則堆中需要排序的元素總數減少一// 初值為 i -1 正好對應最后一個元素的下標,方便交換for (int i = n - 1; i > 0; i--) {// 把最大的和最小的進行交換int temp = arr[0];arr[0] = arr[i];arr[i] = temp;// 交換后破壞了大頂堆的結構,重新調整堆(排序的過程中堆的大小在遞減)heapify(arr, i, 0);}
}

四、歸并排序

動圖演示

請添加圖片描述

思路:運用合并為有序序列的思想、遞歸思想,兩個有序序列通過比較的方式合并成一個更長的有序序列,而比較的過程正好是排序的過程

小結:排序左區間,排序右區間,兩個區間合并,然而排序的過程又是兩個區間合并的過程,即采用遞歸思想

歸并排序代碼



五、基數排序

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

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

相關文章

玩轉Docker | 使用Docker部署Qwerty Learner英語單詞學習網站

玩轉Docker | 使用Docker部署Qwerty Learner英語單詞學習網站 前言一、Qwerty Learner簡介Qwerty Learner 簡介主要特點二、系統要求環境要求環境檢查Docker版本檢查檢查操作系統版本三、部署Qwerty Learner服務下載Qwerty Learner鏡像編輯部署文件創建容器檢查容器狀態檢查服務…

Vue3中computed和watch的區別

文章目錄 前言&#x1f50d; 一、computed vs watch? 示例對比1. computed 示例&#xff08;適合模板綁定、衍生數據&#xff09;2. watch 示例&#xff08;副作用&#xff0c;如調用接口&#xff09; &#x1f9e0; 二、源碼實現原理&#xff08;簡化理解&#xff09;1. comp…

C++修煉:C++11(二)

Hello大家好&#xff01;很高興我們又見面啦&#xff01;給生活添點passion&#xff0c;開始今天的編程之路&#xff01; 我的博客&#xff1a;<但凡. 我的專欄&#xff1a;《編程之路》、《數據結構與算法之美》、《題海拾貝》、《C修煉之路》 歡迎點贊&#xff0c;關注&am…

單元測試與QTestLib框架使用

一.單元測試的意義 在軟件開發中&#xff0c;單元測試是指對軟件中最小可測試單元&#xff08;通常是函數、類的方法&#xff09;進行隔離的、可重復的驗證。進行單元測試具有以下重要意義&#xff1a; 1.提升代碼質量與可靠性&#xff1a; 早期錯誤檢測&#xff1a; 在開發…

(附實現代碼)Step-Back 回答回退策略擴大檢索范圍

1. LangChain 少量示例提示模板 在與 LLM 的對話中&#xff0c;提供少量的示例被稱為 少量示例&#xff0c;這是一種簡單但強大的指導生成的方式&#xff0c;在某些情況下可以顯著提高模型性能&#xff08;與之對應的是零樣本&#xff09;&#xff0c;少量示例可以降低 Prompt…

16-Oracle 23 ai-JSON-Relational Duality-知識準備

一直做DBA的小伙伴&#xff0c;是不是對開發相對陌生一些。JSON 關系二元性是 Oracle Database 23ai 中重要的特性&#xff0c;同時帶來的是范式革命。JSON關系二元性解決了數據庫領域的根本矛盾?&#xff0c;結構化數據的嚴謹性與半結構化數據的靈活性之間的矛盾。 JSON Rela…

什么是預訓練?深入解讀大模型AI的“高考集訓”

1. 預訓練的通俗理解&#xff1a;AI的“高考集訓” 我們可以將預訓練&#xff08;Pre-training&#xff09; 形象地理解為大模型AI的“高考集訓”。就像學霸在高考前需要刷五年高考三年模擬一樣&#xff0c;大模型在正式誕生前&#xff0c;也要經歷一場聲勢浩大的“題海戰術”…

思爾芯攜手Andes晶心科技,加速先進RISC-V 芯片開發

在RISC-V生態快速發展和應用場景不斷拓展的背景下&#xff0c;芯片設計正面臨前所未有的復雜度挑戰。近日&#xff0c;RISC-V處理器核領先廠商Andes晶心科技與思爾芯&#xff08;S2C&#xff09;達成重要合作&#xff0c;其雙核單集群AX45MPV處理器已在思爾芯最新一代原型驗證系…

vscode配置lua

官網下載lua得到如下 打開vscode的擴展下載如下三個 打開vscode的此處設置 搜索 executorMap&#xff0c;并添加如下內容

理解 RAG_HYBRID_BM25_WEIGHT:打造更智能的混合檢索增強生成系統

目錄 理解 RAG_HYBRID_BM25_WEIGHT&#xff1a;打造更智能的混合檢索增強生成系統 一、什么是 Hybrid RAG&#xff1f; 二、什么是 RAG_HYBRID_BM25_WEIGHT&#xff1f; 三、參數設置示例 四、什么時候該調整它&#xff1f; 五、實戰建議 六、總結 理解 RAG_HYBRID_BM25…

Spring Boot 2 中 default-autowire 的使用

Spring Boot 2 中 default-autowire 的使用 在 Spring Boot 2 中&#xff0c;default-autowire 這個來自傳統 XML 配置的概念仍然存在&#xff0c;但它的使用已經大大減少&#xff0c;因為現代 Spring Boot 應用主要使用注解驅動的配置方式。 default-autowire 在 Spring Boo…

Spring Boot + Thymeleaf 防重復提交

在 Spring Boot 與 Thymeleaf 結合的 Web 應用中&#xff0c;防止重復提交可以采用token 機制 客戶端禁用按鈕的方式實現&#xff0c;在高并發場景下&#xff0c;考慮使用 Redis 存儲 token 而非 Session。 第一步&#xff1a;后端實現 Controller public class FormControl…

【20250607接單】Spark + Scala + IntelliJ 項目的開發環境配置從零教學

本教程適用于零基礎、一臺剛裝好 Windows 的全新電腦開始&#xff0c;搭建能運行 Spark Scala IntelliJ 項目的開發環境。以下是超詳細、小白級別逐步教程&#xff0c;從“下載什么”到“點擊哪里”都幫你列清楚。 &#x1f3af; 目標 操作系統&#xff1a;Windows10/11工具…

【ubuntu】虛擬機安裝配置,sh腳本自動化,包含 apt+時間同步+docker+mysql+redis+pgsql

可以說是ubuntu基礎環境搭建合集&#xff0c;個人學習用&#xff0c;使用sh一鍵安裝&#xff0c;避免復制各種命令 流程主要包括 0. 可選擇不同ubuntu版本對應安裝&#xff08;支持 Ubuntu 20.04/22.04/23.04/24.04&#xff09; 1. apt換源aliyun 2. 時間選擇上海時區&#x…

Rust 學習筆記:關于智能指針的練習題

Rust 學習筆記&#xff1a;關于智能指針的練習題 Rust 學習筆記&#xff1a;關于智能指針的練習題問題一問題二問題三問題四問題五問題六問題七問題八問題九問題十問題十一 Rust 學習筆記&#xff1a;關于智能指針的練習題 參考視頻&#xff1a; https://www.bilibili.com/vi…

JavaScript ES6 解構:優雅提取數據的藝術

JavaScript ES6 解構&#xff1a;優雅提取數據的藝術 在 JavaScript 的世界中&#xff0c;ES6&#xff08;ECMAScript 2015&#xff09;的推出為開發者帶來了許多革命性的特性&#xff0c;其中“解構賦值”&#xff08;Destructuring Assignment&#xff09;無疑是最受歡迎的功…

Shell 命令及運行原理 + 權限的概念(7)

文章目錄 Shell 命令以及運行原理&#xff08;4-1.22.08&#xff09;Linux權限的概念1. 什么是權限2. 認識人&#xff08;普通用戶&#xff0c;root用戶&#xff09;以及兩種用戶的切換認識普通用戶和root用戶兩種用戶之間的切換指令提權 3. 文件的屬性解析 權限屬性指令ll顯示…

以智能管理為基礎,樓宇自控打造建筑碳中和新路徑

在全球氣候變化的嚴峻形勢下&#xff0c;“碳中和”已成為各國發展的重要戰略目標。建筑行業作為能源消耗與碳排放的“大戶”&#xff0c;其運行階段的能耗占全社會總能耗近40%&#xff0c;碳排放占比與之相當&#xff0c;實現建筑碳中和迫在眉睫。傳統建筑管理模式下&#xff…

Python爬蟲實戰:研究Hyper 相關技術

一、項目概述 本項目展示了如何結合 Python 的異步編程技術與 Hyper 框架開發一個高性能、可擴展的網絡爬蟲系統。該系統不僅能夠高效地爬取網頁內容,還提供了 RESTful API 接口,方便用戶通過 API 控制爬蟲的運行狀態和獲取爬取結果。 二、系統架構設計 1. 整體架構 系統采…

html 滾動條滾動過快會留下邊框線

滾動條滾動過快時&#xff0c;會留下邊框線 但其實大部分時候是這樣的&#xff0c;沒有多出邊框線的 滾動條滾動過快時留下邊框線的問題通常與滾動條樣式和滾動行為有關。這種問題可能出現在使用了自定義滾動條樣式的情況下。 注意&#xff1a;使用方法 6 好使&#xff0c;其它…