选择排序

先从0~N上找出最小的交换到第一位 再从1~N上找出最小的交换到第二位 ……

  1. public void selectionSort(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return;
  4. }
  5. for (int i = 0; i < arr.length - 1; i++) {
  6. int minIdx = i;
  7. for (int j = i + 1; j < arr.length; j++) {
  8. minIdx = arr[minIdx] > arr[j] ? j : minIdx;
  9. }
  10. swap(arr, i, minIdx);
  11. }
  12. }

冒泡排序

从第一个开始遇到后一个比自己小就与后一个交换位置

  1. public void bubbleSort(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return;
  4. }
  5. for (int i = arr.length - 1; i > 0; i--) {
  6. for (int j = 0; j < i; j++) {
  7. if (arr[j] > arr[j + 1]) {
  8. ArrayUtils.swap(arr, j, j + 1);
  9. }
  10. }
  11. }
  12. }

插入排序

从头开始,每往后移动一位,就往前(已经移动过的)看,如果有比之前的数小,就交换 做到0 - i上有序

  1. public void insertionSort(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return;
  4. }
  5. for (int i = 0; i < arr.length; i++) {
  6. for (int j = i; j > 0; j--) {
  7. if (arr[j] < arr[j - 1]) {
  8. ArrayUtils.swap(arr, j, j - 1);
  9. }
  10. }
  11. }
  12. }

归并排序

将整个数组分为两块儿 使其在左侧区域有序 使其在右侧区域有序 最后将两块儿区域进行合并,使得合并的区域有序(左右两个区域如果值相等,则先处理左侧区域)

  1. public void mergeSort(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return;
  4. }
  5. process(arr, 0, arr.length - 1);
  6. }
  7. private void process(int[] arr, int l, int r) {
  8. if (l >= r) {
  9. return;
  10. }
  11. int mid = l + ((r - l) >> 1);
  12. //让左侧范围(l - mid)上有序
  13. process(arr, l, mid);
  14. //让右侧范围(mid+1 - r)上有序
  15. process(arr, mid + 1, r);
  16. //合并左右区域,使其在范围(l - r)上有序
  17. merge(arr, l, mid, r);
  18. }
  19. private void merge(int[] arr, int l, int mid, int r) {
  20. int[] help = new int[r - l + 1];
  21. //help数组的下标索引
  22. int hIdx = 0;
  23. //左侧区域的起始位置(结束位置为mid)
  24. int idxL = l;
  25. //右侧区域的起始位置(结束位置为r)
  26. int idxR = mid + 1;
  27. while (idxL <= mid && idxR <= r) {
  28. help[hIdx++] = arr[idxL] <= arr[idxR] ? arr[idxL++] : arr[idxR++];
  29. }
  30. while (idxL <= mid) {
  31. help[hIdx++] = arr[idxL++];
  32. }
  33. while (idxR <= r) {
  34. help[hIdx++] = arr[idxR++];
  35. }
  36. //将有序数据刷回源数组
  37. for (int i = 0; i < help.length; i++) {
  38. arr[l++] = help[i];
  39. }
  40. }

给定一个数组arr,求数组小和

在一个数组中,一个数左边比它小的数的总和,叫该数的小和,所有数的小和累加起来,叫数组小和 例子: [1,3,4,2,5] 1左边比1小的数:没有 3左边比3小的数:1 4左边比4小的数:1、3 2左边比2小的数:1 5左边比5小的数:1、3、4、 2 所以数组的小和为1+1+3+1+1+3+4+2=16 给定一个数组arr,求数组小和

