【算法基礎】三指針排序算法 - JAVA

一、基礎概念

1.1 什么是三指針排序

三指針排序是一種特殊的分區排序算法,通過使用三個指針同時操作數組,將元素按照特定規則進行分類和排序。這種算法在處理包含有限種類值的數組時表現出色,最經典的應用是荷蘭國旗問題(Dutch National Flag Problem)。

1.2 三指針排序的基本思想

三指針排序的核心思想是:

  • 使用三個指針將數組劃分為若干個區域
  • 通過元素交換,確保每個區域內的元素都滿足特定條件
  • 一次遍歷完成所有元素的分類排序

1.3 時間復雜度與空間復雜度

  • 時間復雜度:O(n),僅需一次遍歷
  • 空間復雜度:O(1),只使用常數級別的額外空間(幾個指針變量)

二、三指針排序的分類

2.1 按值分類的三指針排序

這是最常見的三指針排序應用,將數組中的元素按照特定值分為三類:

  • 小于基準值的元素
  • 等于基準值的元素
  • 大于基準值的元素

2.2 多值三指針排序

處理有三種不同元素的數組,如荷蘭國旗問題中的紅、白、藍三色:

  • 第一類元素(如0或紅色)
  • 第二類元素(如1或白色)
  • 第三類元素(如2或藍色)

三、三指針排序實現(荷蘭國旗問題)

3.1 數據結構設計

三指針排序主要操作簡單數組,不需要特殊的數據結構設計,只需要三個指針變量:

int low = 0;        // 指向第一類元素(0)的右邊界
int mid = 0;        // 遍歷指針,指向當前處理的元素
int high = n - 1;   // 指向第三類元素(2)的左邊界

3.2 排序算法實現

public class ThreePointerSort {/*** 三指針排序算法(荷蘭國旗問題)* 將數組中的0、1、2三種元素排序*/public void sortColors(int[] nums) {int low = 0;        // 0的右邊界int mid = 0;        // 當前處理元素int high = nums.length - 1;  // 2的左邊界while (mid <= high) {if (nums[mid] == 0) {// 當前元素為0,將其交換到左側區域swap(nums, low, mid);low++;mid++;} else if (nums[mid] == 1) {// 當前元素為1,保持位置不變mid++;} else { // nums[mid] == 2// 當前元素為2,將其交換到右側區域swap(nums, mid, high);high--;// 注意:這里mid不遞增,因為交換后的元素需要重新檢查}}}/*** 交換數組中兩個元素的位置*/private void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}

3.3 實現細節

三個區域劃分

  • [0, low-1]:所有等于0的元素
  • [low, mid-1]:所有等于1的元素
  • [mid, high]:待處理的元素
  • [high+1, n-1]:所有等于2的元素

處理邏輯

  • 當前元素為0:將其交換到左側區域,lowmid都向右移動
  • 當前元素為1:保持位置不變,只移動mid
  • 當前元素為2:將其交換到右側區域,high向左移動,mid不動(需要重新檢查交換后的元素)

終止條件

  • mid > high時,所有元素都已處理完畢

四、執行示例

4.1 示例數組

以數組 [2, 0, 1, 2, 1, 0] 為例:

4.2 執行過程

  1. 初始狀態low=0, mid=0, high=5
    • 數組:[2, 0, 1, 2, 1, 0]
  2. 第一步nums[mid]=2
    • 交換 nums[mid]nums[high][0, 0, 1, 2, 1, 2]
    • high=4, mid=0 (不變)
  3. 第二步nums[mid]=0
    • 交換 nums[low]nums[mid][0, 0, 1, 2, 1, 2] (實際未變)
    • low=1, mid=1
  4. 第三步nums[mid]=0
    • 交換 nums[low]nums[mid][0, 0, 1, 2, 1, 2] (實際未變)
    • low=2, mid=2
  5. 第四步nums[mid]=1
    • mid=3
  6. 第五步nums[mid]=2
    • 交換 nums[mid]nums[high][0, 0, 1, 1, 2, 2]
    • high=3, mid=3
  7. 第六步nums[mid]=1
    • mid=4
  8. 第七步mid=4 > high=3算法終止
    • 最終數組:[0, 0, 1, 1, 2, 2]

五、三指針擴展應用

5.1 快速排序的三路劃分

三路快排是三指針思想的另一個重要應用:

  • 將數組劃分為小于、等于、大于基準值的三個部分
  • 特別適合處理有大量重復元素的數組
  • 可顯著提高快排效率
public void quickSort3Way(int[] arr, int low, int high) {if (low >= high) return;// 選擇基準值int pivot = arr[low];int lt = low;      // 小于區域右邊界int gt = high;     // 大于區域左邊界int i = low + 1;   // 當前處理元素while (i <= gt) {if (arr[i] < pivot) {swap(arr, lt++, i++);} else if (arr[i] > pivot) {swap(arr, i, gt--);} else {i++;}}// 遞歸排序小于和大于部分quickSort3Way(arr, low, lt - 1);quickSort3Way(arr, gt + 1, high);
}

5.2 處理特定數據集的分組

三指針排序可用于將數組按特定規則分為三組,如:

  • 負數、零和正數
  • 奇數、能被3整除的數和其他數
  • 特定范圍內的元素、低于和高于范圍的元素

5.3 優化特定范圍查找

當需要找出數組中屬于特定值范圍的所有元素時,可使用三指針方法快速劃分:

public int[] findElementsInRange(int[] nums, int low, int high) {// 使用三指針劃分數組int[] result = new int[nums.length];int count = partitionByRange(nums, low, high);// 復制中間區域元素并返回// ...
}private int partitionByRange(int[] nums, int lowVal, int highVal) {int left = 0;int curr = 0;int right = nums.length - 1;while (curr <= right) {if (nums[curr] < lowVal) {swap(nums, left++, curr++);} else if (nums[curr] > highVal) {swap(nums, curr, right--);} else {curr++;}}return right - left + 1; // 返回范圍內元素數量
}

六、完整示例程序

6.1 處理三種顏色的完整實現

public class ThreeColorSort {public static void main(String[] args) {int[] colors = {2, 0, 1, 1, 0, 2, 1, 2, 0, 0, 1, 2};System.out.println("排序前: " + arrayToString(colors));sortColors(colors);System.out.println("排序后: " + arrayToString(colors));}public static void sortColors(int[] nums) {int low = 0;        // 0的右邊界int mid = 0;        // 當前處理元素int high = nums.length - 1;  // 2的左邊界while (mid <= high) {if (nums[mid] == 0) {swap(nums, low++, mid++);} else if (nums[mid] == 1) {mid++;} else { // nums[mid] == 2swap(nums, mid, high--);}}}private static void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}private static String arrayToString(int[] arr) {StringBuilder sb = new StringBuilder("[");for (int i = 0; i < arr.length; i++) {sb.append(arr[i]);if (i < arr.length - 1) {sb.append(", ");}}sb.append("]");return sb.toString();}
}

6.2 基于值范圍的三路劃分

public class ThreeWayPartition {public static void main(String[] args) {int[] arr = {5, 2, 8, 12, 3, 6, 9, 4, 10, 7};int lowVal = 4;int highVal = 8;System.out.println("原數組: " + arrayToString(arr));System.out.println("劃分范圍: [" + lowVal + ", " + highVal + "]");partitionByRange(arr, lowVal, highVal);System.out.println("劃分后: " + arrayToString(arr));}public static void partitionByRange(int[] nums, int lowVal, int highVal) {int left = 0;int curr = 0;int right = nums.length - 1;while (curr <= right) {if (nums[curr] < lowVal) {swap(nums, left++, curr++);} else if (nums[curr] > highVal) {swap(nums, curr, right--);} else {curr++;}}}private static void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}private static String arrayToString(int[] arr) {StringBuilder sb = new StringBuilder("[");for (int i = 0; i < arr.length; i++) {sb.append(arr[i]);if (i < arr.length - 1) {sb.append(", ");}}sb.append("]");return sb.toString();}
}

七、總結

三指針排序算法是一種高效、簡潔的算法,特別適合處理有限種類值的排序問題。

核心要點

  • 一次遍歷完成排序
  • 原地操作,不需要額外空間
  • 線性時間復雜度 O(n)
  • 特別適合處理三種不同元素的排序問題

優點

  • 簡單易實現
  • 高效(一次遍歷)
  • 空間利用率高(原地操作)
  • 穩定性可控

缺點

  • 僅適用于處理有限種類元素的排序
  • 需要明確定義元素的優先級或類別

應用場景

