当前位置:   article > 正文

力扣解题:数组排序 各种排序算法 java_力扣有默认排序方法

力扣有默认排序方法

题目:

给你一个整数数组 nums,请你将该数组升序排列

示例 1:输入:nums = [5,2,3,1] 输出:[1,2,3,5]

1、直接插入排序

  1. /*nums[]数组,对其升序排序
  2. * */
  3. //插入排序
  4. public class InsertSort {
  5. public int[] sortArray(int[] nums) {
  6. int len = nums.length;
  7. for (int i = 1; i < len; i++) {
  8. // 先暂存这个元素,然后之前元素逐个后移,留出空位
  9. if (nums[i]<nums[i-1]) {
  10. int temp = nums[i];
  11. int j = i - 1;
  12. while (j >= 0 && nums[j] > temp) {
  13. nums[j + 1] = nums[j];
  14. j--;
  15. }
  16. nums[j + 1] = temp;
  17. }
  18. }
  19. return nums;
  20. }
  21. }

2、选择排序

  1. public class Solution {
  2. // 选择排序:每一轮选择最小元素交换到未排定部分的开头
  3. public int[] sortArray(int[] nums) {
  4. int len = nums.length;
  5. // 循环不变量:[0, i) 有序,且该区间里所有元素就是最终排定的样子
  6. for (int i = 0; i < len - 1; i++) {
  7. // 选择区间 [i, len - 1] 里最小的元素的索引,交换到下标 i
  8. int minIndex = i;
  9. for (int j = i + 1; j < len; j++) {
  10. if (nums[j] < nums[minIndex]) {
  11. minIndex = j;
  12. }
  13. }
  14. swap(nums, i, minIndex);
  15. }
  16. return nums;
  17. }
  18. private void swap(int[] nums, int index1, int index2) {
  19. int temp = nums[index1];
  20. nums[index1] = nums[index2];
  21. nums[index2] = temp;
  22. }
  23. public static void main(String[] args) {
  24. int[] nums = {5, 2, 3, 1};
  25. Solution solution = new Solution();
  26. int[] res = solution.sortArray(nums);
  27. System.out.println(Arrays.toString(res));
  28. }
  29. }

3、归并排序

  1. public class Solution {
  2. // 归并排序
  3. /**
  4. * 列表大小等于或小于该大小,将优先于 mergeSort 使用插入排序
  5. */
  6. private static final int INSERTION_SORT_THRESHOLD = 7;
  7. public int[] sortArray(int[] nums) {
  8. int len = nums.length;
  9. int[] temp = new int[len];
  10. mergeSort(nums, 0, len - 1, temp);
  11. return nums;
  12. }
  13. /**
  14. * 对数组 nums 的子区间 [left, right] 进行归并排序
  15. *
  16. * @param nums
  17. * @param left
  18. * @param right
  19. * @param temp 用于合并两个有序数组的辅助数组,全局使用一份,避免多次创建和销毁
  20. */
  21. private void mergeSort(int[] nums, int left, int right, int[] temp) {
  22. // 小区间使用插入排序
  23. if (right - left <= INSERTION_SORT_THRESHOLD) {
  24. insertionSort(nums, left, right);
  25. return;
  26. }
  27. int mid = left + (right - left) / 2;
  28. // Java 里有更优的写法,在 leftright 都是大整数时,即使溢出,结论依然正确
  29. // int mid = (left + right) >>> 1;
  30. mergeSort(nums, left, mid, temp);
  31. mergeSort(nums, mid + 1, right, temp);
  32. // 如果数组的这个子区间本身有序,无需合并
  33. if (nums[mid] <= nums[mid + 1]) {
  34. return;
  35. }
  36. mergeOfTwoSortedArray(nums, left, mid, right, temp);
  37. }
  38. /**
  39. * 对数组 arr 的子区间 [left, right] 使用插入排序
  40. *
  41. * @param arr 给定数组
  42. * @param left 左边界,能取到
  43. * @param right 右边界,能取到
  44. */
  45. private void insertionSort(int[] arr, int left, int right) {
  46. for (int i = left + 1; i <= right; i++) {
  47. int temp = arr[i];
  48. int j = i;
  49. while (j > left && arr[j - 1] > temp) {
  50. arr[j] = arr[j - 1];
  51. j--;
  52. }
  53. arr[j] = temp;
  54. }
  55. }
  56. /**
  57. * 合并两个有序数组:先把值复制到临时数组,再合并回去
  58. *
  59. * @param nums
  60. * @param left
  61. * @param mid [left, mid] 有序,[mid + 1, right] 有序
  62. * @param right
  63. * @param temp 全局使用的临时数组
  64. */
  65. private void mergeOfTwoSortedArray(int[] nums, int left, int mid, int right, int[] temp) {
  66. System.arraycopy(nums, left, temp, left, right + 1 - left);
  67. int i = left;
  68. int j = mid + 1;
  69. for (int k = left; k <= right; k++) {
  70. if (i == mid + 1) {
  71. nums[k] = temp[j];
  72. j++;
  73. } else if (j == right + 1) {
  74. nums[k] = temp[i];
  75. i++;
  76. } else if (temp[i] <= temp[j]) {
  77. // 注意写成 < 就丢失了稳定性(相同元素原来靠前的排序以后依然靠前)
  78. nums[k] = temp[i];
  79. i++;
  80. } else {
  81. // temp[i] > temp[j]
  82. nums[k] = temp[j];
  83. j++;
  84. }
  85. }
  86. }
  87. }