解题思路:
将左边有多少个数比我小,转换为右边有多少个数比我大 在归并排序merge方法的基础上, 当拷贝左组值是产生小和,拷贝右组值时不产生小和 当左组数和右组数相等时,先拷贝右组数

  1. public int smallSum(int[] arr) {
  2. if (arr == null) {
  3. return 0;
  4. }
  5. return process(arr, 0, arr.length - 1);
  6. }
  7. private int process(int[] arr, int l, int r) {
  8. if (l >= r) {
  9. return 0;
  10. }
  11. int mid = l + ((r - l) >> 1);
  12. int leftMinSum = process(arr, l, mid);
  13. int rightMinSum = process(arr, mid + 1, r);
  14. int currMinSum = merge(arr, l, mid, r);
  15. return leftMinSum + rightMinSum + currMinSum;
  16. }
  17. private int merge(int[] arr, int l, int mid, int r) {
  18. int[] help = new int[r - l + 1];
  19. int idx = 0;
  20. int lIdx = l;
  21. int rIdx = mid + 1;
  22. int minSum = 0;
  23. while (lIdx <= mid && rIdx <= r) {
  24. //拷贝左组产生小和
  25. minSum += arr[lIdx] < arr[rIdx] ? arr[lIdx] * (r - rIdx + 1) : 0;
  26. //相等时先拷贝右组
  27. help[idx++] = arr[lIdx] < arr[rIdx] ? arr[lIdx++] : arr[rIdx++];
  28. }
  29. while (lIdx <= mid) {
  30. help[idx++] = arr[lIdx++];
  31. }
  32. while (rIdx <= r) {
  33. help[idx++] = arr[rIdx++];
  34. }
  35. for (int i = 0; i < help.length; i++) {
  36. arr[l++] = help[i];
  37. }
  38. return minSum;
  39. }

给定一个数组arr,求数组的降序对总数量

在一个数组中,任何一个前面的数a,和任何一个后面的数b,如果(a,b)是降序的,就称为降序对

解题思路:
将右边有多少个数比我小,转换为左边有多少个数比我大 在归并排序merge方法的基础上, 当拷贝右组值是产生逆序对,拷贝左组值时不产生逆序对 当左组数和右组数相等时,先拷贝左组数

  1. public int reverPairNumber(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return 0;
  4. }
  5. return process(arr, 0, arr.length - 1);
  6. }
  7. private int process(int[] arr, int l, int r) {
  8. if (l >= r) {
  9. return 0;
  10. }
  11. int mid = l + ((r - l) >> 1);
  12. int lCount = process(arr, l, mid);
  13. int rCount = process(arr, mid + 1, r);
  14. int currCount = merge(arr, l, mid, r);
  15. return lCount + rCount + currCount;
  16. }
  17. private int merge(int[] arr, int l, int mid, int r) {
  18. int[] help = new int[r - l + 1];
  19. int idx = 0;
  20. int lIdx = l;
  21. int rIdx = mid + 1;
  22. int count = 0;
  23. while (lIdx <= mid && rIdx <= r) {
  24. //当移动右组数据时产生逆序对
  25. count += arr[lIdx] > arr[rIdx] ? (mid - lIdx + 1) : 0;
  26. //当左组和右组数据相等时先移动左组
  27. help[idx++] = arr[lIdx] <= arr[rIdx] ? arr[lIdx++] : arr[rIdx++];
  28. }
  29. while (lIdx <= mid) {
  30. help[idx++] = arr[lIdx++];
  31. }
  32. while (rIdx <= r) {
  33. help[idx++] = arr[rIdx++];
  34. }
  35. for (int i = 0; i < help.length; i++) {
  36. arr[l++] = help[i];
  37. }
  38. return count;
  39. }

在一个数组中,对于任何一个数num,求有多少个(后面的数*2)依然<num,返回总个数

比如:[3,1,7,0,2] 3的后面有:1,0 1的后面有:0 7的后面有:0,2 0的后面没有 2的后面没有 所以总共有5个

