在算法面试或机试(如 ACM 模式)中,往往需要手写或灵活运用常见的排序算法与二分查找算法。以下是使用 Java 实现的常见经典算法模板。
1. 快速排序(Quick Sort)
快速排序利用分治思想,通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序。
时间复杂度: 平均 $O(N \log N)$,最坏 $O(N^2)$。
空间复杂度: $O(\log 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
| public class QuickSort { public static void quickSort(int[] arr, int left, int right) { if (left >= right) { return; } int pivot = arr[(left + right) >> 1]; int i = left - 1; int j = right + 1; while (i < j) { while (arr[++i] < pivot); while (arr[--j] > pivot); if (i < j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } quickSort(arr, left, j); quickSort(arr, j + 1, right); } }
|
2. 归并排序(Merge Sort)
归并排序也是基于分治法。它将数组从中间分成两个子数组,分别递归排序,然后再将两个有序子数组合并成一个最终排序的数组。
时间复杂度: $O(N \log N)$。
空间复杂度: $O(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 34 35 36 37 38
| public class MergeSort { public static void mergeSort(int[] arr, int left, int right) { if (left >= right) { return; } int mid = left + (right - left) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right);
int[] temp = new int[right - left + 1]; int k = 0; int i = left, j = mid + 1; while(i <= mid && j <= right) { if (arr[i] < arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } }
while(i <= mid) { temp[k++] = arr[i++]; } while(j <= right) { temp[k++] = arr[j++]; }
k = 0; for(int i = left; i <= right; i ++) { arr[i] = temp[k++]; } } }
|
3. 堆排序(Heap Sort)
堆排序可以分为两步:第一步建堆(对于升序排序一般建大根堆),第二步是将堆顶元素(最大值)和末尾元素交换,并缩小堆的大小,重新调整堆。
时间复杂度: $O(N \log N)$。
空间复杂度: $O(1)$。
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public class HeapSort { public static void heapSort(int[] arr) { int n = arr.length; for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } for (int i = n - 1; i > 0; i--) { int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; heapify(arr, i, 0); } }
private static void heapify(int[] arr, int n, int i) { int largest = i; int left = 2 * i + 1; int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest]) { largest = left; }
if (right < n && arr[right] > arr[largest]) { largest = right; }
if (largest != i) { int swap = arr[i]; arr[i] = arr[largest]; arr[largest] = swap;
heapify(arr, n, largest); } } }
|
4. 二分查找(Binary Search)
二分查找是针对有序数组的高效查找算法,每次将搜索范围缩小一半。
时间复杂度: $O(\log N)$。
空间复杂度: $O(1)$。
标准二分查找(找精确值)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class BinarySearch { public static int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] == target) { return mid; } else if (arr[mid] < target) { left = mid + 1; } else { right = mid - 1; } } return -1; } }
|
寻找左侧边界的二分查找(常用变形)
在数组有重复数字的情况下,找到目标值出现的第一个位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static int leftBound(int[] arr, int target) { int left = 0, right = arr.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] < target) { left = mid + 1; } else if (arr[mid] > target) { right = mid - 1; } else if (arr[mid] == target) { right = mid - 1; } } if (left >= arr.length || arr[left] != target) { return -1; } return left; }
|