4、快速排序

  1. import java.util.Random;
  2. public class Solution {
  3. // 快速排序 2:双指针(指针对撞)快速排序
  4. /**
  5. * 列表大小等于或小于该大小,将优先于 quickSort 使用插入排序
  6. */
  7. private static final int INSERTION_SORT_THRESHOLD = 7;
  8. private static final Random RANDOM = new Random();
  9. public int[] sortArray(int[] nums) {
  10. int len = nums.length;
  11. quickSort(nums, 0, len - 1);
  12. return nums;
  13. }
  14. private void quickSort(int[] nums, int left, int right) {
  15. // 小区间使用插入排序
  16. if (right - left <= INSERTION_SORT_THRESHOLD) {
  17. insertionSort(nums, left, right);
  18. return;
  19. }
  20. int pIndex = partition(nums, left, right);
  21. quickSort(nums, left, pIndex - 1);
  22. quickSort(nums, pIndex + 1, right);
  23. }
  24. /**
  25. * 对数组 nums 的子区间 [left, right] 使用插入排序
  26. *
  27. * @param nums 给定数组
  28. * @param left 左边界,能取到
  29. * @param right 右边界,能取到
  30. */
  31. private void insertionSort(int[] nums, int left, int right) {
  32. for (int i = left + 1; i <= right; i++) {
  33. int temp = nums[i];
  34. int j = i;
  35. while (j > left && nums[j - 1] > temp) {
  36. nums[j] = nums[j - 1];
  37. j--;
  38. }
  39. nums[j] = temp;
  40. }
  41. }
  42. private int partition(int[] nums, int left, int right) {
  43. int randomIndex = left + RANDOM.nextInt(right - left + 1);
  44. swap(nums, randomIndex, left);
  45. int pivot = nums[left];
  46. int lt = left + 1;
  47. int gt = right;
  48. // 循环不变量:
  49. // all in [left + 1, lt) <= pivot
  50. // all in (gt, right] >= pivot
  51. while (true) {
  52. while (lt <= right && nums[lt] < pivot) {
  53. lt++;
  54. }
  55. while (gt > left && nums[gt] > pivot) {
  56. gt--;
  57. }
  58. if (lt >= gt) {
  59. break;
  60. }
  61. // 细节:相等的元素通过交换,等概率分到数组的两边
  62. swap(nums, lt, gt);
  63. lt++;
  64. gt--;
  65. }
  66. swap(nums, left, gt);
  67. return gt;
  68. }
  69. private void swap(int[] nums, int index1, int index2) {
  70. int temp = nums[index1];
  71. nums[index1] = nums[index2];
  72. nums[index2] = temp;
  73. }
  74. }