解题思路: 原有的归并排序不改变 在merge之前,先通过滑动索引计算右边有多少个数*2小于左边的数

  1. public int reversePairs(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return 0;
  4. }
  5. return process(arr, 0, arr.length - 1);
  6. }
  7. private int process(int[] arr, int l, int r) {
  8. if (l >= r) {
  9. return 0;
  10. }
  11. int mid = l + ((r - l) >> 1);
  12. int lCount = process(arr, l, mid);
  13. int rCount = process(arr, mid + 1, r);
  14. int currCount = merge(arr, l, mid, r);
  15. return lCount + rCount + currCount;
  16. }
  17. private int merge(int[] arr, int l, int mid, int r) {
  18. int count = 0;
  19. // [L....M] [M+1....R]
  20. // 目前囊括进来的数,是从[M+1, windowR)
  21. int windowR = mid + 1;
  22. for (int i = l; i <= mid; i++) {
  23. while (windowR <= r && (long) arr[i] > (long) arr[windowR] * 2) {
  24. windowR++;
  25. }
  26. count += windowR - mid - 1;
  27. }
  28. int[] help = new int[r - l + 1];
  29. int idx = 0;
  30. int lIdx = l;
  31. int rIdx = mid + 1;
  32. while (lIdx <= mid && rIdx <= r) {
  33. help[idx++] = arr[lIdx] <= arr[rIdx] ? arr[lIdx++] : arr[rIdx++];
  34. }
  35. while (lIdx <= mid) {
  36. help[idx++] = arr[lIdx++];
  37. }
  38. while (rIdx <= r) {
  39. help[idx++] = arr[rIdx++];
  40. }
  41. for (int i = 0; i < help.length; i++) {
  42. arr[l++] = help[i];
  43. }
  44. return count;
  45. }

给定一个数组arr,两个整数lower和upper,返回arr中有多少个子数组的累加和在[lower,upper]范围上

leetcode:https://leetcode-cn.com/problems/count-of-range-sum/ 1)利用前缀和 2)原数组[lower,upper]这个问题 转换为 在前缀和数组中求新指标问题,前缀和数组中每个数X新指标为[x-upper,x-lower] 3)前缀数组的每一个x,在x之前有多少个数是在新指标[x-upper,x-lower]上

  1. public int countRangeSum(int[] arr, int lower, int upper) {
  2. long[] sum = new long[arr.length];
  3. sum[0] = arr[0];
  4. //求前缀和
  5. for (int i = 1; i < arr.length; i++) {
  6. sum[i] = sum[i - 1] + arr[i];
  7. }
  8. return process(sum, 0, sum.length - 1, lower, upper);
  9. }
  10. private int process(long[] arr, int l, int r, long lower, long upper) {
  11. if (l == r) {
  12. //arr[l] 表示区间[0,l]的区间和
  13. return arr[l] >= lower && arr[l] <= upper ? 1 : 0;
  14. }
  15. int mid = l + ((r - l) >> 1);
  16. int lCount = process(arr, l, mid, lower, upper);
  17. int rCount = process(arr, mid + 1, r, lower, upper);
  18. int mergeCount = merge(arr, l, mid, r, lower, upper);
  19. return lCount + rCount + mergeCount;
  20. }
  21. private int merge(long[] arr, int l, int mid, int r, long lower, long upper) {
  22. int mergeCount = 0;
  23. int windowL = l;
  24. int windowR = l;
  25. //将问题转换为针对右组任意数x,左组中有多少个数在区间[x-upper,x-lower]上
  26. //指针不回退,时间复杂度O(N)
  27. for (int i = mid + 1; i <= r; i++) {
  28. long min = arr[i] - upper;
  29. long max = arr[i] - lower;
  30. while (windowL <= mid && arr[windowL] < min) {
  31. windowL++;
  32. }
  33. while (windowR <= mid && arr[windowR] <= max) {
  34. windowR++;
  35. }
  36. mergeCount += windowR - windowL;
  37. }
  38. long[] help = new long[r - l + 1];
  39. int idx = 0;
  40. int lIdx = l;
  41. int rIdx = mid + 1;
  42. while (lIdx <= mid && rIdx <= r) {
  43. help[idx++] = arr[lIdx] <= arr[rIdx] ? arr[lIdx++] : arr[rIdx++];
  44. }
  45. while (lIdx <= mid) {
  46. help[idx++] = arr[lIdx++];
  47. }
  48. while (rIdx <= r) {
  49. help[idx++] = arr[rIdx++];
  50. }
  51. for (int i = 0; i < help.length; i++) {
  52. arr[l++] = help[i];
  53. }
  54. return mergeCount;
  55. }

