排序算法
冒泡排序
可以先这么想,
- 对于外层循环,就是五个数字要比较四轮(又例如,99个数字比较98轮),n 个数字比较n - 1轮。
- 对于内层循环,(以第一次循环的时候为例子)五个数字需要比较四次(才能将最大的那一个沉底),(以第一次循环的时候为例子)99个数字比较98次(才能将最大的那一个沉底)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public void BubbleSort(int[] nums){ for (int i = 1; i < nums.length; i++) { for (int j = 0; j < nums.length - i; j++){ if (nums[j] > nums[j + 1]) { int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; } } } }
|
选择排序
- 新的理解,将下标逐次赋给min_index的时候,并不需要把最后一个(即n - 1)赋给它,因为每次遍历已经将最小值置换到前面去了,最后一个肯定是最大的那一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public void select_sort(int[] arr){ int n = arr.length, min_index; for (int i = 0; i < n - 1; i++) { min_index = i; for (int j = i + 1; j < n; j++) { if (arr[min_index] > arr[j]) { min_index = j; } } if(i != min_index){ int tmp = arr[i]; arr[i] = arr[min_index]; arr[min_index] = tmp; } } }
|
插入排序
这个版本的插入排序和希尔排序都挺好记忆的,(对我而言)是最优的版本
1 2 3 4 5 6 7 8 9 10
| static void insert_sort(int[] arr) { int n = arr.length; for (int i = 0; i < n; i++) { int j = i, v = arr[i]; while (j - 1 >= 0 && arr[j - 1] > v) arr[j] = arr[--j]; arr[j] = v; } }
|
希尔排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| static void shell_sort(int[] arr) { int gap = arr.length; while (gap > 1) { gap /= 2; for (int i = 0; i < arr.length; i++) { int v = arr[i]; int j = i; while (j - gap >= 0 && arr[j - gap] >= v) { arr[j] = arr[j - gap]; j -= gap; } arr[j] = v; } } }
|
归并排序
是我太无知了,将这个程序Debug了四五次,我还是把这个程序先背过吧,以后多写几遍慢慢理解
System.arraycopy();中的五个参数分别是:
源数组,(复制)起始位置,目的数组,(拷贝)起始位置,复制的长度。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public void merge_Sort(int l, int r){ if (l >= r) return; int mid = (l + r) >> 1; merge_Sort(l, mid); merge_Sort(mid + 1, r); merge(l, mid, r); }
public void merge(int l, int m, int r){ int s = l; int j = m + 1; int idx = l; while (l <= m && j <= r){ if (arr0[l] <= arr0[j]) arr1[idx] = arr0[l++]; else arr1[idx] = arr0[j++]; idx++; } while (l <= m) arr1[idx++] = arr0[l++]; while (j <= r) arr1[idx++] = arr0[j++]; if (r + 1 - s >= 0) System.arraycopy(arr1, s, arr0, s, r + 1 - s); }
|
快速排序
它第一次循环下来肯定是左边的数字小于参考值,右边的数全部大于参考值,(参考值就可以完全归位了)
- 之前,我一直有一个疑问为啥要先从右边找(第一个比tmp小的值)呢?为啥我不可以从左边先找一个比参考值(tmp)大的数字呢
在进行循环比较的时候,一定是tmp <= arr[j],如果忘了等于号就会导致从左边到右边第一个数字(也就是tmp)被选中交换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static void quick_sort(int[] arr, int l, int r){ if (l >= r) return; int i = l, j = r, tmp = arr[l]; while (i < j){ while (tmp <= arr[j] && j > i) j--; while (tmp >= arr[i] && j > i) i++; if (i < j){ arr[i] ^= arr[j]; arr[j] ^= arr[i]; arr[i] ^= arr[j]; } } arr[l] = arr[j]; arr[j] = tmp; quick_sort(arr, l, j - 1); quick_sort(arr, j + 1, r); }
|
- 当二者(i,j)相遇之后,那一个数字肯定比参考值小(tmp),才能进行交换操作,使得参考值左边的数字都小于自己,参考值右边的数字都大于自己。
桶排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void bucketSort(int[] arr) { int min = 0x3f3f3f3f, max = -min; for(var e : arr) { min = Math.min(min, e); max = Math.max(max, e); } int bucketSize = (max - min) / arr.length + 1; int bucketCount = (max - min) / bucketSize + 1; List<Integer>[] lists = new ArrayList[bucketCount]; Arrays.setAll(lists, e -> new ArrayList<>()); for (var e : arr) { lists[(e - min) / bucketSize].add(e); } for (var list : lists) list.sort(Comparator.comparing(e -> e)); int idx = 0; for (int i = 0; i < bucketCount; i++) { for (var e : lists[i]) arr[idx++] = e; } }
|
计数排序
不能处理负数,如果有负数就得加偏移量。
有一些像我之前写过的统计字符串中的字符那一道题目,应该也是10个中最简单的一个了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void countSort(int[] arr) { int n = arr.length; Integer[] array = new Integer[1000]; for (var e : arr) { if (array[e] == null) array[e] = 1; else array[e] += 1; } int idx = 0; for (int i = 0; i < 1000; i++) { if (array[i] != null) { int cnt = array[i]; while (cnt-- > 0) arr[idx++] = i; } } }
|
基数排序
核心思想: 用0~9表示位上面的数,总共10个桶,遍历maxLen次,每次遍历当前位,将每个数放到自己值的位置。时间复杂度稳定O(k * n),不能处理负数,如果有负数就得加偏移量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| void radixSort(int[] arr) { LinkedList<Integer>[] lists = new LinkedList[10]; Arrays.setAll(lists, e -> new LinkedList<>()); int maxLen = -1; for (var e : arr) maxLen = Math.max(getLength(e), maxLen); for (int i = 1; i <= maxLen; i++) { for (var e : arr) lists[getIndexValue(i, e)].add(e); int idx = 0; for (var list : lists) { while (!list.isEmpty()) { arr[idx++] = list.poll(); } } } }
int getLength(int num) { int ans = 0; while (num > 0) { num /= 10; ans++; } return ans; }
int getIndexValue(int k, int num) { int res = num % 10; for (int i = 0; i < k; i++) { res = num % 10; num /= 10; } return res; }
|