常用排序算法及Java实现
排序算法,可以分为内部排序和外部排序两大种。这篇文章主要对内部排序进行介绍。内部排序又分为两类,基于比较的非线性时间类,和非比较的线性时间类。前一类又可以分为四种,交换排序(包括冒泡排序和快速排序),插入排序(包括简单插入排序和希尔排序),选择排序(包括简单选择排序和堆排序)以及归并排序;后者主要包含三种,计数排序,桶排序和基数排序。
总体来说,快排、堆排和归并排序是非线性时间中最快的三种。一般认为,快排的时间效率会比堆排更好。另一方面,快排和堆排都是不稳定的算法,只有归并排序、冒泡排序和插入排序是稳定的算法,因此Java中的sort算法在实现的时候,有一个阈值,大概是60左右。数组长度低于这个阈值的,直接使用插入排序;高于这个阈值的,如果元素是基本数据类型,救使用快排,如果是引用数据类型,就使用归并排序。而对于基于比较的排序算法,都很依赖于数据本身的分布——在数据均匀分布的情况下,效率可以很高。计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名;计数排序则要求对每一位使用的排序算法都是稳定的。
下面我们对这九种算法进行详细的介绍。为了方便,我们设定所有的排序都基于整形数组,需要按照从小到大的顺序进行排列。在这些排序算法中,有一些公用的操作,比如元素交换,元素打印,寻找最大值最小值等,为了代码的复用,我们定义了工具类Tools,首先给出Tools类的代码。
1 public class Tools { 2 public static void swap(int[] arr, int i, int j) { 3 int tmp = arr[i]; 4 arr[i] = arr[j]; 5 arr[j] = tmp; 6 } 7 8 public static void printArray(int[] arr) { 9 int i = 0; 10 System.out.print("["); 11 for (; i < arr.length - 1; i++) { 12 System.out.print(arr[i] + ","); 13 } 14 System.out.println(arr[i] + "]"); 15 } 16 17 public static int findMax(int[] arr) { 18 int max = Integer.MIN_VALUE; 19 for (int num : arr) { 20 max = Math.max(max, num); 21 } 22 return max; 23 } 24 25 public static int findMin(int[] arr) { 26 int min = Integer.MAX_VALUE; 27 for (int num : arr) { 28 min = Math.min(min, num); 29 } 30 return min; 31 } 32 }
1、交换算法
1.1 冒泡算法
整体思路:第i轮排序,从第0号元素到第(length-1-i)号元素,进行相邻元素的比较,并将较大的元素不断交换到后一位置。
特点:第i轮排序完成后,第i个最大值出现在下标为(length-1-i)的位置。
时间复杂度:最坏:O(n^2),平均:O(n^2),最好:O(n);
空间复杂度:O(1)
稳定性:稳定,但是当条件变为arr[j] >= arr[j + 1]时,就不稳定了
Java实现:
1 /** 2 * 3 * 4 * 以整型数组为例,通过冒泡排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:第i轮排序,从第0号元素到第(length-1-i)号元素,进行相邻元素的比较,并将较大的元素交换到后一位置。 6 * 特点:第i轮排序结束后,第i个最大值出现在下标为(length-1-i)的位置 7 * 时间复杂度:最坏:O(n^2),平均:O(n^2),最好:O(n); 8 * 空间复杂度:O(1) 9 * 稳定性:稳定,但是当条件变为arr[j] >= arr[j + 1]时,就不稳定了 10 */ 11 public class BubbleSort { 12 public static void bubbleSort(int[] arr) { 13 for (int i = 0; i < arr.length - 1; i++) { 14 for (int j = 0; j < arr.length - 1 - i; j++) { 15 if (arr[j] > arr[j + 1]) { 16 Tools.swap(arr, j, j + 1); 17 } 18 } 19 } 20 } 21 22 public static void main(String[] args) { 23 int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 24 System.out.println("before sorting:"); 25 Tools.printArray(arr); 26 bubbleSort(arr); 27 System.out.println("after sorting:"); 28 Tools.printArray(arr); 29 } 30 }
1.2 快速排序
整体思路:通过递归的方式,不断将数组分为两部分,主元左边的都比主元小,右边的都比主元大。特点:每一轮的排序结束后,数组中的某一部分就会成为有序的序列。
时间复杂度:最坏O(n^2),平均O(nlog2n),最好O(nlog2n)。
空间复杂度:O(nlog2n),主要是由于递归调用造成的栈内存的使用。
稳定性:不稳定。
在每一轮的排序过程中,注意首先从右往左进行查找;在跳出循环后,将low索引指向的位置作为主元交换的位置。
Java实现:
1 /** 2 * 3 * 4 * 以整型数组为例,通过快速排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:通过递归的方式,不断将数组分为两部分,主元左边的都比主元小,右边的都比主元大。 6 * 特点:每一轮的排序结束后,数组中的某一部分就会成为有序的序列。 7 * 时间复杂度:最坏O(n^2),平均O(nlog2n),最好O(nlog2n) 8 * 空间复杂度:O(nlog2n),主要是由于递归调用造成的栈内存的使用 9 * 稳定性:不稳定 10 * 11 * 在每一轮的排序过程中,注意首先从右往左进行查找;在跳出循环后,将low索引指向的位置作为主元交换的位置 12 * 13 */ 14 public class QuickSort { 15 public static void quickSort(int[] arr, int first, int last) { 16 if (last < first) { 17 return; 18 } 19 int low = first; 20 int high = last; 21 int pivot = arr[first]; 22 while (high > low) { 23 while (high > low && arr[high] >= pivot) 24 high--; 25 while (high > low && arr[low] <= pivot) 26 low++; 27 if (high > low) { 28 Tools.swap(arr, low, high); 29 } 30 } 31 32 Tools.swap(arr, first, low); 33 quickSort(arr, first, low - 1); 34 quickSort(arr, low + 1, last); 35 } 36 37 public static void quickSort(int[] arr) { 38 quickSort(arr, 0, arr.length - 1); 39 } 40 41 public static void main(String[] args) { 42 int[] arr = { 1, 5, 6, 8, 3, 2, 1, 9, 7, 2, 1, 1 }; 43 // int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 44 System.out.println("before sorting:"); 45 Tools.printArray(arr); 46 quickSort(arr); 47 System.out.println("after sorting:"); 48 Tools.printArray(arr); 49 } 50 }
2. 选择排序
2.1 简单选择排序
整体思路:第i轮排序,找到第i个最小值,将其交换到下标为i的位置。
特点:第i轮排序结束后,第i个最小值出现在下标为i的位置。
时间复杂度:三种情况都是O(n^2)。
空间复杂度:O(1)。
稳定性:不稳定
在每一轮选择最小元素的过程中,可以在每次符合条件时都进行换位,也可以将这一轮中最小值的索引记下来,这一轮结束时进行一次换位。这样减少了在堆内存中的操作,更加高效。
Java实现:
1 /** 2 * @author hr 3 * 4 * 以整型数组为例,通过选择排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:第i轮排序,找到第i个最小值,将其交换到下标为i的位置。 6 * 特点:第i轮排序结束后,第i个最小值出现在下标为i的位置 7 * 8 * 在每一轮选择最小元素的过程中,可以在每次符合条件时都进行换位,也可以将这一轮中最小值的 9 * 索引记下来,这一轮结束时进行一次换位。这样减少了在堆内存中的操作,更加高效。 10 * 时间复杂度:三种情况都是O(n^2) 11 * 空间复杂度:O(1) 12 * 稳定性:不稳定 13 * 14 */ 15 public class SelectionSort { 16 public static void selectionSort(int[] arr) { 17 for (int i = 0; i < arr.length - 1; i++) { 18 int minIndex = i; 19 for (int j = i + 1; j < arr.length; j++) { 20 if (arr[j] < arr[minIndex]) 21 minIndex = j; 22 } 23 if (minIndex != i) 24 Tools.swap(arr, i, minIndex); 25 } 26 } 27 28 public static void main(String[] args) { 29 int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 30 System.out.println("before sorting:"); 31 Tools.printArray(arr); 32 selectionSort(arr); 33 System.out.println("after sorting:"); 34 Tools.printArray(arr); 35 } 36 }
2.2 堆排序
整体思路:首先,将给定的数组建立起一个大顶堆,这也意味着找到了最大的元素;然后,将最大的元素换到堆的末尾(也就是数组的末尾),将剩下的元素重新建立起一个大顶堆,不断找到剩余元素中的最大值。
特点:第i轮排序结束后,第i个最大值出现在下标为length - i的位置 。
时间复杂度:三种情况都是O(nlog2n)。
空间复杂度:O(1)。
稳定性:不稳定。
在最开始建立大顶堆时,只需要遍历前半部分数组即可,初始的循环遍历条件设为(length - 1) / 2,直到0为止。随后每次找最大值,也是从后面的元素开始向上遍历。而对大顶堆进行调整的时候,则是从给定的元素开始不断向下进行调整。每次对堆进行调整的循环停止条件为:当前节点不存在左孩子节点,或者当前节点值已经是三个节点中的最大值了。
Java实现:
/** * @author hr * * 以整型数组为例,通过堆排序将数组中的元素按从小到大的顺序进行排列 * 思路:首先,将给定的数组建立起一个大顶堆,这也意味着找到了最大的元素;然后,将最大的元素换到堆的末尾 * (也就是数组的末尾),将剩下的元素重新建立起一个大顶堆,不断找到剩余元素中的最大值。 * 特点:第i轮排序结束后,第i个最大值出现在下标为length - i的位置 * * 在最开始建立大顶堆时,只需要遍历前半部分数组即可,初始的循环遍历条件设为(length - 1) / 2,直到0为止 * 随后每次找最大值,也是从后面的元素开始向上遍历。 * 而对大顶堆进行调整的时候,则是从给定的元素开始不断向下进行调整。 * 时间复杂度:三种情况都是O(nlog2n) * 空间复杂度:O(1) * 稳定性:不稳定 * */ public class HeapSort { private static void heapify(int[] arr, int index, int heapSize) { int left = 2 * index + 1; int right = 2 * index + 2; int largest = index; while (left < heapSize) { if (arr[left] > arr[largest]) largest = left; if (right < heapSize && arr[right] > arr[index]) largest = right; if (index != largest) { Tools.swap(arr, index, largest); index = largest; left = 2 * index + 1; right = 2 * index + 2; } else break; } } public static void buildHeap(int[] arr) { for (int i = (arr.length - 1) / 2; i >= 0; i--) { heapify(arr, i, arr.length); } } public static void heapSort(int[] arr) { buildHeap(arr); for (int i = arr.length - 1; i >= 0; i--) { Tools.swap(arr, 0, i); heapify(arr, 0, i); } } public static void main(String[] args) { int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; System.out.println("before sorting:"); Tools.printArray(arr); heapSort(arr); System.out.println("after sorting:"); Tools.printArray(arr); } }
3. 插入排序
3.1 简单插入排序
整体思路:
第i轮排序,是将第i号元素插入由0,1,2...(i-1)号元素组成的有序表中。
特点:第i轮排序结束后,由0,1,2...i号元素组成的序列是有序的。
时间复杂度:最坏(数组是反序的)O(n^2),平均O(n^2),最好(数组本身就是正序的)O(n)。
空间复杂度:O(1)。
稳定性:稳定。
由于第i个元素之前都是有序的,因此在插入第i个元素的时候,可以从前往后遍历,找到合适的位置就停止。
Java实现:
1 /** 2 * @author hr 3 * 4 * 以整型数组为例,通过插入排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:第i轮排序,是将第i号元素插入由0,1,2...(i-1)号元素组成的有序表中 6 * 特点:第i轮排序结束后,由0,1,2...i号元素组成的序列是有序的 7 * 时间复杂度:最坏(数组是反序的)O(n^2),平均O(n^2),最好(数组本身就是正序的)O(n) 8 * 空间复杂度:O(1) 9 * 稳定性:稳定 10 * 11 * 由于第i个元素之前都是有序的,因此在插入第i个元素的时候,可以从前往后遍历, 12 * 找到合适的位置就停止 13 */ 14 public class InsertionSort { 15 public static void insertionSort(int[] arr) { 16 for (int i = 1; i < arr.length; i++) { 17 int curNum = arr[i]; 18 int j; 19 for (j = i - 1; j >= 0 && arr[j] > curNum; j--) { 20 arr[j + 1] = arr[j]; 21 } 22 arr[j + 1] = curNum; 23 } 24 } 25 26 public static void main(String[] args) { 27 int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 28 System.out.println("before sorting:"); 29 Tools.printArray(arr); 30 insertionSort(arr); 31 System.out.println("after sorting:"); 32 Tools.printArray(arr); 33 } 34 }
3.2 希尔排序
整体思路:初始将数组均分为gap组,所有下标之差为gap的元素在同一组内,然后对每一组进行插入排序;最后不断调整gap的值进行循环,直到gap为0。
时间复杂度:最坏O(n^2),平均O(n^1.3),最好O(n)。
空间复杂度:O(1)。
稳定性:不稳定。
实际实现的时候,并不是一组插入排序结束之后再进行另外一组,而是每一组交叉进行。
Java实现:
1 /** 2 * @author hr 3 * 4 * 以整型数组为例,通过希尔排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:初始将数组均分为gap组,所有下标之差为gap的元素在同一组内,然后对每一组进行插入排序; 6 * 最后不断调整gap的值进行循环。 7 * 8 * 9 * 实际实现的时候,并不是一组插入排序结束之后再进行另外一组,而是每一组交叉进行 10 * 时间复杂度:最坏O(n^2),平均O(n^1.3),最好O(n) 11 * 空间复杂度:O(1) 12 * 稳定性:不稳定 13 * 14 */ 15 16 public class ShellSort { 17 public static void ShellSort(int[] arr) { 18 for (int gap = arr.length / 2; gap > 0; gap /= 2) { 19 for (int i = gap; i < arr.length; i++) { 20 for (int j = i - gap; j >= 0; j -= gap) { 21 if (arr[j] > arr[j + gap]) { 22 Tools.swap(arr, j, j + gap); 23 } 24 } 25 } 26 } 27 } 28 29 public static void main(String[] args) { 30 int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 31 System.out.println("before sorting:"); 32 Tools.printArray(arr); 33 ShellSort(arr); 34 System.out.println("after sorting:"); 35 Tools.printArray(arr); 36 } 37 }
4. 归并排序
整体思路:归并排序采用的是分治法。首先不断将数组分为左右两部分,直到每部分都只包含一个元素为止。然后对所有的子序列两两合并,最终得到有序序列。
时间复杂度:最坏O(nlog2n),平均O(nlog2n),最好O(nlog2n)。
空间复杂度:O(n)。
稳定性:稳定。
Java实现:
1 /** 2 * @author hr 3 * 4 * 以整型数组为例,通过归并排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:归并排序采用的是分治法。首先不断将数组分为左右两部分,直到每部分都只包含一个元素为止。 6 * 然后对所有的子序列两两合并,最终得到有序序列。 7 * 8 * 时间复杂度:最坏O(nlog2n),平均O(nlog2n),最好O(nlog2n) 9 * 空间复杂度:O(n) 10 * 稳定性:稳定 11 * 12 */ 13 public class MergeSort { 14 //将arr[first~mid]和arr[mid~last]合并到tmp中 15 public static void mergeArray(int[] arr, int first, int mid, int last) { 16 int[] tmp = new int[last - first + 1]; 17 int begin1 = first; 18 int begin2 = mid + 1; 19 int end1 = mid; 20 int end2 = last; 21 int k = 0; 22 while (begin1 <= end1 && begin2 <= end2) { 23 if (arr[begin1] < arr[begin2]) { 24 tmp[k++] = arr[begin1++]; 25 } else { 26 tmp[k++] = arr[begin2++]; 27 } 28 } 29 while (begin1 <= end1) { 30 tmp[k++] = arr[begin1++]; 31 } 32 while (begin2 <= end2) { 33 tmp[k++] = arr[begin2++]; 34 } 35 //将辅助数组tmp的数据写回arr 36 for (begin1 = 0; begin1 < k; begin1++) { 37 arr[first + begin1] = tmp[begin1]; 38 } 39 } 40 41 public static void mergeSort(int[] arr, int first, int last) { 42 if (last - first > 0) { 43 int mid = (last + first) / 2; 44 mergeSort(arr, first, mid); 45 mergeSort(arr, mid + 1, last); 46 mergeArray(arr, first, mid, last); 47 } 48 } 49 50 public static void mergeSort(int[] arr) { 51 mergeSort(arr, 0, arr.length - 1); 52 } 53 54 public static void main(String[] args) { 55 int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 56 System.out.println("before sorting:"); 57 Tools.printArray(arr); 58 mergeSort(arr); 59 System.out.println("after sorting:"); 60 Tools.printArray(arr); 61 } 62 }
5.计数排序
整体思路:统计出数组中每个元素出现的次数,然后将元素按顺序填入就可得到有序序列。
时间复杂度:三种情况都是O(n + k)。
空间复杂度:O(n + k),k代表数组的宽度。
稳定性:稳定。
在统计每个元素出现的次数时,首先找到数组的宽度(数组最大值和最小值之差再加一),这样,统计数组中的下标就和元素值联系在一起(相差为min)。得到统计值之后,统计数组中的下标可以找到原数组中对应的元素,统计数组的元素值代表原数组对应元素的出现次数
Java实现:
1 /** 2 * @author hr 3 * 4 * 以整型数组为例,通过计数排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:统计出数组中每个元素出现的次数,然后将元素按顺序填入就可得到有序序列 6 * 7 * 在统计每个元素出现的次数时,首先找到数组的宽度(数组最大值和最小值之差再加一), 8 * 这样,统计数组中的下标就和元素值联系在一起(相差为min)。得到统计值之后,统计 9 * 数组中的下标可以找到原数组中对应的元素,统计数组的元素值代表原数组对应元素的出现次数 10 * 11 * 时间复杂度:三种情况都是O(n + k) 12 * 空间复杂度:O(n + k),k代表数组的宽度 13 * 稳定性:稳定 14 * 15 */ 16 public class CountSort { 17 18 public static void countSort(int[] arr) { 19 int max = Tools.findMax(arr); 20 int min = Tools.findMin(arr); 21 int[] count = new int[max - min + 1]; 22 for (int num : arr) { 23 count[num - min]++; 24 } 25 int index = 0; 26 for (int i = 0; i < count.length; i++) { 27 while (count[i] != 0) { 28 arr[index++] = i + min; 29 count[i]--; 30 } 31 } 32 } 33 34 public static void main(String[] args) { 35 int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 36 System.out.println("before sorting:"); 37 Tools.printArray(arr); 38 countSort(arr); 39 System.out.println("after sorting:"); 40 Tools.printArray(arr); 41 } 42 }
6. 桶排序
整体思路:根据数组的宽度,生成数量合适的桶。遍历数组,将元素放入对应的桶中。然后对每个桶进行排序,这样,桶内和桶间就都是有序的了。
时间复杂度:最坏:O(n^2),平均:O(n + k),最好:O(n)。
空间复杂度:O(n + k),其中k为数组的宽度。
稳定性:稳定。
实现时,用list<list>代表一个桶,将桶的数量设置为(max - min) / arr.length + 1,这样,(num - min) / arr.length = i的元素就放在第i个桶中。桶内元素我们利用简单插入排序。
Java实现:
1 /** 2 * @author hr 3 * 4 * 以整型数组为例,通过桶排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:根据数组的宽度,生成数量合适的桶。遍历数组,将元素放入对应的桶中。然后对每个桶进行排序, 6 * 这样,桶内和桶间就都是有序的了。 7 * 8 * 实现时,用list<list>代表一个桶,将桶的数量设置为(max - min) / arr.length + 1,这样, 9 * (num - min) / arr.length = i的元素就放在第i个桶中。桶内元素我们利用简单插入排序。 10 * 11 * 时间复杂度:最坏:O(n^2),平均:O(n + k),最好:O(n); 12 * 空间复杂度:O(n + k),其中k为数组的宽度 13 * 稳定性:稳定 14 */ 15 public class BucketSort { 16 public static void insertionSort(ArrayList<Integer> bucket) { 17 for (int i = 1; i < bucket.size(); i++) { 18 int j; 19 int curNum = bucket.get(i); 20 for (j = i - 1; j >= 0 && bucket.get(j) > curNum; j--) { 21 22 bucket.set(j + 1, bucket.get(j)); 23 24 } 25 bucket.set(j + 1, curNum); 26 } 27 } 28 29 public static void bucketSort(int[] arr) { 30 int max = Integer.MIN_VALUE; 31 int min = Integer.MAX_VALUE; 32 max = Tools.findMax(arr); 33 min = Tools.findMin(arr); 34 int bucketNum = (max - min) / arr.length + 1; 35 ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(); 36 for (int i = 0; i < bucketNum; i++) { 37 buckets.add(new ArrayList<>()); 38 } 39 40 for (int num : arr) { 41 int index = (num - min) / arr.length; 42 buckets.get(index).add(num); 43 } 44 45 int index = 0; 46 for (int i = 0; i < buckets.size(); i++) { 47 insertionSort(buckets.get(i)); 48 for (int num : buckets.get(i)) { 49 arr[index++] = num; 50 } 51 } 52 } 53 54 public static void main(String[] args) { 55 int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 }; 56 System.out.println("before sorting:"); 57 Tools.printArray(arr); 58 bucketSort(arr); 59 System.out.println("after sorting:"); 60 Tools.printArray(arr); 61 } 62 }
7. 基数排序
整体思路:本质上和桶排序是一样的,只是这个桶是固定的10个。排序的过程,就是将所有元素,从个位开始,不断进行桶排序。当所有的数位都排序一遍之后,就得到了有序序列。
时间复杂度:三种情况都是O(n + k)。
空间复杂度:O(n + k),其中k为数组的宽度。
稳定性:稳定。
实现时,可以用list<list>代表一个基数的计数桶;也可以用一个和原数组等长的临时数组,和一个大小为10的计数数组来进行统计。但是用后者会在一次排序的过程中,遍历两遍数组。
Java实现:
1 /** 2 * @author hr 3 * 4 * 以整型数组为例,通过基数排序将数组中的元素按从小到大的顺序进行排列 5 * 思路:本质上和桶排序是一样的,只是这个桶是固定的10个。排序的过程,就是将所有元素,从个位开始, 6 * 不断进行桶排序。当所有的数位都排序一遍之后,就得到了有序序列。 7 * 8 * 实现时,可以用list<list>代表一个基数的计数桶;也可以用一个和原数组等长的临时数组, 9 * 和一个大小为10的计数数组来进行统计。但是用后者会在一次排序的过程中,遍历两遍数组 10 * 11 * 时间复杂度:三种情况都是O(n + k); 12 * 空间复杂度:O(n + k),其中k为数组的宽度 13 * 稳定性:稳定 14 */ 15 public class RadixSort { 16 public static void radixSort(int[] arr) { 17 ArrayList<ArrayList<Integer>> tmp = new ArrayList<>(); 18 for (int i = 0; i < 10; i++) { 19 tmp.add(new ArrayList<>()); 20 } 21 22 int maxNum = Tools.findMax(arr); 23 int maxLength = Integer.toString(maxNum).length(); 24 25 int radix = 1; 26 for (int i = 0; i < maxLength; i++) { 27 for (int k = 0; k < 10; k++) { 28 tmp.add(new ArrayList<>()); 29 } 30 31 for (int num : arr) { 32 int digit = (num / radix) % 10; 33 tmp.get(digit).add(num); 34 } 35 36 int index = 0; 37 for (int j = 0; j < tmp.size(); j++) { 38 for (int num : tmp.get(j)) { 39 arr[index++] = num; 40 } 41 } 42 43 radix *= 10; 44 tmp.clear(); 45 } 46 } 47 48 public static void main(String[] args) { 49 int[] arr = { 15, 6, 8, 3, 2, 1, 9, 7, 2 }; 50 System.out.println("before sorting:"); 51 Tools.printArray(arr); 52 radixSort(arr); 53 System.out.println("after sorting:"); 54 Tools.printArray(arr); 55 } 56 }