荷兰国旗问题引出快排

给定一个数组,小于数组最后一个数的值放左边,等于数组最后一个数的值放中间,大于数组最后一个数的值放右边

  1. public int[] partition(int[] arr) {
  2. return process(arr, 0, arr.length - 1);
  3. }
  4. public int[] process(int[] arr, int l, int r) {
  5. if (l > r) {
  6. return new int[]{-1, -1};
  7. }
  8. int idx = l;
  9. int lessIdx = l - 1;
  10. int ratherThanIdx = r;
  11. while (idx < ratherThanIdx) {
  12. if (arr[idx] == arr[r]) {
  13. idx++;
  14. } else if (arr[idx] < arr[r]) {
  15. swap(arr, idx++, ++lessIdx);
  16. } else {
  17. swap(arr, idx, --ratherThanIdx);
  18. }
  19. }
  20. swap(arr, ratherThanIdx, r);
  21. return new int[]{lessIdx + 1, ratherThanIdx};
  22. }

快排(递归版本)

时间复杂度最好:O(N*logN),最差:O(N2) 额外空间复杂度最好:O(logN),最差:O(N)

  1. public void quickSort(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return;
  4. }
  5. partition(arr, 0, arr.length - 1);
  6. }
  7. public void partition(int[] arr, int l, int r) {
  8. if (l >= r) {
  9. return;
  10. }
  11. //随机一个数与范围上的最后一个数交换
  12. int randomIdx = (int) (Math.random() * (r - l + 1)) + l;
  13. swap(arr, randomIdx, r);
  14. int[] process = process(arr, l, r);
  15. partition(arr, l, process[0] - 1);
  16. partition(arr, process[1] + 1, r);
  17. }
  18. public int[] process(int[] arr, int l, int r) {
  19. if (l > r) {
  20. return new int[]{-1, -1};
  21. }
  22. if (l == r) {
  23. return new int[]{l, r};
  24. }
  25. int idx = l;
  26. //小于区域
  27. int lessIdx = l - 1;
  28. //大于区域
  29. int ratherThanIdx = r;
  30. while (idx < ratherThanIdx) {
  31. if (arr[idx] == arr[r]) {
  32. idx++;
  33. } else if (arr[idx] < arr[r]) {
  34. swap(arr, idx++, ++lessIdx);
  35. } else {
  36. swap(arr, idx, --ratherThanIdx);
  37. }
  38. }
  39. swap(arr, ratherThanIdx, r);
  40. return new int[]{lessIdx + 1, ratherThanIdx};
  41. }