5、堆排序 

  1. public class Solution {
  2. public int[] sortArray(int[] nums) {
  3. int len = nums.length;
  4. // 将数组整理成堆
  5. heapify(nums);
  6. // 循环不变量:区间 [0, i] 堆有序
  7. for (int i = len - 1; i >= 1; ) {
  8. // 把堆顶元素(当前最大)交换到数组末尾
  9. swap(nums, 0, i);
  10. // 逐步减少堆有序的部分
  11. i--;
  12. // 下标 0 位置下沉操作,使得区间 [0, i] 堆有序
  13. siftDown(nums, 0, i);
  14. }
  15. return nums;
  16. }
  17. /**
  18. * 将数组整理成堆(堆有序)
  19. *
  20. * @param nums
  21. */
  22. private void heapify(int[] nums) {
  23. int len = nums.length;
  24. // 只需要从 i = (len - 1) / 2 这个位置开始逐层下移
  25. for (int i = (len - 1) / 2; i >= 0; i--) {
  26. siftDown(nums, i, len - 1);
  27. }
  28. }
  29. /**
  30. * @param nums
  31. * @param k 当前下沉元素的下标
  32. * @param end [0, end] 是 nums 的有效部分
  33. */
  34. private void siftDown(int[] nums, int k, int end) {
  35. while (2 * k + 1 <= end) {
  36. int j = 2 * k + 1;
  37. if (j + 1 <= end && nums[j + 1] > nums[j]) {
  38. j++;
  39. }
  40. if (nums[j] > nums[k]) {
  41. swap(nums, j, k);
  42. } else {
  43. break;
  44. }
  45. k = j;
  46. }
  47. }
  48. private void swap(int[] nums, int index1, int index2) {
  49. int temp = nums[index1];
  50. nums[index1] = nums[index2];
  51. nums[index2] = temp;
  52. }
  53. }

6、希尔排序

  1. public class Solution {
  2. // 希尔排序
  3. public int[] sortArray(int[] nums) {
  4. int len = nums.length;
  5. int h = 1;
  6. // 使用 Knuth 增量序列
  7. // 找增量的最大值
  8. while (3 * h + 1 < len) {
  9. h = 3 * h + 1;
  10. }
  11. while (h >= 1) {
  12. // insertion sort
  13. for (int i = h; i < len; i++) {
  14. insertionForDelta(nums, h, i);
  15. }
  16. h = h / 3;
  17. }
  18. return nums;
  19. }
  20. /**
  21. * 将 nums[i] 插入到对应分组的正确位置上,其实就是将原来 1 的部分改成 gap
  22. *
  23. * @param nums
  24. * @param gap
  25. * @param i
  26. */
  27. private void insertionForDelta(int[] nums, int gap, int i) {
  28. int temp = nums[i];
  29. int j = i;
  30. // 注意:这里 j >= deta 的原因
  31. while (j >= gap && nums[j - gap] > temp) {
  32. nums[j] = nums[j - gap];
  33. j -= gap;
  34. }
  35. nums[j] = temp;
  36. }
  37. }

7、冒泡排序

  1. public class Solution {
  2. // 冒泡排序:超时
  3. public int[] sortArray(int[] nums) {
  4. int len = nums.length;
  5. for (int i = len - 1; i >= 0; i--) {
  6. // 先默认数组是有序的,只要发生一次交换,就必须进行下一轮比较,
  7. // 如果在内层循环中,都没有执行一次交换操作,说明此时数组已经是升序数组
  8. boolean sorted = true;
  9. for (int j = 0; j < i; j++) {
  10. if (nums[j] > nums[j + 1]) {
  11. swap(nums, j, j + 1);
  12. sorted = false;
  13. }
  14. }
  15. if (sorted) {
  16. break;
  17. }
  18. }
  19. return nums;
  20. }
  21. private void swap(int[] nums, int index1, int index2) {
  22. int temp = nums[index1];
  23. nums[index1] = nums[index2];
  24. nums[index2] = temp;
  25. }
  26. }

8、折半排序

  1. public class BinaryInsertSortTest {
  2. public void binaryInsertSort(int[] data) {
  3. for (int i = 1; i < data.length; i++) {
  4. if (data[i] < data[i - 1]) {
  5. // 缓存i处的元素值
  6. int tmp = data[i];
  7. // 记录搜索范围的左边界
  8. int low = 0;
  9. // 记录搜索范围的右边界
  10. int high = i - 1;
  11. while (low <= high) {
  12. // 记录中间位置
  13. int mid = (low + high) / 2;
  14. // 比较中间位置数据和i处数据大小,以缩小搜索范围
  15. if (data[mid] < tmp) {
  16. low = mid + 1;
  17. } else {
  18. high = mid - 1;
  19. }
  20. }
  21. //将low~i处数据整体向后移动1
  22. for (int j = i; j > low; j--) {
  23. data[j] = data[j - 1];
  24. }
  25. data[low] = tmp;
  26. }
  27. }
  28. }

题目链接:力扣 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/735816
推荐阅读
相关标签
  

闽ICP备14008679号