当前位置:   article > 正文

算法.1-三大排序算法-对数器-二分

算法.1-三大排序算法-对数器-二分

三大排序算法&对数器

1.选择排序

Java版

  1. package class01;
  2. import java.util.Arrays;
  3. public class Code01_SelectionSort {
  4. public static void selectionSort(int[] arr) {
  5. if (arr == null || arr.length < 2) {
  6. return;
  7. }
  8. // 0 ~ N-1 找到最小值,在哪,放到0位置上
  9. // 1 ~ n-1 找到最小值,在哪,放到1 位置上
  10. // 2 ~ n-1 找到最小值,在哪,放到2 位置上
  11. for (int i = 0; i < arr.length - 1; i++) {
  12. int minIndex = i;
  13. for (int j = i + 1; j < arr.length; j++) { // i ~ N-1 上找最小值的下标
  14. minIndex = arr[j] < arr[minIndex] ? j : minIndex;
  15. }
  16. swap(arr, i, minIndex);
  17. }
  18. }
  19. public static void swap(int[] arr, int i, int j) {
  20. int tmp = arr[i];
  21. arr[i] = arr[j];
  22. arr[j] = tmp;
  23. }
  24. // for test
  25. public static void comparator(int[] arr) {
  26. Arrays.sort(arr);
  27. }
  28. // for test
  29. public static int[] generateRandomArray(int maxSize, int maxValue) {
  30. // Math.random() [0,1)
  31. // Math.random() * N [0,N)
  32. // (int)(Math.random() * N) [0, N-1]
  33. int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
  34. for (int i = 0; i < arr.length; i++) {
  35. // [-? , +?]
  36. arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
  37. }
  38. return arr;
  39. }
  40. // for test
  41. public static int[] copyArray(int[] arr) {
  42. if (arr == null) {
  43. return null;
  44. }
  45. int[] res = new int[arr.length];
  46. for (int i = 0; i < arr.length; i++) {
  47. res[i] = arr[i];
  48. }
  49. return res;
  50. }
  51. // for test
  52. public static boolean isEqual(int[] arr1, int[] arr2) {
  53. if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
  54. return false;
  55. }
  56. if (arr1 == null && arr2 == null) {
  57. return true;
  58. }
  59. if (arr1.length != arr2.length) {
  60. return false;
  61. }
  62. for (int i = 0; i < arr1.length; i++) {
  63. if (arr1[i] != arr2[i]) {
  64. return false;
  65. }
  66. }
  67. return true;
  68. }
  69. // for test
  70. public static void printArray(int[] arr) {
  71. if (arr == null) {
  72. return;
  73. }
  74. for (int i = 0; i < arr.length; i++) {
  75. System.out.print(arr[i] + " ");
  76. }
  77. System.out.println();
  78. }
  79. // for test
  80. public static void main(String[] args) {
  81. int testTime = 500000;
  82. int maxSize = 100;
  83. int maxValue = 100;
  84. boolean succeed = true;
  85. for (int i = 0; i < testTime; i++) {
  86. int[] arr1 = generateRandomArray(maxSize, maxValue);
  87. int[] arr2 = copyArray(arr1);
  88. selectionSort(arr1);
  89. comparator(arr2);
  90. if (!isEqual(arr1, arr2)) {
  91. succeed = false;
  92. printArray(arr1);
  93. printArray(arr2);
  94. break;
  95. }
  96. }
  97. System.out.println(succeed ? "Nice!" : "Wrong!");
  98. int[] arr = generateRandomArray(maxSize, maxValue);
  99. printArray(arr);
  100. selectionSort(arr);
  101. printArray(arr);
  102. }
  103. }