快排(栈实现版本)

  1. private static class Op {
  2. private int l;
  3. private int r;
  4. public Op(int l, int r) {
  5. this.l = l;
  6. this.r = r;
  7. }
  8. }
  9. public void quickSort2(int[] arr) {
  10. if (arr == null || arr.length < 2) {
  11. return;
  12. }
  13. Stack<Op> stack = new Stack<>();
  14. int random = (int) (Math.random() * (arr.length));
  15. swap(arr, random, arr.length - 1);
  16. int[] partition = partition(arr, 0, arr.length - 1);
  17. stack.push(new Op(0, partition[0] - 1));
  18. stack.push(new Op(partition[1] + 1, arr.length - 1));
  19. while (!stack.isEmpty()) {
  20. Op op = stack.pop();
  21. if (op.l < op.r) {
  22. random = op.l + (int) (Math.random() * (op.r - op.l + 1));
  23. swap(arr, random, op.r);
  24. partition = partition(arr, op.l, op.r);
  25. stack.push(new Op(op.l, partition[0] - 1));
  26. stack.push(new Op(partition[1] + 1, op.r));
  27. }
  28. }
  29. }
  30. private int[] partition(int[] arr, int l, int r) {
  31. if (l > r) {
  32. return new int[]{-1, -1};
  33. }
  34. if (l == r) {
  35. return new int[]{l, r};
  36. }
  37. int lIdx = l - 1;
  38. int rIdx = r;
  39. int idx = l;
  40. while (idx < rIdx) {
  41. if (arr[idx] < arr[r]) {
  42. swap(arr, idx++, ++lIdx);
  43. } else if (arr[idx] > arr[r]) {
  44. swap(arr, idx, --rIdx);
  45. } else {
  46. idx++;
  47. }
  48. }
  49. swap(arr, rIdx, r);
  50. return new int[]{lIdx + 1, rIdx};
  51. }
  52. private void swap(int[] arr, int i, int j) {
  53. int temp = arr[i];
  54. arr[i] = arr[j];
  55. arr[j] = temp;
  56. }

快排(队列实现版本)

  1. private static class Op {
  2. private int l;
  3. private int r;
  4. public Op(int l, int r) {
  5. this.l = l;
  6. this.r = r;
  7. }
  8. }
  9. public static void quickSort3(int[] arr) {
  10. if (arr == null || arr.length < 2) {
  11. return;
  12. }
  13. Queue<Op> queue = new LinkedList<>();
  14. int random = (int) (Math.random() * (arr.length));
  15. swap(arr, random, arr.length - 1);
  16. int[] partition = partition(arr, 0, arr.length - 1);
  17. queue.offer(new Op(0, partition[0] - 1));
  18. queue.offer(new Op(partition[1] + 1, arr.length - 1));
  19. while (!queue.isEmpty()) {
  20. Op op = queue.poll();
  21. if (op.l < op.r) {
  22. random = op.l + (int) (Math.random() * (op.r - op.l + 1));
  23. swap(arr, random, op.r);
  24. partition = partition(arr, op.l, op.r);
  25. queue.offer(new Op(op.l, partition[0] - 1));
  26. queue.offer(new Op(partition[1] + 1, op.r));
  27. }
  28. }
  29. }
  30. private int[] partition(int[] arr, int l, int r) {
  31. if (l > r) {
  32. return new int[]{-1, -1};
  33. }
  34. if (l == r) {
  35. return new int[]{l, r};
  36. }
  37. int lIdx = l - 1;
  38. int rIdx = r;
  39. int idx = l;
  40. while (idx < rIdx) {
  41. if (arr[idx] < arr[r]) {
  42. swap(arr, idx++, ++lIdx);
  43. } else if (arr[idx] > arr[r]) {
  44. swap(arr, idx, --rIdx);
  45. } else {
  46. idx++;
  47. }
  48. }
  49. swap(arr, rIdx, r);
  50. return new int[]{lIdx + 1, rIdx};
  51. }
  52. private void swap(int[] arr, int i, int j) {
  53. int temp = arr[i];
  54. arr[i] = arr[j];
  55. arr[j] = temp;
  56. }

