在常见的排序算法中,有几种可以使用双指针技术来优化。让我详细介绍:
1️⃣ 快速排序(最典型的双指针应用)
public class QuickSort {
public void quickSort(int[] arr, int left, int right) {
if (left < right) {
int pivot = partition(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
}
private int partition(int[] arr, int left, int right) {
int pivot = arr[left]; // 选择第一个元素作为基准
int i = left; // 左指针
int j = right; // 右指针
while (i < j) {
// 右指针向左移,找到小于pivot的数
while (i < j && arr[j] >= pivot) {
j--;
}
// 左指针向右移,找到大于pivot的数
while (i < j && arr[i] <= pivot) {
i++;
}
// 交换两个数
if (i < j) {
swap(arr, i, j);
}
}
// 将基准值放到最终位置
swap(arr, left, i);
return i;
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
2️⃣ 归并排序的合并过程(双指针)
public class MergeSort {
private void merge(int[] arr, int left, int mid, int right) {
int i = left; // 左半部分的指针
int j = mid + 1; // 右半部分的指针
int[] temp = new int[right - left + 1]; // 临时数组
int t = 0;
// 使用双指针合并两个有序数组
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
// 处理剩余元素
while (i <= mid) temp[t++] = arr[i++];
while (j <= right) temp[t++] = arr[j++];
// 复制回原数组
System.arraycopy(temp, 0, arr, left, temp.length);
}
}
3️⃣ 冒泡排序的优化版本(双指针)
public class BubbleSort {
public void bubbleSort(int[] arr) {
int left = 0; // 左边界
int right = arr.length - 1; // 右边界
while (left < right) {
// 从左向右冒泡,将最大值移到右边
for (int i = left; i < right; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
}
}
right--;
// 从右向左冒泡,将最小值移到左边
for (int i = right; i > left; i--) {
if (arr[i] < arr[i - 1]) {
swap(arr, i, i - 1);
}
}
left++;
}
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
4️⃣ 三路快排(三指针)
public class ThreeWayQuickSort {
public void quickSort3Way(int[] arr, int left, int right) {
if (left >= right) return;
int lt = left; // 小于区域的右边界
int i = left + 1; // 当前遍历的位置
int gt = right; // 大于区域的左边界
int pivot = arr[left]; // 基准值
while (i <= gt) {
if (arr[i] < pivot) {
swap(arr, lt++, i++);
} else if (arr[i] > pivot) {
swap(arr, i, gt--);
} else {
i++;
}
}
quickSort3Way(arr, left, lt - 1);
quickSort3Way(arr, gt + 1, right);
}
}
📝 各种双指针实现的比较
-
快速排序
- 优点:原地排序,不需要额外空间
- 缺点:不稳定排序
-
归并排序
- 优点:稳定排序
- 缺点:需要额外空间
-
冒泡排序优化版
- 优点:实现简单,稳定排序
- 缺点:时间复杂度仍为O(n²)
-
三路快排
- 优点:处理重复元素效率高
- 缺点:实现相对复杂
🎯 使用场景建议
- 数据量大且内存充足:归并排序
- 数据量大且要求原地排序:快速排序
- 数据量小:冒泡排序
- 有大量重复元素:三路快排
⚡ 性能比较
算法 时间复杂度(平均) 空间复杂度 是否稳定
快速排序 O(nlogn) O(1) 否
归并排序 O(nlogn) O(n) 是
冒泡排序 O(n²) O(1) 是
三路快排 O(nlogn) O(1) 否
这些使用双指针的实现方式都能在某种程度上优化排序过程,具体选择哪种方法要根据实际场景考虑:
- 内存限制
- 数据特征
- 稳定性要求
- 性能要求