本文用于记录个人算法竞赛学习,仅供参考
一.快速排序(升序为例)
思想:确定分界点x,将小于分界点的值放在分界点的左边,将大于分界定的值放在分界点的右边,再递归处理两边的左右区间。
步骤:
1.确定分界点:分界定的确定是随机的,一般取中间点(mid)和左右(L,R)边界点
2.调整区间:将小于分界点的值放在分界点的左边,将大于分界定的值放在分界点的右边(降序相反)
3.递归:递归处理左右两边,重复上述操作
调整区间的实现方式:
1.可以开辟两个空间来存放分界点的值,然后再拷贝回去,但这样会额外消耗空间
2.双指针法:L为左边界,R为右边界,用i 从L出发,用j 从R出发,i 向前遍历,直到遇到大于分界点x 的值并停下来,j 向后遍历,直到遇到小于x 的值并停下来,接着i 与j 指向的值交换,再继续重复上述操作直到i 与 j 相遇。
快排模板--O(N*logN)
void quick_sort(int q[], int l, int r)
{
//只剩一个数,就不需要再操作了
if (l >= r) return;
//这里-1和+1是因为后面的do while操作
int i = l - 1, j = r + 1;
int x = q[(l + r) >> 1];
while (i < j)
{
do i++;
while (q[i] < x);
do j--;
while (q[j] > x);
//这里需要判断,因为有可能会出现i == j
if (i < j)
swap(q[i], q[j]);
}
//递归左右两边
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
二.归并排序(升序为例)
思想:将两个有序数组合并成一个有序数组,那么归并排序整体就是先递归排序,再将有序数组合并成一个数组
步骤:
1.确定分界定:mid = (l + r) >> 1;
2.递归排序左边和右边
3.将两个有序的数组合并成一个数组--双指针遍历两个数组比较大小
归并模板--O(N*logN)
const int N = 100010;
int temp[N];
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = (l + r) >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
//合并
int index = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
{
if (q[i] < q[j]) temp[index++] = q[i++];
else temp[index++] = q[j++];
}
while (i <= mid) temp[index++] = q[i++];
while (j <= r) temp[index++] = q[j++];
//拷贝回去
for (i = l, index = 0; i <= r; i++,index++)
{
q[i] = temp[index];
}
}