快速排序
快速排序(Java)
声明:此文章参考https://www.cnblogs.com/c4isr/p/4603980.html
一、原理(分治法)
- 先从数列中取出一个数作为基准数。
- 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 再对左右区间重复第二步,直到各区间只有一个数
二、时间复杂度
时间复杂度为O(nlog2n)~O(n2),空间复杂度O(log2n),此排序是不稳定的
三、代码实现
这里主要是有三种选取基准元的方法,不同选取基准元的方法有不同的用处,还有一些快速排序的优化算法,具体可以看文章开头的链接
- 固定基准元(基本的快速排序方法)
- 随机基准元(在待排序列是部分有序时,固定选取基准元使快排效率底下,要缓解这种情况,就引入了随机选取基准元)
- 三数取中基准元(虽然随机选取基准时,减少出现不好分割的几率,但是还是最坏情况下还是O(n^2),要缓解这种情况,就引入了三数取中选取基准)
1 /** 2 * 划分数组 3 * @param arr 数组 4 * @param low 起始位置 5 * @param high 结束位置 6 */ 7 public int partition(int arr[],int low,int high) { 8 //如果传入的参数不符合,结束 9 if (arr == null || low < 0 || high >= arr.length) { 10 new Exception("输出不合法!"); 11 } 12 //固定基准元为数组第一位 13 int point = arr[low]; 14 while (low < high) { 15 //如果从后往前与基准值比较,发现比基准值大,则下标减一 16 while (low < high && arr[high] >= point){ 17 high--; 18 } 19 //从后往前遍历完后,将该位置上的值赋给数组第一位(此时数组第一位已被复制到point中,可以认为现在它是空的) 20 arr[low] = arr[high]; 21 //同理,从前往后与基准值比较,比基准值小,则下标加一 22 while (low < high && arr[low] <= point){ 23 low++; 24 } 25 //同理,arr[high]上的值已经被上一个的arr[low]复制,所以也可以认为现在这个位置是空的,可以进行复制(挖空原理) 26 arr[high] = arr[low]; 27 } 28 //最后将基准值赋给最后一个空位置,补全数组 29 arr[low] = point; 30 return low; 31 } 32 33 /** 34 * 随机选取基准值 35 * 选取之后与数组首位进行交换,等到进行快速排序时,直接选取首位,就相当于随机选择了基准值 36 * @param arr 37 * @param left 38 * @param right 39 */ 40 public void referenceValue(int arr[],int left, int right) { 41 //随机选择一个基准,预防待排数据有序,选择的数据是left-right之间 42 Random random = new Random(); 43 int randomPoint = random.nextInt(right - left +1) + left; 44 System.out.println("选择的基准数下标为:" + randomPoint + "\n基准数为:" + arr[randomPoint]); 45 System.out.println("arr[" + randomPoint + "]与数组arr[" + left + "]进行交换"); 46 System.out.println("========================="); 47 swap(arr,randomPoint,left); 48 } 49 50 /** 51 * 三数取中基准元,并将确定好的基准元与数组首位交换 52 * @param arr 53 * @param low 54 * @param high 55 */ 56 public void partitionMedianOfThree(int[] arr, int low, int high){ 57 int mid = low + (high + -low) / 2; 58 if (arr[mid] > arr[high]) 59 { 60 swap(arr, mid, high); 61 } 62 if (arr[low] > arr[high]) 63 { 64 swap(arr, low, high); 65 } 66 //将中间大小的数与第一个数交换 67 if (arr[mid] > arr[low]) 68 { 69 swap(arr, mid, low); 70 } 71 } 72 73 /** 74 * 固定基准元排序 75 * @param arr 76 * @param left 77 * @param right 78 */ 79 public void sort(int[] arr, int left, int right) { 80 if (left < right) { 81 int boundary = partition(arr,left,right); 82 sort(arr, left, boundary - 1); 83 sort(arr, boundary + 1, right); 84 } 85 } 86 87 /** 88 * 随机基准元排序 89 * @param arr 90 * @param left 91 * @param right 92 */ 93 public void sortRandom(int[] arr, int left, int right) { 94 if (left < right) { 95 referenceValue(arr,left,right); 96 int boundary = partition(arr,left,right); 97 sort(arr, left, boundary - 1); 98 sort(arr, boundary + 1, right); 99 } 100 } 101 102 /** 103 * 三数取中基准元快速排序 104 * @param arr 105 * @param left 106 * @param right 107 */ 108 public void sortMedianOfThree(int []arr, int left, int right) { 109 if (left < right) { 110 partitionMedianOfThree(arr,left,right); 111 int boundary = partition(arr,left,right); 112 sort(arr, left, boundary - 1); 113 sort(arr, boundary + 1, right); 114 } 115 } 116 117 /** 118 * 交换函数 119 * @param arr 120 * @param left 121 * @param right 122 */ 123 public void swap(int arr[],int left,int right) { 124 int temp = arr[left]; 125 arr[left] = arr[right]; 126 arr[right] = temp; 127 } 128 129 130 @Test 131 public void quickSort(){ 132 int[] arr = new int[10]; 133 for (int i = 0; i < arr.length; i++) { 134 arr[i] = (int) (Math.random()*100); 135 } 136 System.out.println("------原始数据------\n"+ 137 Arrays.toString(arr)); 138 // sort(arr,0, arr.length - 1); 139 // sortRandom(arr,0,arr.length - 1); 140 sortMedianOfThree(arr,0,arr.length - 1); 141 System.out.println("------排序结果-------"); 142 System.out.println(Arrays.toString(arr)); 143 }