├── .idea ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── README.md ├── demoCode.iml └── src └── com └── aaja └── demo ├── basic ├── Lee01_BubbleSort.java ├── Lee02_SelectionSort.java ├── Lee03_InsertionSort.java ├── Lee04_ShellSort.java ├── Lee05_MergeSort.java ├── Lee06_QuickSort.java ├── Lee07_HeapSort.java ├── Lee08_CountingSort.java ├── Lee09_BucketSort.java ├── Lee10_RadixSort.java └── README.md └── leetcode └── Lee_315.java /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 1595382827101 72 | 78 | 79 | 1595397705677 80 | 85 | 86 | 1595425465714 87 | 92 | 93 | 1595431256735 94 | 99 | 100 | 1595431680502 101 | 106 | 107 | 1595467404502 108 | 113 | 114 | 1595467637556 115 | 120 | 121 | 1595473332732 122 | 127 | 128 | 1595477103002 129 | 134 | 135 | 1595477154236 136 | 141 | 142 | 1595477204103 143 | 148 | 149 | 1595477262849 150 | 155 | 156 | 1595477305822 157 | 162 | 163 | 1595477349383 164 | 169 | 170 | 1595481128451 171 | 176 | 177 | 1595481395402 178 | 183 | 184 | 1595481533038 185 | 190 | 193 | 194 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 |         The so-called sorting algorithm is to re-sort one or more sets of data according to a predetermined pattern through a specific algorithm factor. This new sequence follows certain rules and reflects certain laws. Therefore, the processed data is convenient for screening and calculation, which greatly improves the calculation efficiency. For sorting, we first require it to have a certain degree of stability, that is, when two identical elements appear in a sequence at the same time, after a certain sorting algorithm, the relative positions of the two before and after sorting will not change. In other words, even if there are two identical elements, they are different in the ordering process, and confusion is not allowed. 4 | 5 | ## sort 6 | 7 |         Sorting is an important operation in computer programming. Its function is to rearrange an arbitrary sequence of data elements (or records) into an ordered sequence of keywords. 8 | Sorting is to sort the elements in the set together in a certain order. Generally speaking, there are two sorts of ascending order and descending order. There are 8 basic sorts in the algorithm: 9 | 10 | - Bubble sorting; 11 | - Selection order; 12 | - Insertion sort; 13 | - Hill sorting; 14 | - Merge and sort; 15 | - Quick sort; 16 | - Cardinal number sorting; 17 | - Heap sorting; 18 | - Count and sort; 19 | - Bucket sorting. 20 | 21 | ## standard 22 | 23 |         Stability is a particularly important evaluation criterion. A stable algorithm will not change the relative order of the positions of the elements during the sorting process. On the contrary, an unstable sorting algorithm will often change this order, which we do not want to see. When we use the sorting algorithm or selecting the sorting algorithm, we hope that the order will not change and be more stable. Therefore, the stability of the sorting algorithm is a particularly important parameter measurement index basis. Just like space complexity and time complexity, sometimes it is even more important than time complexity and space complexity. Therefore, it is often possible to evaluate the quality of a sorting algorithm from the following aspects: 24 | - Time complexity: the measurement of time spent in the process from the initial state of the sequence to the transformation and shifting of the sorting algorithm to the final state of the sorted result. 25 | - Space complexity: It is the space overhead spent from the initial state of the sequence through the process of sorting shift transformation to the final state. 26 | - Usage scenarios: There are many sorting algorithms, and different kinds of sorting algorithms are suitable for different kinds of scenarios. Sometimes it is necessary to save space and not so much time requirement. On the contrary, sometimes it is hoped to consider more time and space requirements. Not so high, in short, you generally have to make a decision from one aspect. 27 | - Stability: Stability is a problem that must be considered regardless of time and space, and it is often a very important factor affecting choice. 28 | 29 | # Summary Target 30 | - Ten classic basic sorting algorithms 31 | - Leetcode writing record -------------------------------------------------------------------------------- /demoCode.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee01_BubbleSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | /** 8 | *

Title: Lee01_BubbleSort

9 | *

Description: 冒泡排序

