快速排序
特点:分治思想
方法:
设立一个基准值,可以在左边界,可以是右边界,也可以是中间值
然后利用双指针、数组分成两区间,左边小于基准值,右边大于基准值
下一步,循环迭代。
#include <iostream>
using namespace std;
const int N = 1000010;
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[l + r >> 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()
{
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]);
return 0;
}
注意:一定要注意边界问题;
归并排序(双路归并)
特点:分治思想
方法: 实现:首先确定中值mid,
其次递归到底;
然后双路归并,合二为一。
#include <iostream>
using namespace std;
const int N=100010;
int n;
int q[N],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 k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
if(q[i]>=q[j]) temp[k++]=q[j++];
else temp[k++]=q[i++];
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
merge_sort(q,0,n-1);
for(int i=0;i<n;i++) printf("%d ",q[i]);
return 0;
}
注意:
二者排序算法的时间效率都是n*log2n,时间与sort库函数相差无几
二分
整数二分:
区间里可以找到一个性质,可以用二分把边界点二分出来, 使得把使得整个长度一分为二,二分绿色和红色,就是两个不同的模板。
注意:1.需要考虑边界问题
2. 二分算法得出的结果一定是有解的,不存在无解的情况。只是结果或许存在相对题目 而言无解的存在
整数二分例题:数的范围
给定一个按照升序排列的长度为 nn 的整数数组,以及 qq 个查询。
对于每个查询,返回一个元素 kk 的起始位置和终止位置(位置从 00 开始计数)。
如果数组中不存在该元素,则返回
-1 -1
。输入格式
第一行包含整数 nn 和 qq,表示数组长度和询问个数。
第二行包含 nn 个整数(均在 1∼100001∼10000 范围内),表示完整数组。
接下来 qq 行,每行包含一个整数 kk,表示一个询问元素。
输出格式
共 qq 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回
-1 -1
。数据范围
1≤n≤1000001≤n≤100000
1≤q≤100001≤q≤10000
1≤k≤10000输入样例:
6 3 1 2 2 3 3 4 3 4 5
输出样例:
3 4 5 5 -1 -1
#include <iostream>
using namespace std;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int q[n];
for(int i=0;i<n;i++) scanf("%d",&q[i]);
while(m--){
int x;
scanf("%d",&x);
int l=0,r=n-1;
while(l<r)
{
int mid=l+r>>1;
if(q[mid]>=x) r=mid;
else l=mid+1;
}
if(x!=q[l]) cout<<"-1 -1"<<endl;
else
{ cout<<l<<" ";
int l=0,r=n-1;
while(l<r)
{
int mid=l+r+1>>1;
if(q[mid]<=x) l=mid;
else r=mid-1;
}
cout<<r<<endl;
}
}
return 0;
}
浮点二分例题:数的三次方根
注意:浮点二分不需要考虑边界问题
给定一个浮点数 nn,求它的三次方根。
输入格式
共一行,包含一个浮点数 nn。
输出格式
共一行,包含一个浮点数,表示问题的解。
注意,结果保留 66 位小数。
数据范围
−10000≤n≤10000−10000≤n≤10000
输入样例:
1000.00
输出样例:
10.000000
#include <iostream>
using namespace std;
int main()
{
double x;
cin>>x;
double l=-1000,r=1000;
while(r-l>1e-8)
{
double mid=(l+r)/2;
if(mid*mid*mid>=x) r=mid;
else l=mid;
}
printf("%.6lf",l);
return 0;
}