快速排序
图解
先找到左哨兵作为基准数,右哨兵移动到比基准数小的数,左哨兵再移动到比右哨兵大的数。
交换两个数
重复上述过程,直到两哨兵相遇
相遇后将基准数与本数交换
这样就完成了第一轮交换,可以发现基准数已归位且在基准数左侧的数都比基准数小,右侧的数都比基准数大。只需分左右依次递归即可。
递归树
模板代码
void qsort(int l,int r){
if(l>=r) return;
int sol=a[l];
int i=l,j=r;
while(i!=j){
while(a[j]>=sol&&i<j)j--;
while(a[i]<=sol&&i<j) i++;
if(i<j) swap(a[i],a[j]);
}
swap(a[l],a[i]);
qsort(l,i-1);
qsort(i+1,r);
}
例子
- 第k小数1
题目描述
对于给定的n个元素的无序数组,要求从中找出第k小的元素。
输入格式
第一行是总数n(1<n<100000)和k,第二行是n个待比较元素。
输出格式
第k小的数在数组中的位置(若有多个,请输出最左边的元素位置)。
样例输入
5 3
25 9 90 57 3
样例输出
1
只需将模板改为
void qsort(int l,int r){
int sol=a[l];
int i=l,j=r;
while(i!=j){
while(a[j]>=sol&&i<j)j--;
while(a[i]<=sol&&i<j) i++;
if(i<j) swap(a[i],a[j]);
}
swap(a[l],a[i]);
if(k==i){
p=a[i];
return;
}
else if(k<i) qsort(l,i-1);
else qsort(i+1,r);
}
因为我们只需第k小数,比k大或小不需要浪费时间去递归
- 第k小数2通上
题目描述
对于两个有序数组a[n]和 a[m] (1<n,m<100000),找出第k小的数。
输入格式
第一行三个整数n,m,k。
第二行是第一个有序数组的n个元素。
第三行是第二个有序数组的m个元素。
输出格式
第k小的数。
样例输入
6 7 6
786 3891 4258 4694 7130 7899
357 720 1292 2579 7889 9255 9611
样例输出
3891
只需将两组输入合并即可
归并排序
图解
第一步将原数组对半分,直到只剩下一个元素时停止。
第二步将分开的数组依次已小在前合并
模板代码
void merge(int head,int tail){
int mid=(head+tail)/2;
int s=head,e=mid+1,k=0;
while(s<=mid&&e<=tail){
if(a[s]>a[e]) temp[k++]=a[e++];
else temp[k++]=a[s++];
}
while(s<=mid) temp[k++]=a[s++];
while(e<=tail) temp[k++]=a[e++];
k=0;
for(int i=head;i<=tail;i++) a[i]=temp[k++];
}
void m_sort(int head,int tail){
int mid=(head+tail)/2;
if(head<tail){
m_sort(head,mid);
m_sort(mid+1,tail);
merge(head,tail);
}
return;
}
例子
只需在合的过程中,只要这个数比另一个数小,那么比这个数小的数一定也比另一个数小,所以答案加上mid-s+1。
- 查找最大和次大元素
题目描述
对于给定的含有n元素的无序序列,求这个序列中最大和次大的两个不同的元素,序列保证没有相同的数字。
例如:(2, 5, 1, 4, 6, 3),最大元素为6,次大元素为5。
输入格式
输入有两行
第一行一个正整数n,表示序列中数字的数量
第二行有n个空格分开的整数,表示这个序列中的数字
输出格式
输出由两个空格隔开的数字,第一个表示最大值,第二个表示次大值
样例输入
6
2 5 1 4 6 3
样例输出
6 5
void f(int l,int r,int &max1,int &max2