10 | * 冒泡排序算法的原理: 11 | * 1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。 12 | * 2、对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 13 | * 3、针对所有的元素重复以上的步骤,除了最后一个。 14 | * 4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 15 | * 算法分析: 16 | * 时间复杂度: 17 | * 若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数 和记录移动次数 均达到最小值 18 | * 所以,冒泡排序最好的时间复杂度为O(n)。 19 | * 若初始文件是反序的,需要进行 趟排序。每趟排序要进行 次关键字的比较(1≤i≤n-1),且每次比较都必须移 20 | * 动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值 21 | * 冒泡排序的最坏时间复杂度为O(n²)。 22 | * 综上,因此冒泡排序总的平均时间复杂度为O(n²)。 23 | * 空间复杂度:O(1) 24 | * 稳定性:稳定 25 | * @author aaja 26 | * @date 2020/7/22 13:58 27 | */ 28 | public class Lee01_BubbleSort { 29 | 30 | public static int[] bubbleSort(int arr[]) { 31 | boolean flag; 32 | for(int i =0 ; iarr[j+1]) { 36 | flag = true; 37 | arr[j+1] = arr[j] ^ arr[j+1]; 38 | arr[j] = arr[j]^arr[j+1]; 39 | arr[j+1] = arr[j]^arr[j+1]; 40 | } 41 | } 42 | if(!flag) break; 43 | } 44 | return arr; 45 | } 46 | 47 | public static void main(String[] args) { 48 | int[] arr = new int[]{1, 34, 6, -3, 9, 13}; 49 | List resList = Arrays.stream(bubbleSort(arr)) 50 | .boxed() 51 | .collect(Collectors.toList()); 52 | System.out.println(resList); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee02_SelectionSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | /** 4 | *

Title: Lee02_SelectionSort

5 | *

Description: 选择排序

6 | * 7 | * ①基本思想:选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理: 8 | * 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素, 9 | * 然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 10 | * ②算法描述:(n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。) 11 | * 初始状态:无序区为R[1..n],有序区为空; 12 | * 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字 13 | * 最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个 14 | * 数减少1个的新无序区; 15 | * n-1趟结束,数组有序化了。 16 | * @author aaja 17 | * @date 2020/7/22 21:00 18 | */ 19 | public class Lee02_SelectionSort { 20 | public static int[] selectionSort(int[] array) { 21 | if (array.length == 0) 22 | return array; 23 | for (int i = 0; i < array.length; i++) { 24 | int minIndex = i; 25 | for (int j = i; j < array.length; j++) { 26 | if (array[j] < array[minIndex]) //找到最小的数 27 | minIndex = j; //将最小数的索引保存 28 | } 29 | int temp = array[minIndex]; 30 | array[minIndex] = array[i]; 31 | array[i] = temp; 32 | } 33 | return array; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee03_InsertionSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | /** 4 | *

Title: Lee03_InsertionSort

5 | *

Description: 插入排序

6 | * 7 | * ①基本思想:在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中, 8 | * 使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。 9 | * ②算法描述: 10 | * 从第一个元素开始,该元素可以认为已经被排序; 11 | * 取出下一个元素,在已经排序的元素序列中从后向前扫描; 12 | * 如果该元素(已排序)大于新元素,将该元素移到下一位置; 13 | * 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置; 14 | * 将新元素插入到该位置后; 15 | * 重复步骤2~5。 16 | * @author aaja 17 | * @date 2020/7/22 21:01 18 | */ 19 | public class Lee03_InsertionSort { 20 | 21 | public static int[] insertionSort(int[] array) { 22 | if (array.length == 0) 23 | return array; 24 | int current; 25 | for (int i = 0; i < array.length - 1; i++) { 26 | current = array[i + 1]; 27 | int preIndex = i; 28 | while (preIndex >= 0 && current < array[preIndex]) { 29 | array[preIndex + 1] = array[preIndex]; 30 | preIndex--; 31 | } 32 | array[preIndex + 1] = current; 33 | } 34 | return array; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee04_ShellSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | /** 4 | *

Title: Lee04_ShellSort

5 | *

Description: 希尔排序

6 | * 7 | * ①基本思想:希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序, 8 | * 同时该算法是冲破O(n2)的第一批算法之一。它与插入排序的不同之处在于,它会优先比较距离较远的元素。 9 | * ②算法描述: 10 | * 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1; 11 | * 按增量序列个数k,对序列进行k 趟排序; 12 | * 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子 13 | * 为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。 14 | * @author aaja 15 | * @date 2020/7/22 21:02 16 | */ 17 | public class Lee04_ShellSort { 18 | 19 | public static int[] ShellSort(int[] array) { 20 | int len = array.length; 21 | int temp, gap = len / 2; 22 | while (gap > 0) { 23 | for (int i = gap; i < len; i++) { 24 | temp = array[i]; 25 | int preIndex = i - gap; 26 | while (preIndex >= 0 && array[preIndex] > temp) { 27 | array[preIndex + gap] = array[preIndex]; 28 | preIndex -= gap; 29 | } 30 | array[preIndex + gap] = temp; 31 | } 32 | gap /= 2; 33 | } 34 | return array; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee05_MergeSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | *

Title: Lee05_MergeSort

7 | *

Description: 归并排序

8 | * ①基本思想: 9 | * 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常 10 | * 典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将 11 | * 两个有序表合并成一个有序表,称为2-路归并。 12 | * ②算法描述: 13 | * 把长度为n的输入序列分成两个长度为n/2的子序列; 14 | * 对这两个子序列分别采用归并排序; 15 | * 将两个排序好的子序列合并成一个最终的排序序列。 16 | * @author aaja 17 | * @date 2020/7/22 21:04 18 | */ 19 | public class Lee05_MergeSort { 20 | 21 | public static int[] MergeSort(int[] array) { 22 | if (array.length < 2) return array; 23 | int mid = array.length / 2; 24 | int[] left = Arrays.copyOfRange(array, 0, mid); 25 | int[] right = Arrays.copyOfRange(array, mid, array.length); 26 | return merge(MergeSort(left), MergeSort(right)); 27 | } 28 | 29 | /** 30 | * 归并排序——将两段排序好的数组结合成一个排序数组 31 | * 32 | * @param left 33 | * @param right 34 | * @return 35 | */ 36 | public static int[] merge(int[] left, int[] right) { 37 | int[] result = new int[left.length + right.length]; 38 | for (int index = 0, i = 0, j = 0; index < result.length; index++) { 39 | if (i >= left.length) 40 | result[index] = right[j++]; 41 | else if (j >= right.length) 42 | result[index] = left[i++]; 43 | else if (left[i] > right[j]) 44 | result[index] = right[j++]; 45 | else 46 | result[index] = left[i++]; 47 | } 48 | return result; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee06_QuickSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | /** 4 | *

Title: Lee06_QuickSort

5 | *

Description: 快速排序

6 | * 7 | * ①基本思想(分治): 8 | * 通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则 9 | * 可分别对这两部分记录继续进行排序,以达到整个序列有序。 10 | * ②算法描述:快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下: 11 | * 从数列中挑出一个元素,称为 “基准”(pivot); 12 | * 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同 13 | * 的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作; 14 | * 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。 15 | * @author aaja 16 | * @date 2020/7/22 21:05 17 | */ 18 | public class Lee06_QuickSort { 19 | 20 | public static int[] QuickSort(int[] array, int start, int end) { 21 | if (array.length < 1 || start < 0 || end >= array.length || start > end) return null; 22 | int smallIndex = partition(array, start, end); 23 | if (smallIndex > start) 24 | QuickSort(array, start, smallIndex - 1); 25 | if (smallIndex < end) 26 | QuickSort(array, smallIndex + 1, end); 27 | return array; 28 | } 29 | 30 | /** 31 | * 快速排序算法——partition 32 | * @param array 33 | * @param start 34 | * @param end 35 | * @return 36 | */ 37 | public static int partition(int[] array, int start, int end) { 38 | int pivot = (int) (start + Math.random() * (end - start + 1)); 39 | int smallIndex = start - 1; 40 | swap(array, pivot, end); 41 | for (int i = start; i <= end; i++) 42 | if (array[i] <= array[end]) { 43 | smallIndex++; 44 | if (i > smallIndex) 45 | swap(array, i, smallIndex); 46 | } 47 | return smallIndex; 48 | } 49 | 50 | /** 51 | * 交换数组内两个元素 52 | * @param array 53 | * @param i 54 | * @param j 55 | */ 56 | public static void swap(int[] array, int i, int j) { 57 | int temp = array[i]; 58 | array[i] = array[j]; 59 | array[j] = temp; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee07_HeapSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | import static com.aaja.demo.basic.Lee06_QuickSort.swap; 4 | 5 | /** 6 | *

Title: Lee07_HeapSort

7 | *

Description: 堆排序

8 | * 9 | * ①基本思想:堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构, 10 | * 并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 11 | * ②算法描述: 12 | * 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区; 13 | * 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn), 14 | * 且满足R[1,2…n-1]<=R[n]; 15 | * 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再 16 | * 次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此 17 | * 过程直到有序区的元素个数为n-1,则整个排序过程完成。 18 | * @author aaja 19 | * @date 2020/7/22 21:07 20 | */ 21 | public class Lee07_HeapSort { 22 | 23 | //声明全局变量,用于记录数组array的长度; 24 | static int len; 25 | 26 | /** 27 | * 堆排序算法 28 | * 29 | * @param array 30 | * @return 31 | */ 32 | public static int[] HeapSort(int[] array) { 33 | len = array.length; 34 | if (len < 1) return array; 35 | //1.构建一个最大堆 36 | buildMaxHeap(array); 37 | //2.循环将堆首位(最大值)与末位交换,然后在重新调整最大堆 38 | while (len > 0) { 39 | swap(array, 0, len - 1); 40 | len--; 41 | adjustHeap(array, 0); 42 | } 43 | return array; 44 | } 45 | 46 | /** 47 | * 建立最大堆 48 | * 49 | * @param array 50 | */ 51 | public static void buildMaxHeap(int[] array) { 52 | //从最后一个非叶子节点开始向上构造最大堆 53 | for (int i = (len/2 - 1); i >= 0; i--) { 54 | adjustHeap(array, i); 55 | } 56 | } 57 | 58 | /** 59 | * 调整使之成为最大堆 60 | * 61 | * @param array 62 | * @param i 63 | */ 64 | public static void adjustHeap(int[] array, int i) { 65 | int maxIndex = i; 66 | //如果有左子树,且左子树大于父节点,则将最大指针指向左子树 67 | if (i * 2 < len && array[i * 2] > array[maxIndex]) maxIndex = i * 2; 68 | //如果有右子树,且右子树大于父节点,则将最大指针指向右子树 69 | if (i * 2 + 1 < len && array[i * 2 + 1] > array[maxIndex]) maxIndex = i * 2 + 1; 70 | //如果父节点不是最大值,则将父节点与最大值交换,并且递归调整与父节点交换的位置。 71 | if (maxIndex != i) { 72 | swap(array, maxIndex, i); 73 | adjustHeap(array, maxIndex); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee08_CountingSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | *

Title: Lee08_CountingSort

7 | *

Description: 计数排序

8 | * 9 | * ①基本思想:计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 10 | * 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 11 | * ②算法描述: 12 | * 找出待排序的数组中最大和最小的元素; 13 | * 统计数组中每个值为i的元素出现的次数,存入数组C的第i项; 14 | * 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加); 15 | * 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。 16 | * @author aaja 17 | * @date 2020/7/22 21:11 18 | */ 19 | public class Lee08_CountingSort { 20 | 21 | /** 22 | * 计数排序 23 | * 24 | * @param array 25 | * @return 26 | */ 27 | public static int[] CountingSort(int[] array) { 28 | if (array.length == 0) return array; 29 | int bias, min = array[0], max = array[0]; 30 | for (int i = 1; i < array.length; i++) { 31 | if (array[i] > max) 32 | max = array[i]; 33 | if (array[i] < min) 34 | min = array[i]; 35 | } 36 | bias = 0 - min; 37 | int[] bucket = new int[max - min + 1]; 38 | Arrays.fill(bucket, 0); 39 | for (int i = 0; i < array.length; i++) { 40 | bucket[array[i] + bias]++; 41 | } 42 | int index = 0, i = 0; 43 | while (index < array.length) { 44 | if (bucket[i] != 0) { 45 | array[index] = i - bias; 46 | bucket[i]--; 47 | index++; 48 | } else 49 | i++; 50 | } 51 | return array; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee09_BucketSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | /** 7 | *

Title: Lee09_BucketSort

8 | *

Description: 桶排序

9 | * 10 | * ①基本思想: 11 | * 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。 12 | * 桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每 13 | * 个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。 14 | * ②算法描述: 15 | * 设置一个定量的数组当作空桶; 16 | * 遍历输入数据,并且把数据一个一个放到对应的桶里去; 17 | * 对每个不是空的桶进行排序; 18 | * 从不是空的桶里把排好序的数据拼接起来。 19 | * @author aaja 20 | * @date 2020/7/22 21:13 21 | */ 22 | public class Lee09_BucketSort { 23 | 24 | public static void bucketSort(int[] arr){ 25 | 26 | int max = Integer.MIN_VALUE; 27 | int min = Integer.MAX_VALUE; 28 | for(int i = 0; i < arr.length; i++){ 29 | max = Math.max(max, arr[i]); 30 | min = Math.min(min, arr[i]); 31 | } 32 | 33 | //桶数 34 | int bucketNum = (max - min) / arr.length + 1; 35 | ArrayList> bucketArr = new ArrayList<>(bucketNum); 36 | for(int i = 0; i < bucketNum; i++){ 37 | bucketArr.add(new ArrayList()); 38 | } 39 | //将每个元素放入桶 40 | for(int i = 0; i < arr.length; i++){ 41 | int num = (arr[i] - min) / (arr.length); 42 | bucketArr.get(num).add(arr[i]); 43 | } 44 | //对每个桶进行排序 45 | for(int i = 0; i < bucketArr.size(); i++){ 46 | Collections.sort(bucketArr.get(i)); 47 | } 48 | System.out.println(bucketArr.toString()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/Lee10_RadixSort.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.basic; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | 6 | /** 7 | *

Title: Lee10_RadixSort

8 | *

Description: 基数排序

9 | * 10 | * ①基本思想: 11 | * 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。 12 | * 有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高 13 | * 优先级高的在前,高优先级相同的低优先级高的在前。 14 | * ②算法描述: 15 | * 取得数组中的最大数,并取得位数; 16 | * arr为原始数组,从最低位开始取每个位组成radix数组; 17 | * 对radix进行计数排序(利用计数排序适用于小范围数的特点); 18 | * @author aaja 19 | * @date 2020/7/22 21:20 20 | */ 21 | public class Lee10_RadixSort { 22 | 23 | public int[] sort(int[] sourceArray) throws Exception { 24 | // 对 arr 进行拷贝,不改变参数内容 25 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 26 | 27 | int maxDigit = getMaxDigit(arr); 28 | return radixSort(arr, maxDigit); 29 | } 30 | 31 | /** 32 | * 获取最高位数 33 | */ 34 | private int getMaxDigit(int[] arr) { 35 | int maxValue = getMaxValue(arr); 36 | return getNumLenght(maxValue); 37 | } 38 | 39 | private int getMaxValue(int[] arr) { 40 | int maxValue = arr[0]; 41 | for (int value : arr) { 42 | if (maxValue < value) { 43 | maxValue = value; 44 | } 45 | } 46 | return maxValue; 47 | } 48 | 49 | protected int getNumLenght(long num) { 50 | if (num == 0) { 51 | return 1; 52 | } 53 | int lenght = 0; 54 | for (long temp = num; temp != 0; temp /= 10) { 55 | lenght++; 56 | } 57 | return lenght; 58 | } 59 | 60 | private int[] radixSort(int[] arr, int maxDigit) { 61 | int mod = 10; 62 | int dev = 1; 63 | 64 | for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { 65 | // 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10) 66 | int[][] counter = new int[mod * 2][0]; 67 | 68 | for (int j = 0; j < arr.length; j++) { 69 | int bucket = ((arr[j] % mod) / dev) + mod; 70 | counter[bucket] = arrayAppend(counter[bucket], arr[j]); 71 | } 72 | 73 | int pos = 0; 74 | for (int[] bucket : counter) { 75 | for (int value : bucket) { 76 | arr[pos++] = value; 77 | } 78 | } 79 | } 80 | return arr; 81 | } 82 | 83 | /** 84 | * 自动扩容,并保存数据 85 | * 86 | * @param arr 87 | * @param value 88 | */ 89 | private int[] arrayAppend(int[] arr, int value) { 90 | arr = Arrays.copyOf(arr, arr.length + 1); 91 | arr[arr.length - 1] = value; 92 | return arr; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/com/aaja/demo/basic/README.md: -------------------------------------------------------------------------------- 1 | # 10大经典排序算法对比 2 | 3 | - 线性对比 4 | 5 | ![](https://aaja.gitee.io/picture/demoCode/20200723001.png) 6 | 7 | - 区别 8 | 9 | ![](https://aaja.gitee.io/picture/demoCode/20200722002.png) 10 | 11 | # 01冒泡排序 12 | 13 | ![](https://aaja.gitee.io/picture/demoCode/20200722001.gif) 14 | 15 | # 02选择排序 16 | 17 | ![](https://aaja.gitee.io/picture/demoCode/20200722002.gif) 18 | 19 | # 03插入排序 20 | 21 | ![](https://aaja.gitee.io/picture/demoCode/20200722003.gif) 22 | 23 | # 04 **希尔排序** 24 | 25 | ![](https://aaja.gitee.io/picture/demoCode/20200722004.gif) 26 | 27 | # 05 归并排序 28 | 29 | ![](https://aaja.gitee.io/picture/demoCode/20200722005.gif) 30 | 31 | # 06 快速排序 32 | 33 | ![](https://aaja.gitee.io/picture/demoCode/20200722006.gif) 34 | 35 | # 07 堆排序 36 | 37 | ![](https://aaja.gitee.io/picture/demoCode/20200722007.gif) 38 | 39 | # 08 计数排序 40 | 41 | ![](https://aaja.gitee.io/picture/demoCode/20200722008.gif) 42 | 43 | # 09 桶排序 44 | 45 | ![](https://aaja.gitee.io/picture/demoCode/20200722009.gif) 46 | 47 | # 10 基数排序 48 | 49 | ![](https://aaja.gitee.io/picture/demoCode/20200722010.gif) -------------------------------------------------------------------------------- /src/com/aaja/demo/leetcode/Lee_315.java: -------------------------------------------------------------------------------- 1 | package com.aaja.demo.leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @title 计算右侧小于当前元素的个数 8 | * @description 给定一个整数数组 nums,按要求返回一个新数组 counts。 9 | * 数组 counts 有该性质: counts[i] 的值是  nums[i] 右 10 | * 侧小于 nums[i] 的元素的数量。 11 | * 12 | * @example 输入:[5,2,6,1] 13 | * 输出:[2,1,1,0] 14 | * @Explanation 5 的右侧有 2 个更小的元素 (2 和 1) 15 | * 2 的右侧仅有 1 个更小的元素 (1) 16 | * 6 的右侧有 1 个更小的元素 (1) 17 | * 1 的右侧有 0 个更小的元素 18 | * 19 | * @LeetCode 315 20 | * @author aaja 21 | * @date 2020/7/22 13:59 22 | */ 23 | public class Lee_315 { 24 | 25 | /** 26 | * v1.0 27 | * 看到题目第一眼想到的,然后提交不通过 28 | */ 29 | public static List countSmaller1(int[] nums) { 30 | List couns = new ArrayList(); 31 | for(int i= 0; i < nums.length; i++) { 32 | int j= 0; 33 | for(int k= i+1; k < nums.length; k++) { 34 | if(nums[k] < nums[i]) { 35 | j++; 36 | } 37 | } 38 | couns.add(j); 39 | } 40 | return couns; 41 | } 42 | 43 | /** 44 | * 大佬解法 45 | * @param nums 46 | * @return 47 | */ 48 | public List countSmaller(int[] nums) { 49 | List result = new ArrayList<>(); 50 | int len = nums.length; 51 | if (len == 0) return result; 52 | 53 | int[] temp = new int[len]; 54 | int[] res = new int[len]; 55 | int[] indexes = new int[len]; // 索引数组,作用:归并回去的时候,方便知道是哪个下标的元素 56 | 57 | for (int i = 0; i < len; i++) { 58 | indexes[i] = i; 59 | } 60 | mergeAndCountSmaller(nums, 0, len - 1, indexes, temp, res); 61 | 62 | for (int i = 0; i < len; i++) { // 把 int[] 转换成为 List,没有业务逻辑 63 | result.add(res[i]); 64 | } 65 | return result; 66 | } 67 | 68 | /** 69 | * 针对数组 nums 指定的区间 [left, right] 进行归并排序,在排序的过程中完成统计任务 70 | * 71 | * @param nums 72 | * @param left 73 | * @param right 74 | */ 75 | private void mergeAndCountSmaller(int[] nums, int left, int right, int[] indexes, int[] temp, int[] res) { 76 | if (left == right) { 77 | return; 78 | } 79 | int mid = left + (right - left) / 2; 80 | mergeAndCountSmaller(nums, left, mid, indexes, temp, res); 81 | mergeAndCountSmaller(nums, mid + 1, right, indexes, temp, res); 82 | 83 | // 归并排序的优化,如果索引数组有序,则不存在逆序关系,没有必要合并 84 | if (nums[indexes[mid]] <= nums[indexes[mid + 1]]) { 85 | return; 86 | } 87 | mergeOfTwoSortedArrAndCountSmaller(nums, left, mid, right, indexes, temp, res); 88 | } 89 | 90 | /** 91 | * [left, mid] 是排好序的,[mid + 1, right] 是排好序的 92 | * 93 | * @param nums 94 | * @param left 95 | * @param mid 96 | * @param right 97 | * @param indexes 98 | * @param temp 99 | * @param res 100 | */ 101 | private void mergeOfTwoSortedArrAndCountSmaller(int[] nums, int left, int mid, int right, int[] indexes, int[] temp, int[] res) { 102 | for (int i = left; i <= right; i++) { 103 | temp[i] = indexes[i]; 104 | } 105 | 106 | int i = left; 107 | int j = mid + 1; 108 | for (int k = left; k <= right; k++) { 109 | if (i > mid) { 110 | indexes[k] = temp[j]; 111 | j++; 112 | } else if (j > right) { 113 | indexes[k] = temp[i]; 114 | i++; 115 | res[indexes[k]] += (right - mid); 116 | } else if (nums[temp[i]] <= nums[temp[j]]) { 117 | // 注意:这里是 <= ,保证稳定性 118 | indexes[k] = temp[i]; 119 | i++; 120 | res[indexes[k]] += (j - mid - 1); 121 | } else { 122 | indexes[k] = temp[j]; 123 | j++; 124 | } 125 | } 126 | } 127 | 128 | public static void handle() { 129 | int[] nums = new int[] {5, 2, 6, 1}; 130 | System.out.println(countSmaller1(nums)); 131 | } 132 | 133 | /** 134 | * 单个Java方法不能超过65535字节 135 | * 单个Java文件常量个数上限是65536 136 | */ 137 | public static void handleResult() { 138 | int[] numx = new int[] {5183,2271,3067,539,8939,2999,9264,737,3974,5846,-210,9278,5800, 139 | 2675,6608,1133,-1,6018,9672,5179,9842,7424,-209,2988,2757,5984,1107,2644,-499, 140 | 7234,7539,6525,347,5718,-742,1797,5292,976,8752,8297,1312,3385,5924,2882,6091, 141 | -282,2595,96,1906,8014,7667,5895,7283,7974,-167,7068,3946,6223,189,1589,2058,9277, 142 | -302,8157,8256,5261,8067,1071,9470,2682,8197,5632,753,3179,8187,9042,8167,4657,7080, 143 | 7801,5627,7917,8085,928,-892,-427,3685,4676,2431,8064,8537,343,505,4352,2108,4399,66, 144 | 2086,1922,9126,9460,393,443,5689,7595,850,8493,2866,732,3738,7933,3666,2370,5804,4045, 145 | 7903,8009,5387,5542,7593,6862,1547,6934,-160,9693,4560,7429,9989,7232,-594,587,6476,9277, 146 | 4471,5979,6268,2419,6706,-727,1927,7361,9684,5519,2703,1723,5181,3545,4290,9421,4288,1656, 147 | 1541,9632,1448,-490,4747,5416,4139,-845,3834,3349,8594,7882,2279,7777,9369,9917,8167,6799}; 148 | System.out.println(countSmaller1(numx)); 149 | } 150 | 151 | public static void main(String[] args) { 152 | handle(); 153 | // handleResult(); 154 | } 155 | } 156 | --------------------------------------------------------------------------------