算法之快速排序(递归和非递归)
快速排序的两种实现方式.递归和非递归
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 }