排序算法
算法思想-分治。确认分界点,不断调整区间,使得分界点的左边全部小于分界点,右边全部大于分界点,递归处理左右两段区间直至全部有序。
使用两个指针不断向中间位置(实际上是分界点)逼近,知直到确定分界点的位置。
模板:
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[(l + r ) /2];
while (i < j)
{
do i++; while (q[i] < x);//找到左边第一个比分界点大的位置
do j--; while (q[j] > x);//找到右边第一个比分界点小的位置
if (i < j) swap(q[i], q[j]);//交换两个位置的值
}//继续向分界点位置靠近
quick_sort(q, l, j); // quick_sort(q, l, i-1);模拟后可以发现i和j的位置,每次能确定一个数的位置
quick_sort(q, j + 1, r); // quick_sort(q, i, r);
}
常规代码:
void Quick_Sort(int a[], int low, int high) {
if (low > high)
return;
int pivot = a[low];
int i = low;
int j = high;
while (i != j) {//不断交换左边比枢纽大的值和右边比枢纽小的值,循环结束后i和j的值应当为i>=j
while (a[j] >= pivot && j > i)
j--;
while (a[i] <= pivot && j > i)
i++;
if (j > i) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
a[low] = a[i];//i指向的为比枢纽小的值,此时循环结束后i左边应当都是比枢纽小的值,交换位置后可确定枢纽排序后的位置
a[i] = pivot;
Quick_Sort(a, low, i - 1);
Quick_Sort(a, i + 1, high);
}
归并算法
算法思想:分治。确定分界点,递归排序左边和右边,得到两个有序的小区间,归并整个数组。难点在如何合并两个已经有序的数列。
双路归并,合二为一。
模板:
void mergesort(int a[], int low, int high) {
if (low >= high) return;
int mid = (low + high) / 2;
mergesort(a, low, mid);
mergesort(a, mid + 1, high);
int temp[N];
int k = 0, i = low, j = mid+1;
while (i <= mid && j <= high) {
if (a[i] <= a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while (i <= mid) temp[k++] = a[i++];
while (j <= high) temp[k++] = a[j++];
for (int i = low, j = 0; i <= high;) a[i++] = temp[j++];
}
二分查找
算法思想:二分查找复合某个条件的元素值
二分本质是用来查找满足某种性质的边界点
在给定区间内,能找到某种性质使得区间分为两部分,一部分满足,另外一部分不满足这种性质,
二分就可以用来寻找这个性质的边界:满足某种性质的第一个元素;或者是满足某种性质的最后一个元素。
从而有两个不同模板。
注意二分法一定能找到满足某种性质的边界点,但它不一定是你要找的目标,目标不一定在区间内
先写check函数,如何根据check函数更新区间,再判断选用哪个模板
主要是边界问题
模板:
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
浮点数二分
模板
bool check(double x) {/* ... */} // 检查x是否满足某种性质
double bsearch_3(double l, double r)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
也可以直接循环一百次,不用while循环