C++双指针快排算法
简介(什么是双指针)
有什么优势
- 时间复杂度通常较低,很多情况下能达到线性时间复杂度O(n),避免了暴力解法中可能出现的双重循环导致的O(n^2)时间复杂度,提高了算法效率。
时间复杂度
- O(n)
指针思想and基本原理
- 利用两个指针,通常命名为 left 和 right ,或者 slow 和 fast 等,它们在数据结构上移动,通过不同的移动策略来解决各种问题。本文指针均用l和r代表左右指针
实例代码1(快排算法)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
// 数组q用于存储待排序的元素
int q[N];
// 快速排序函数quick_sort,参数为数组q,以及待排序区间的左右边界l和r
void quick_sort(int q[], int l, int r);
int main() {
//读取操作
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> q[i];
quick_sort(q, 0, n - 1);
//输出快排后的结果
for (int i = 0; i < n; i++)
cout << q[i] << " ";
return 0;
}
void quick_sort(int q[], int l, int r) {
// 如果左边界l大于等于右边界r,说明区间内元素个数等于1或者0,无需排序,直接返回
if (l >= r)
return;
// 选择数组中间元素q[l+r]作为基准元素x,初始化左指针i为l-1,右指针j为r+1
//左指针之所以为l-1,右指针之所以为r+1,是为了便利后续操作,因为后续操作为++i,++j,是先移动指针i和j,然后再和基准元素x做比较
int x = q[l+r], i = l - 1, j = r + 1;
// 当左指针i小于右指针j时,继续循环,进行元素交换和指针移动
while (i < j) {
// 从左向右移动左指针i,直到找到一个大于等于基准元素x的元素才停止
while (q[++i] < x);
// 从右向左移动右指针j,直到找到一个小于等于基准元素x的元素才停止
while (q[--j] > x);
// 如果i小于j,说明找到了一对需要交换位置的元素,交换它们
if (i < j) swap(q[i], q[j]);
}
// 递归调用快速排序函数,对左子数组(即基准元素x左边的子数组)进行排序
quick_sort(q, l, j);
// 递归调用快速排序函数,对右子数组(即基准元素x右边的子数组)进行排序
quick_sort(q, j + 1, r);
}
代码1的详细说明,逻辑
1.quick_sort函数原理
-首先选择一个基准元素(这里是q[l])。
- 通过两个指针i和j从数组的两端向中间移动,i从左向右找大于等于基准的元素,j从右向左找小于等于基准的元素,当i < j时,交换这两个元素。
- 当i和j相遇时,将基准元素与j指向的元素交换,此时基准元素左边的元素都小于它,右边的元素都大于它。
- 然后递归地对基准元素左边和右边的子数组进行快速排序。
2.main函数功能
- 读取输入的数组大小n。
- 读取n个整数到数组q中。
- 调用quick_sort函数对数组q进行排序。
- 最后输出排序后的数组元素。
3. * *递归终止条件 * *
if (l >= r) return;
:如果左边界大于等于右边界,说明子数组的元素个数为0或1,已经是有序的,直接返回,不再进行排序操作。
4. * *选择基准元素并初始化指针 * *
int x = q[l], i = l - 1, j = r + 1;
:选择数组的第一个元素q[l]
作为基准元素x
。然后初始化两个指针i
和j
,i
初始化为左边界l
的左边一个位置(l - 1
),j
初始化为右边界r
的右边一个位置(r+1
)。
5. * *划分操作(双指针法) * *
-while (i < j)
:只要i
小于j
,就进行以下操作。
do i++; while (q[i] < x);
:从左向右移动i
指针,直到找到一个大于等于基准元素x
的元素。do j--; while (q[j] > x);
:从右向左移动j
指针,直到找到一个小于等于基准元素x
的元素。if (i < j) swap(q[i], q[j]);
:如果i
小于j
,说明找到了一对需要交换的元素,将它们交换,以使得左边的元素都小于等于基准元素,右边的元素都大于等于基准元素。
6. * *递归调用 * *
quick_sort(q, l, j);
:对基准元素左边的子数组(左闭右闭区间[l, j]
)进行快速排序。quick_sort(q, j + 1, r);
:对基准元素右边的子数组(左闭右闭区间[j + 1, r]
)进行快速排序。
实例代码2
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int q[N];
int quick_sort(int q[], int l, int r,int k);
int main() {
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> q[i];
cout << quick_sort(q, 0, n - 1, k)<< " ";
return 0;
}
int quick_sort(int q[], int l, int r,int k) {
if (l >= r)
return q[l];
int x = q[l], i = l - 1, j = r + 1;
while (i < j) {
while (q[++i] < x);
while (q[--j] > x);
if (i < j) swap(q[i], q[j]);
}
int sl = j - l + 1;//这里的i和j可以互换,因为此时的i和j都指向了同一个位置,
if(k<=sl)
return quick_sort(q, l, j, k);
return quick_sort(q, j + 1, r, k-sl);
}
代码2的详细说明,逻辑
1.quick_sort函数原理
- 首先选择一个基准元素(这里是q[l])。
- 通过两个指针i和j从数组的两端向中间移动,i从左向右找大于等于基准的元素,j从右向左找小于等于基准的元素,当i < j时,交换这两个元素。
- 当i和j相遇时,将基准元素与j指向的元素交换,此时基准元素左边的元素都小于它,右边的元素都大于它。基准元素左边的元素构成s1,基准元素右边的元素构成s2
- 然后递归地对基准元素左边和右边的子数组进行快速排序。
2.main函数功能
- 读取输入的数组大小n。
- 读取n个整数到数组q中。
- 调用quick_sort函数对数组q进行排序。
- 最后输出排序后的数组元素。
3. * *递归终止条件 * *
if (l >= r) return;
:如果左边界大于等于右边界,说明子数组的元素个数为0或1,已经是有序的,直接返回,不再进行排序操作。
4. * *选择基准元素并初始化指针 * *
- `int x = q[l], i = l - 1, j = r + 1; `:选择数组的第一个元素`q[l]`作为基准元素`x`。然后初始化两个指针`i`和`j`,`i`初始化为左边界`l`的左边一个位置(`l - 1`),`j`初始化为右边界`r`的右边一个位置(`r+1`)。
5. * *划分操作(双指针法) * *
while (i < j)
:只要i
小于j
,就进行以下操作。do i++; while (q[i] < x);
:从左向右移动i
指针,直到找到一个大于等于基准元素x
的元素。do j--; while (q[j] > x);
:从右向左移动j
指针,直到找到一个小于等于基准元素x
的元素。if (i < j) swap(q[i], q[j]);
:如果i
小于j
,说明找到了一对需要交换的元素,将它们交换,以使得左边的元素都小于等于基准元素,右边的元素都大于等于基准元素。
6. * *递归调用 * *
quick_sort(q, l, j);
:对基准元素左边的子数组(左闭右闭区间[l, j]
)进行快速排序。quick_sort(q, j + 1, r);
:对基准元素右边的子数组(左闭右闭区间[j + 1, r]
)进行快速排序。