1.排序
1.1快速排序—分治的思想
在下图所示中,左端点为l
,右端点为r
。
快排思想
1.确定分界点x
2.划分,根据选取的分界点x
将数组划分成小于x
的部分和大于x
的部分
3.递归求解小于x
和大于x
的部分
代码实现:
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int q[N];
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1;//与后面写法有关,先移动指针,再进行判断
int 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, 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;
}
C++STL实现
#include <bits/stdc++.h>
using namespace std;
const int N=1000000+100;
int a[N],n,m,i,j;
int main()//C++ Stl使人快乐
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
cout<<endl;
}
1.2归并排序
归并在此使用双指针算法
归并排序是稳定的(位置不发生变化)。
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1000010;
int n;
int q[N],tmp[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]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
while(i <= mid) tmp[k++] = q[i++];
while(j <= r) tmp[k++] = q[j++];
//把数拿回来
for(int i = l,j = 0; i <= r;i++,j++) q[i] = tmp[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;
}
2.二分
2.1整数二分
所谓的二分算法,就是我们知道当前的候选区间中,一定存在我们要找到的答案,而且我们发现这个区间拥有单调性质此类的性质,那么我们可以不停地缩减候选区间的范围,达到排除无用答案的效果.二分本质查找分届点。
2.1.1二分左边点
为什么要+1???
答:若
l
=
r
−
1
l = r - 1
l=r−1则
m
i
d
=
(
l
+
l
−
1
)
/
2
mid = (l + l -1)/ 2
mid=(l+l−1)/2结果还是
l
l
l,在此我们会陷入死循环。 所以我们必须补上加1.
2.1.2二分右边点
2.1.3小结
例题:数的范围
图示:
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
int n,m;
int q[N];
int main()
{
scanf("%d%d",&n,&m);
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;
}
//当while循环退出的时候l == r
if(q[l] != x) cout<<"-1 -1"<<endl;
else
{
cout<<l<<" ";//输出左半边,这里即可输出l又可输出r,
//因为上一个循环退出条件为l=r
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<<l<<endl;
}
}
return 0;
}