堆排序

  1. // 堆排序额外空间复杂度O(1)
  2. public static void heapSort(int[] arr) {
  3. if (arr == null || arr.length < 2) {
  4. return;
  5. }
  6. // O(N*logN)
  7. // for (int i = 0; i < arr.length; i++) { // O(N)
  8. // heapInsert(arr, i); // O(logN)
  9. // }
  10. // O(N)
  11. for (int i = arr.length - 1; i >= 0; i--) {
  12. heapify(arr, i, arr.length);
  13. }
  14. int heapSize = arr.length;
  15. // O(N*logN)
  16. while (heapSize > 0) { // O(N)
  17. swap(arr, 0, --heapSize); // O(1)
  18. heapify(arr, 0, heapSize); // O(logN)
  19. }
  20. }
  21. // arr[index]刚来的数,往上
  22. public void heapInsert(int[] arr, int index) {
  23. while (arr[index] > arr[(index - 1) / 2]) {
  24. swap(arr, index, (index - 1) / 2);
  25. index = (index - 1) / 2;
  26. }
  27. }
  28. // arr[index]位置的数,能否往下移动
  29. public void heapify(int[] arr, int index, int heapSize) {
  30. int left = index * 2 + 1; // 左孩子的下标
  31. while (left < heapSize) { // 下方还有孩子的时候
  32. // 两个孩子中,谁的值大,把下标给largest
  33. // 1)只有左孩子,left -> largest
  34. // 2) 同时有左孩子和右孩子,右孩子的值<= 左孩子的值,left -> largest
  35. // 3) 同时有左孩子和右孩子并且右孩子的值> 左孩子的值, right -> largest
  36. int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
  37. // 父和较大的孩子之间,谁的值大,把下标给largest
  38. largest = arr[largest] > arr[index] ? largest : index;
  39. if (largest == index) {
  40. break;
  41. }
  42. swap(arr, largest, index);
  43. index = largest;
  44. left = index * 2 + 1;
  45. }
  46. }
  47. public void swap(int[] arr, int i, int j) {
  48. int tmp = arr[i];
  49. arr[i] = arr[j];
  50. arr[j] = tmp;
  51. }

已知一个几乎有序的数组,请选择一个合适的排序策略,对这个数组进行排序

几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离一定不超过k,k相对于数组长度来说是比较小的

解题思路:时间复杂度O(N*logk) 建立一个大小为k+1 的小根堆,并将堆填充满 然后依次弹出一个再增加一个 没有多余的数添加后依次弹出堆里的数

给定很多线段,每个线段都有两个数[start, end],表示线段开始位置和结束位置,左右都是闭区间,返回线段最多重合区域中,包含了几条线段

规定: 1)线段的开始和结束位置一定都是整数值 2)线段重合区域的长度必须>=1

解题思路:

  1. 方案一
    • 找出所有线段中开始位置的最小值,结束位置的最大值
    • 从最小值开始依次遍历到最大值,将当前数加0.5,再依次看所有线段有多少经过该点
    • 记录经过点最大的次数就是答案
  2. 方案二
    • 将线段开始位置进行升序排列
    • 准备小根堆,遍历排完序的所有线段
    • 将堆中小于等于当前线段开始位置的数从堆中全部弹出
    • 将当前线段结束位置加入堆中
    • 此时堆中的元素个数就是与当前线段重合的线段数
  1. public int maxCover(int[][] m) {
  2. Line[] lines = new Line[m.length];
  3. for (int i = 0; i < m.length; i++) {
  4. lines[i] = new Line(m[i][0], m[i][1]);
  5. }
  6. //先按照每条线段的开始位置进行升序排序
  7. Arrays.sort(lines, new StartComparator());
  8. // 小根堆,每一条线段的结尾数值,使用默认的
  9. PriorityQueue<Integer> heap = new PriorityQueue<>();
  10. int max = 0;
  11. //小于等于线段开始位置的数都从堆中弹出,最后将自己结束位置加入堆
  12. for (int i = 0; i < lines.length; i++) {
  13. // lines[i] -> cur 在黑盒中,把<=cur.start 东西都弹出
  14. while (!heap.isEmpty() && heap.peek() <= lines[i].start) {
  15. heap.poll();
  16. }
  17. heap.add(lines[i].end);
  18. //此时堆中数据的多少就代表该线段与多少线段重合
  19. max = Math.max(max, heap.size());
  20. }
  21. return max;
  22. }
  23. public class Line {
  24. public int start;
  25. public int end;
  26. public Line(int s, int e) {
  27. start = s;
  28. end = e;
  29. }
  30. }
  31. public class StartComparator implements Comparator<Line> {
  32. @Override
  33. public int compare(Line o1, Line o2) {
  34. return o1.start - o2.start;
  35. }
  36. }

