804 字
4 分钟
竞赛算法(2) 排序, 二分
2025-10-09
无标签

快速排序#

基于分治思想, 对于每个区间将其分为较小的一段和较大的一段, 较小段的最大值小于等于较大段的最小值.

快速排序的步骤
  1. 选定基准值x, 将某个区间分为小于等于x的部分和大于x的部分, 当x靠近中位数时分治效果较为理想. 通常随机选取区间中的某个数.
  2. 使用双指针i, j. 其中i从前往后遍历, j从后往前遍历.
  3. 保证i遍历过的部分都是小于等于x的, j遍历过的都是大于x的.
  4. 如果i处大于x, j处小于等于x, 并且i在j前面, 交换两处的数字, 并移动i和j
  5. 如果i不在j前面, 说明已经遍历完毕, break.
  6. 递归处理左右两段.
void qks(vector<int>& arr, int l, int r) {
if (l >= r) return;
int x = arr[(l + r) / 2];
int i = l - 1;
int j = r + 1;
while (i < j) {
do i++; while (arr[i] < x);
do j--; while (arr[j] > x);
if (i < j) swap(arr[i], arr[j]);
}
qks(arr, l, j);
qks(arr, j + 1, r);
}

归并排序#

同样基于分治思想, 见算法导论.

void mgs(vector<int>& arr, int l, int r) {
static vector<int> tmp(arr.size());
if (l >= r) return;
int mid = (l + r) / 2;
mgs(arr, l, mid), mgs(arr, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r) {
if (arr[i] <= arr[j]) {
tmp[k++] = arr[i++];
}
else {
tmp[k++] = arr[j++];
}
}
while (i <= mid) {
tmp[k++] = arr[i++];
}
while (j <= r) {
tmp[k++] = arr[j++];
}
for (i = l, k = 0; i <= r; i++, k++) {
arr[i] = tmp[k];
}
}

归并排序用于求逆序对#

long long ans = 0;
void mgs(vector<int>& arr, int l, int r) {
static vector<int> tmp(arr.size());
if (l >= r) return;
int mid = (l + r) / 2;
mgs(arr, l, mid), mgs(arr, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r) {
if (arr[i] <= arr[j]) { // 注意这里必须是小于等于
tmp[k++] = arr[i++];
}
else {
tmp[k++] = arr[j++];
ans += mid - i + 1; // 添加的一行
}
}
while (i <= mid) {
tmp[k++] = arr[i++];
}
while (j <= r) {
tmp[k++] = arr[j++];
}
for (i = l, k = 0; i <= r; i++, k++) {
arr[i] = tmp[k];
}
}

二分查找#

bool check(int a);
void bs(const vector<int>& arr) {
int n = arr.size();
int l = -1;
int r = n;
while (r - l > 1) {
int mid = (l + r) / 2;
if (check(arr[mid])) {
l = mid;
}
else {
r = mid;
}
}
return;
}
// 实数域二分
const double PCS = 1e-7;
bool check(double a);
double bs(double n, double l, double r) {
while (r - l > PCS) {
double mid = (l + r) / 2;
if (check(mid)) {
l = mid;
}
else {
r = mid;
}
}
return l;
}

主定理(master公式)#

用于求解分治算法的时间复杂度.

T(n)=aT(nb)+f(n)T(n) = aT(\frac{n}{b}) + f(n)

我们去比较f(n)f(n)nlogban^{\log_ba}, 分为如下几种情况:

  1. f(n)<nlogbaf(n) < n^{\log_ba}, 则时间复杂度由递归主导, T(n)=O(nlogba)T(n) = O(n^{\log _b a})
  2. f(n)=nlogbaf(n) = n^{\log_ba}, 则时间复杂度由递归部分与非递归部分共同影响, T(n)=O(nlogbalogn)T(n) = O(n^{\log _b a}\log n). 需要注意logn\log n不算阶数.
  3. f(n)>nlogbaf(n) > n^{\log_ba}, 同时满足正则条件af(nb)cf(n)af(\frac{n}{b}) \le cf(n)(通常竞赛题目都满足), 则时间复杂度由非递归主导, T(n)=O(f(n))T(n) = O(f(n))
竞赛算法(2) 排序, 二分
https://fuwari.vercel.app/posts/竞赛算法2-排序/
作者
ykindred
发布于
2025-10-09
许可协议
CC BY-NC-SA 4.0