C++ 

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <vector>
  4. using namespace std;
  5. void selectionSort(vector<int>& arr) {
  6. if (arr.size() < 2) {
  7. return;
  8. }
  9. for (int i = 0; i < arr.size() - 1; i++) {
  10. int minIndex = i;
  11. for (int j = i + 1; j < arr.size(); j++) { // i ~ N-1 上找最小值的下标
  12. minIndex = arr[j] < arr[minIndex] ? j : minIndex;
  13. }
  14. swap(arr[i], arr[minIndex]);
  15. }
  16. }
  17. // for test
  18. void comparator(vector<int>& arr) {
  19. sort(arr.begin(), arr.end());
  20. }
  21. // for test
  22. vector<int> generateRandomArray(int maxSize, int maxValue) {
  23. vector<int> arr((size_t)((maxSize + 1) * (double)rand() / RAND_MAX));
  24. for (int i = 0; i < arr.size(); i++) {
  25. arr[i] = (int)((maxValue + 1) * (double)rand() / RAND_MAX) - (int)(maxValue * (double)rand() / RAND_MAX);
  26. }
  27. return arr;
  28. }
  29. // for test
  30. vector<int> copyArray(const vector<int>& arr) {
  31. if (arr.empty()) {
  32. return {};
  33. }
  34. vector<int> res(arr.size());
  35. for (size_t i = 0; i < arr.size(); i++) {
  36. res[i] = arr[i];
  37. }
  38. return res;
  39. }
  40. // for test
  41. bool isEqual(const vector<int>& arr1, const vector<int>& arr2) {
  42. if ((arr1.empty() && !arr2.empty()) || (!arr1.empty() && arr2.empty())) {
  43. return false;
  44. }
  45. if (arr1.empty() && arr2.empty()) {
  46. return true;
  47. }
  48. if (arr1.size() != arr2.size()) {
  49. return false;
  50. }
  51. for (size_t i = 0; i < arr1.size(); i++) {
  52. if (arr1[i] != arr2[i]) {
  53. return false;
  54. }
  55. }
  56. return true;
  57. }
  58. // for test
  59. void printArray(const vector<int>& arr) {
  60. if (arr.empty()) {
  61. return;
  62. }
  63. for (const auto& val : arr) {
  64. cout << val << " ";
  65. }
  66. cout << endl;
  67. }
  68. // for test
  69. int main() {
  70. srand(time(nullptr));
  71. int testTime = 500000;
  72. int maxSize = 100;
  73. int maxValue = 100;
  74. bool succeed = true;
  75. for (int i = 0; i < testTime; i++) {
  76. vector<int> arr1 = generateRandomArray(maxSize, maxValue);
  77. vector<int> arr2 = copyArray(arr1);
  78. selectionSort(arr1);
  79. comparator(arr2);
  80. if (!isEqual(arr1, arr2)) {
  81. succeed = false;
  82. printArray(arr1);
  83. printArray(arr2);
  84. break;
  85. }
  86. }
  87. cout << (succeed ? "Nice!" : "Wrong!") << endl;
  88. vector<int> arr = generateRandomArray(maxSize, maxValue);
  89. printArray(arr);
  90. selectionSort(arr);
  91. printArray(arr);
  92. return 0;
  93. }

对数器

1,你想要测的方法a(最优解)

2,实现复杂度不好但是容易实现的方法b(暴力解)

3,实现一个随机样本产生器(长度也随机、值也随机)

4,把方法a和方法b跑相同的输入样本,看看得到的结果是否一样

5,如果有一个随机样本使得比对结果不一致,打印这个出错的样本进行人工干预,改对方法a和方法b

6,当样本数量很多时比对测试依然正确,可以确定方法a(最优解)已经正确。

关键是第5步,找到一个数据量小的错误样本,便于你去带入debug

然后把错误例子带入代码一步一步排查

Print大法、断点技术都可以

对数器的门槛其实是比较高的,因为往往需要在两种不同思路下实现功能相同的两个方法,暴力一个、想象中的最优解是另一个。

以后的很多题目都会用到对数器,几乎可以验证任何方法,尤其在验证贪心、观察规律方面很有用

到时候会丰富很多对数器的实战用法,这里只是一个简单易懂的示例

2.冒泡排序

  1. public class Code02_BubbleSort {
  2. public static void bubbleSort(int[] arr) {
  3. if (arr == null || arr.length < 2) {
  4. return;
  5. }
  6. // 0 ~ N-1
  7. // 0 ~ N-2
  8. // 0 ~ N-3
  9. for (int e = arr.length - 1; e > 0; e--) { // 0 ~ e
  10. for (int i = 0; i < e; i++) {
  11. if (arr[i] > arr[i + 1]) {
  12. swap(arr, i, i + 1);
  13. }
  14. }
  15. }
  16. }
  17. // 交换arr的i和j位置上的值
  18. public static void swap(int[] arr, int i, int j) {
  19. arr[i] = arr[i] ^ arr[j];
  20. arr[j] = arr[i] ^ arr[j];
  21. arr[i] = arr[i] ^ arr[j];
  22. }

3.插入排序(类似打扑克时摸到牌插牌的感觉)

  1. public static void insertionSort(int[] arr) {
  2. if (arr == null || arr.length < 2) {
  3. return;
  4. }
  5. // 不只1个数
  6. for (int i = 1; i < arr.length; i++) { // 0 ~ i 做到有序
  7. for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
  8. swap(arr, j, j + 1);
  9. }
  10. }
  11. }
  12. // i和j是一个位置的话,会出错
  13. public static void swap(int[] arr, int i, int j) {
  14. arr[i] = arr[i] ^ arr[j];
  15. arr[j] = arr[i] ^ arr[j];
  16. arr[i] = arr[i] ^ arr[j];
  17. }