桶排序(计数排序)

一般要求样本是整数,且范围比较窄; 要求有改变,则改动很大

  1. // only for 0~200 value
  2. public static void countSort(int[] arr) {
  3. if (arr == null || arr.length < 2) {
  4. return;
  5. }
  6. int max = Integer.MIN_VALUE;
  7. for (int i = 0; i < arr.length; i++) {
  8. max = Math.max(max, arr[i]);
  9. }
  10. int[] bucket = new int[max + 1];
  11. for (int i = 0; i < arr.length; i++) {
  12. bucket[arr[i]]++;
  13. }
  14. int i = 0;
  15. for (int j = 0; j < bucket.length; j++) {
  16. while (bucket[j]-- > 0) {
  17. arr[i++] = j;
  18. }
  19. }
  20. }

基数排序

一般要求样本是10进制的正整数 要求有改变,则改动很大 步骤:

  1. 找出数组中最大的元素,并计算有多少位;如{12, 3, 45, 103, 265},最大值为265,最大位数3位
  2. 准备10个桶0-9,然后遍历源数组,并取出元素个位数字,然后将数据放入个位数字对应的桶中;如12,个位数为2,则12放入2号桶
  3. 将所有元素都放入桶之后,从0-9遍历10个桶,从每个桶中取出第二步放进去的数据(先进先出)
  4. 然后使用相同的方法(重复2、3步)处理十位、百位、千位……直到处理完最大位数,如果一个数在当前处理的位上没值,则记为0
  1. // only for no-negative value
  2. public static void radixSort(int[] arr) {
  3. if (arr == null || arr.length < 2) {
  4. return;
  5. }
  6. radixSort(arr, 0, arr.length - 1, maxbits(arr));
  7. }
  8. public static int maxbits(int[] arr) {
  9. int max = Integer.MIN_VALUE;
  10. for (int i = 0; i < arr.length; i++) {
  11. max = Math.max(max, arr[i]);
  12. }
  13. int res = 0;
  14. while (max != 0) {
  15. res++;
  16. max /= 10;
  17. }
  18. return res;
  19. }
  20. // arr[L..R]排序 , 最大值的十进制位数digit
  21. public static void radixSort(int[] arr, int L, int R, int digit) {
  22. final int radix = 10;
  23. int i = 0, j = 0;
  24. // 有多少个数准备多少个辅助空间
  25. int[] help = new int[R - L + 1];
  26. for (int d = 1; d <= digit; d++) { // 有多少位就进出几次
  27. // 10个空间
  28. // count[0] 当前位(d位)是0的数字有多少个
  29. // count[1] 当前位(d位)是(0和1)的数字有多少个
  30. // count[2] 当前位(d位)是(0、1和2)的数字有多少个
  31. // count[i] 当前位(d位)是(0~i)的数字有多少个
  32. int[] count = new int[radix]; // count[0..9]
  33. for (i = L; i <= R; i++) {
  34. // 103 1 3
  35. // 209 1 9
  36. j = getDigit(arr[i], d);
  37. count[j]++;
  38. }
  39. for (i = 1; i < radix; i++) {
  40. count[i] = count[i] + count[i - 1];
  41. }
  42. for (i = R; i >= L; i--) {
  43. j = getDigit(arr[i], d);
  44. help[count[j] - 1] = arr[i];
  45. count[j]--;
  46. }
  47. for (i = L, j = 0; i <= R; i++, j++) {
  48. arr[i] = help[j];
  49. }
  50. }
  51. }
  52. public static int getDigit(int x, int d) {
  53. return ((x / ((int) Math.pow(10, d - 1))) % 10);
  54. }