快速排序的兩種實現方式.遞歸和非遞歸
1 package com.ebiz.sort; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Arrays; 5 import java.util.Date; 6 import java.util.Stack; 7 8 /** 9 * @author YHj 10 * @create 2019-08-18 17:42 11 */ 12 public class Quick { 13 14 public static void main(String[] args) { 15 int[] arr = new int[8]; 16 for (int i = 0; i < 8; i++) { 17 arr[i] = (int) (Math.random() * 800000); 18 } 19 20 String s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); 21 System.out.println("排序前 = " + s); 22 23 quickSort(arr,0,arr.length-1); 24 25 26 String l = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); 27 System.out.println("排序后 = " + l); 28 } 29 30 /** 31 * 快速排序(遞歸) 32 * <p> 33 * ①. 從數列中挑出一個元素,稱為"基准"(pivot)。 34 * ②. 重新排序數列,所有比基准值小的元素擺放在基准前面,所有比基准值大的元素擺在基准后面(相同的數可以到任一邊)。在這個分區結束之后,該基准就處於數列的中間位置。這個稱為分區(partition)操作。 35 * ③. 遞歸地(recursively)把小於基准值元素的子數列和大於基准值元素的子數列排序。 36 * 37 * @param arr 待排序數組 38 * @param low 左邊界 39 * @param high 右邊界 40 */ 41 public static void quickSort(int[] arr, int low, int high) { 42 if (arr.length <= 0){ 43 return; 44 } 45 if (low >= high) { 46 return; 47 } 48 int left = low; 49 int right = high; 50 51 int temp = arr[left]; //挖坑1:保存基准的值 52 while (left < right) { 53 while (left < right && arr[right] >= temp) { //坑2:從后向前找到比基准小的元素,插入到基准位置坑1中 54 right--; 55 } 56 arr[left] = arr[right]; 57 while (left < right && arr[left] <= temp) { //坑3:從前往后找到比基准大的元素,放到剛才挖的坑2中 58 left++; 59 } 60 arr[right] = arr[left]; 61 } 62 arr[left] = temp; //基准值填補到坑3中,准備分治遞歸快排 63 System.out.println("Sorting: " + Arrays.toString(arr)); 64 quickSort(arr, low, left - 1); 65 quickSort(arr, left + 1, high); 66 } 67 /** 68 * 快速排序(非遞歸) 69 * 70 * ①. 從數列中挑出一個元素,稱為"基准"(pivot)。 71 * ②. 重新排序數列,所有比基准值小的元素擺放在基准前面,所有比基准值大的元素擺在基准后面(相同的數可以到任一邊)。在這個分區結束之后,該基准就處於數列的中間位置。這個稱為分區(partition)操作。 72 * ③. 把分區之后兩個區間的邊界(low和high)壓入棧保存,並循環①、②步驟 73 * @param arr 待排序數組 74 */ 75 public static void quickSortByStack(int[] arr){ 76 if(arr.length <= 0){ 77 return; 78 } 79 Stack<Integer> stack = new Stack<Integer>(); 80 81 //初始狀態的左右指針入棧 82 stack.push(0); 83 stack.push(arr.length - 1); 84 while(!stack.isEmpty()){ 85 int high = stack.pop(); //出棧進行划分 86 int low = stack.pop(); 87 88 int pivotIdx = partition(arr, low, high); 89 90 //保存中間變量 91 if(pivotIdx > low) { 92 stack.push(low); 93 stack.push(pivotIdx - 1); 94 } 95 if(pivotIdx < high && pivotIdx >= 0){ 96 stack.push(pivotIdx + 1); 97 stack.push(high); 98 } 99 } 100 } 101 102 private static int partition(int[] arr, int low, int high){ 103 if(arr.length <= 0) { 104 return -1; 105 } 106 if(low >= high) { 107 return -1; 108 } 109 int l = low; 110 int r = high; 111 112 int pivot = arr[l]; //挖坑1:保存基准的值 113 while(l < r){ 114 while(l < r && arr[r] >= pivot){ //坑2:從后向前找到比基准小的元素,插入到基准位置坑1中 115 r--; 116 } 117 arr[l] = arr[r]; 118 while(l < r && arr[l] <= pivot){ //坑3:從前往后找到比基准大的元素,放到剛才挖的坑2中 119 l++; 120 } 121 arr[r] = arr[l]; 122 } 123 arr[l] = pivot; //基准值填補到坑3中,准備分治遞歸快排 124 return l; 125 } 126 127 128 }