二分

1.在有序数组中确定num存在还是不存在

指针来到中间位置,中间值比n大意味着n-n-1位置都不可能,右指针来到mid-1,在左右之间再次取中间值递归

  1. package class01;
  2. import java.util.Arrays;
  3. public class Code04_BSExist {
  4. public static boolean exist(int[] sortedArr, int num) {
  5. if (sortedArr == null || sortedArr.length == 0) {
  6. return false;
  7. }
  8. int L = 0;
  9. int R = sortedArr.length - 1;
  10. int mid = 0;
  11. // L..R
  12. while (L < R) { // L..R 至少两个数的时候
  13. mid = L + ((R - L) >> 1);
  14. if (sortedArr[mid] == num) {
  15. return true;
  16. } else if (sortedArr[mid] > num) {
  17. R = mid - 1;
  18. } else {
  19. L = mid + 1;
  20. }
  21. }
  22. return sortedArr[L] == num;
  23. }
  24. // for test
  25. public static boolean test(int[] sortedArr, int num) {
  26. for(int cur : sortedArr) {
  27. if(cur == num) {
  28. return true;
  29. }
  30. }
  31. return false;
  32. }
  33. // for test
  34. public static int[] generateRandomArray(int maxSize, int maxValue) {
  35. int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
  36. for (int i = 0; i < arr.length; i++) {
  37. arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
  38. }
  39. return arr;
  40. }
  41. public static void main(String[] args) {
  42. int testTime = 500000;
  43. int maxSize = 10;
  44. int maxValue = 100;
  45. boolean succeed = true;
  46. for (int i = 0; i < testTime; i++) {
  47. int[] arr = generateRandomArray(maxSize, maxValue);
  48. Arrays.sort(arr);
  49. int value = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
  50. if (test(arr, value) != exist(arr, value)) {
  51. succeed = false;
  52. break;
  53. }
  54. }
  55. System.out.println(succeed ? "Nice!" : "fuck!");
  56. }
  57. }

2.在有序数组中找>=num的最左位置

  1. / 在arr上,找满足>=value的最左位置
  2. public static int nearestIndex(int[] arr, int value) {
  3. int L = 0;
  4. int R = arr.length - 1;
  5. int index = -1; // 记录最左的对号
  6. while (L <= R) { // 至少一个数的时候
  7. int mid = L + ((R - L) >> 1);
  8. if (arr[mid] >= value) {
  9. index = mid;
  10. R = mid - 1;
  11. } else {
  12. L = mid + 1;
  13. }
  14. }
  15. return index;
  16. }

3.最右 

  1. // 在arr上,找满足<=value的最右位置
  2. public static int nearestIndex(int[] arr, int value) {
  3. int L = 0;
  4. int R = arr.length - 1;
  5. int index = -1; // 记录最右的对号
  6. while (L <= R) {
  7. int mid = L + ((R - L) >> 1);
  8. if (arr[mid] <= value) {
  9. index = mid;
  10. L = mid + 1;
  11. } else {
  12. R = mid - 1;
  13. }
  14. }
  15. return index;
  16. }

4.寻找最小值,二分搜索不一定发生在有序数组上, 

  1. package class01;
  2. public class Code06_BSAwesome {
  3. public static int getLessIndex(int[] arr) {
  4. if (arr == null || arr.length == 0) {
  5. return -1; // no exist
  6. }
  7. if (arr.length == 1 || arr[0] < arr[1]) {
  8. return 0;
  9. }
  10. if (arr[arr.length - 1] < arr[arr.length - 2]) {
  11. return arr.length - 1;
  12. }
  13. int left = 1;
  14. int right = arr.length - 2;
  15. int mid = 0;
  16. while (left < right) {
  17. mid = (left + right) / 2;
  18. if (arr[mid] > arr[mid - 1]) {
  19. right = mid - 1;
  20. } else if (arr[mid] > arr[mid + 1]) {
  21. left = mid + 1;
  22. } else {
  23. return mid;
  24. }
  25. }
  26. return left;
  27. }
  28. }

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

闽ICP备14008679号