快排属于分治算法,分治算法都有三步:
- 分成子问题
- 递归处理子问题
- 子问题合并
题目:
请你使用快速排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。
输入格式 输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在 1∼109 范围内),表示整个数列。
输出格式: 输出共一行,包含 n 个整数,表示排好序的数列。
数据范围 1≤n≤100000 >
输入样例: 5 3 1 2 4 5
输出样例: 1 2 3 4 5
图片中轴取的是左部,代码中是中间
原理:分治思想
选择一个中轴数,将所有小于中轴数的数放在左面,大于中轴数的数放在右面。
用递归的方式,将两个被分割的数组重复同样的操作,直到数组为1。
本来需要在数组外开辟额外空间用于存储左部和右部,通过以下方式可以规避这一点:
注意事项:
1.为什么初始值i = l - 1, j = r + 1?
每次i和j会向中间移动1(i++, j –).作为偏移量。
下面是我一次错误的代码及其解决:
#include <iostream>
using namespace std;
const int N = 100010;
int q[N];
void quick_sort(int* q, int l, int r)
{
if (l >= r)
return;
int i = l - 1, j = r + 1, x = q[i + j >> 1];
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, j + 1, r);
}
int main(void)
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &q[i]);
}
quick_sort(q, 0, n - 1);
for (int i = 0; i < n; i++)
{
printf("%d ", q[i]);
}
}
错误实例如下:
10
49 59 88 37 98 97 68 54 31 3
输出
3 37 49 59 88 31 54 68 97 98
标准答案
3 31 37 49 54 59 68 88 97 98
还有一些判例MLE。
错误原因:
在i移动之前,需要判断i是否在j左边
正确答案:
#include <iostream>
using namespace std;
const int N = 100010;
int q[N];
void quick_sort(int* q, int l, int r)
{
if (l >= r)
return;
int i = l - 1, j = r + 1, x = q[(i + j) >> 1];
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, j + 1, r);
}
int main(void)
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &q[i]);
}
quick_sort(q, 0, n - 1);
for (int i = 0; i < n; i++)
{
printf("%d ", q[i]);
}
}
感悟:
自己的debug能力有所欠缺。
这套课程上学期就买了,直到现在也没有啃下来。原因有以下几点:
1.y总的代码思维要求比较高,内容简单,思想抽象,自己不加以思考就原封不动地抄下来,事实证明这样是不行的。宁可学习速度没那么快,也要好好领悟其思想。
2.自己比较懒。这一点是大学两年来自己最大的错误。总是不能坚持下来,到头来什么也干不成。
目标:
领悟每一道题的思想,自己动手写一遍,写在博客上进行总结。
自己一定要多练啊,再不练就真混到毕业了。