  • 荷蘭國旗問題(三色排序)
  • 快速排序的三路劃分優化
  • 特定元素分組(如正數、零、負數)
  • 數據預處理和清洗
  • 基于特征值的數據分類

三指針排序是分治思想和指針技術的巧妙結合,體現了算法設計中"簡單而高效"的理念。掌握這一技術不僅有助于解決特定問題,更能啟發我們思考更廣泛的算法設計方法。

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

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

相關文章

《操作系統真象還原》第十二章(2)——進一步完善內核

文章目錄 前言可變參數的原理實現系統調用write更新syscall.h更新syscall.c更新syscall-init.c 實現printf編寫stdio.h編寫stdio.c 第一次測試main.cmakefile結果截圖 完善printf修改main.c 結語 前言 上部分鏈接&#xff1a;《操作系統真象還原》第十二章&#xff08;1&#…

ICML2021 | DeiT | 訓練數據高效的圖像 Transformer 與基于注意力的蒸餾

Training data-efficient image transformers & distillation through attention 摘要-Abstract引言-Introduction相關工作-Related Work視覺Transformer&#xff1a;概述-Vision transformer: overview通過注意力機制蒸餾-Distillation through attention實驗-Experiments…

深度學習:AI 機器人時代

在科技飛速發展的當下&#xff0c;AI 機器人時代正以洶涌之勢席卷而來&#xff0c;而深度學習作為其核心驅動力&#xff0c;正重塑著我們生活與工作的方方面面。 從智能工廠的自動化生產&#xff0c;到家庭中貼心服務的智能助手&#xff0c;再到復雜環境下執行特殊任務的專業機…

《告別試錯式開發:TDD的精準質量鍛造術》

深度解鎖TDD&#xff1a;應用開發的創新密鑰 在應用開發的復雜版圖中&#xff0c;如何雕琢出高質量、高可靠性的應用&#xff0c;始終是開發者們不懈探索的核心命題。測試驅動開發&#xff08;TDD&#xff09;&#xff0c;作為一種顛覆性的開發理念與方法&#xff0c;正逐漸成…

應用層自定義協議序列與反序列化

目錄 一、網絡版計算器 二、網絡版本計算器實現 2.1源代碼 2.2測試結果 一、網絡版計算器 應用層定義的協議&#xff1a; 應用層進行網絡通信能否使用如下的協議進行通信呢&#xff1f; 在操作系統內核中是以這種協議進行通信的&#xff0c;但是在應用層禁止以這種協議進行…

Excel-CLI:終端中的輕量級Excel查看器

在數據驅動的今天&#xff0c;Excel 文件處理成為了我們日常工作中不可或缺的一部分。然而&#xff0c;頻繁地在圖形界面與命令行界面之間切換&#xff0c;不僅效率低下&#xff0c;而且容易出錯。現在&#xff0c;有了 Excel-CLI&#xff0c;一款運行在終端中的輕量級Excel查看…

百度后端開發一面

mutex, rwmutex 在Go語言中&#xff0c;Mutex&#xff08;互斥鎖&#xff09;和RWMutex&#xff08;讀寫鎖&#xff09;是用于管理并發訪問共享資源的核心工具。以下是它們的常見問題、使用場景及最佳實踐總結&#xff1a; 1. Mutex 與 RWMutex 的區別 Mutex: 互斥鎖&#xf…

STM32 IIC總線

目錄 IIC協議簡介 IIC總線系統結構 IIC總線物理層特點 IIC總線協議層 空閑狀態 應答信號 數據的有效性 數據傳輸 STM32的IIC特性及架構 STM32的IIC結構體 0.96寸OLED顯示屏 SSD1306框圖及引腳定義 4針腳I2C接口模塊原理圖 字節傳輸-I2C 執行邏輯框圖 命令表…

【unity游戲開發入門到精通——UGUI】整體控制一個UGUI面板的淡入淡出——CanvasGroup畫布組組件的使用

注意&#xff1a;考慮到UGUI的內容比較多&#xff0c;我將UGUI的內容分開&#xff0c;并全部整合放在【unity游戲開發——UGUI】專欄里&#xff0c;感興趣的小伙伴可以前往逐一查看學習。 文章目錄 前言CanvasGroup畫布組組件參數 實戰專欄推薦完結 前言 如果我們想要整體控制…

大型語言模型個性化助手實現

大型語言模型個性化助手實現 目錄 大型語言模型個性化助手實現PERSONAMEM,以及用戶資料和對話模擬管道7種原位用戶查詢類型關于大語言模型個性化能力評估的研究大型語言模型(LLMs)已經成為用戶在各種任務中的個性化助手,從提供寫作支持到提供量身定制的建議或咨詢。隨著時間…

生成式 AI 的未來

在人類文明的長河中,技術革命始終是推動社會躍遷的核心引擎。從蒸汽機解放雙手,到電力點亮黑夜,再到互聯網編織全球神經網絡,每一次技術浪潮都在重塑人類的生產方式與認知邊界。而今天,生成式人工智能(Generative AI)正以一種前所未有的姿態登上歷史舞臺——它不再局限于…

【序列化與反序列化詳解】

文章目錄 一、序列化與反序列化是什么&#xff1f;1. 為什么需要序列化&#xff1f;2. 反序列化的作用 二、常見的序列化格式三、不同編程語言的序列化與反序列化示例1. Python 的序列化與反序列化JSON 序列化Pickle 序列化&#xff08;僅限 Python&#xff09; 2. Java 的序列…

【單例模式】簡介

目錄 概念理解使用場景優缺點實現方式 概念理解 單例模式要保證一個類在整個系統運行期間&#xff0c;無論創建多少次該類的對象&#xff0c;始終只會有一個實例存在。就像操作系統中的任務管理器&#xff0c;無論何時何地調用它&#xff0c;都是同一個任務管理器在工作&#…

目標檢測YOLO實戰應用案例100講- 無人機平臺下露天目標檢測與計數

目錄 知識儲備 基于YOLOv8改進的無人機露天目標檢測與計數 一、環境配置與依賴安裝 二、核心代碼實現(帶詳細注釋) 1. 改進YOLOv8模型定義(添加注意力機制) 2. 無人機視角數據增強(drone_augment.py ) 3. 多目標跟蹤與計數(tracking_counter.py ) 4. 完整推理流…

【在Spring Boot中集成Redis】

在Spring Boot中集成Redis 依賴在application.yml中配置Redis服務地址創建Redis配置類緩存工具類使用 依賴 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency&…

計算機視覺——基于樹莓派的YOLO11模型優化與實時目標檢測、跟蹤及計數的實踐

概述 設想一下&#xff0c;你在多地擁有多個倉庫&#xff0c;要同時監控每個倉庫的實時狀況&#xff0c;這對于時間和精力而言&#xff0c;都構成了一項艱巨挑戰。從成本和可靠性的層面考量&#xff0c;大規模部署計算設備也并非可行之策。一方面&#xff0c;大量計算設備的購…

通信協議記錄儀-產品規格書

以下是為 ??通信協議記錄儀(ProtoLogger Pro)?? 的??詳細產品規格書??,覆蓋 ??技術細節、場景需求、競品差異化??,確保可作為產品開發、市場營銷及競品分析的核心依據。 ??通信協議記錄儀產品規格書?? ??產品名稱??:ProtoLogger Pro(中文名稱:蹲守…

python:sklearn 決策樹(Decision Tree)

5. 決策樹&#xff08;Decision Tree&#xff09; - 第5章 算法思想&#xff1a;基于信息增益&#xff08;ID3&#xff09;或基尼不純度&#xff08;CART&#xff09;遞歸劃分特征。 編寫 test_dtree_1.py 如下 # -*- coding: utf-8 -*- """ 5. 決策樹&…

【2-sat】2-sat算法內容及真題

A.2-sat簡介 2-sat算法可以求解給定推出關系下的一種合法情況。題目中重常常&#xff0c;給定一些布爾變量A、B、C、D…&#xff0c;再給出一系列形如 B ? A , C ? D B \longrightarrow A , C \longrightarrow \neg D B?A,C?D的推出關系&#xff0c;詢問使得所有推出關系…

【git】獲取特定分支和所有分支

1 特定分支 1.1 克隆指定分支&#xff08;默認只下載該分支&#xff09; git clone -b <分支名> --single-branch <倉庫URL> 示例&#xff08;克隆 某一個 分支&#xff09;&#xff1a; git clone -b xxxxxx --single-branch xxxxxxx -b &#xff1a;指定分支…