某csdn大佬推荐的新手刷题网站,快速入门!洛谷
新手入门刷题(专题二)排序———>持续更新
4.5
【深基9.例1】选举学生会
题目描述
学校正在选举学生会成员,有 n ( n ≤ 999 ) 名候选人,每名候选人编号分别从 1 到 n,现在收集到了 m (m ≤ 2000000 ) 张选票,每张选票都写了一个候选人编号。现在想把这些堆积如山的选票按照投票数字从小到大排序。
输入格式
输入 n和 m以及 m个选票上的数字。
输出格式
求出排序后的选票编号。
输入样例
5 10
2 5 2 2 5 2 2 2 1 2
输出样例
1 2 2 2 2 2 2 2 5 5
思路
上去就无脑冒泡,结果TLE感动了,本题正确思路是采用计数排序
代码
#include<iostream>
using namespace std;
int a[2000];
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++){
int t;
cin>>t;
a[t]++;
}
int flag=0;
for(int i=1;i<=n;i++){
for(int j=0;j<a[i];j++){
if(flag++) cout<<' ';
cout<<i;
}
}
return 0;
}
【模板】快速排序
题目描述
略
思路
每次迭代确保k值左边 <= k ,k 值右边 >= k, 即,每轮下来,确定一个k值的位置,快排模板是一定要记住的!!
这里简单记录一下位运算,>> 代表 右移
比如 6 的二进制为 0110,将其右移一位,变成 0011,即 3,因此 >>1 可以理解为 /2
代码
#include<iostream>
using namespace std;
int a[100010];
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",&a[i]);
}
quick_sort(a,0,n-1);
for(int i=0;i<n;i++){
if(i<n-1){
printf("%d ",a[i]);
}else{
printf("%d",a[i]);
}
}
return 0;
}
【深基9.例4】求第 k 小的数
题目描述
略
思路
无论是求第k小数还是第k大数,都是快排的延伸,我们知道快排一轮可以确定一个数的位置,进行迭代的过程,我们只需要知道第k小数在该数字的左边还是右边,然后迭代单边即可,记住快排模板,加以改进即可。
代码
#include <iostream>
using namespace std;
const int N = 5000010;
int q[N];
//该模板是从第1个数开始的
int quick_sort(int q[], int l, int r, int k)
{
if (l >= r) return q[l];
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]);
}
if (j - l + 1 >= k) return quick_sort(q, l, j, k);
else return quick_sort(q, j + 1, r, k - (j - l + 1));
}
int main(){
int n, k;
scanf("%d%d", &n, &k);
//题目要求从第0个数开始,因此k++
k++;
//如果求第k大数,只需赋值k为如下代码即可
//k = n-k+1;
for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
cout << quick_sort(q, 0, n - 1, k) << endl;
return 0;
}
[NOIP2006 普及组] 明明的随机数
题目描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N 个 1 到 1000 之间的随机整数 ( N ≤ 100 ),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。
思路
本题分为两步,第一步去重复,第二步排序,去重在输入过程中,遍历数组判断该数字是否存在即可
代码
#include <iostream>
using namespace std;
const int N = 110;
int q[N];
//排序直接用快排模板
int quick_sort(int q[], int l, int r)
{
if (l >= r) return q[l];
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;
int len=1;
scanf("%d", &n);
for (int i = 0; i < n; i ++ ){
int t;
scanf("%d", &t);
for(int j=0;j<len;j++){
//如果输入的数字在数组中已存在,跳出本次循环
if(q[j]==t) break;
//否则在数组尾部插入该数字,并调整数组长度+1,确保数组尾部总有一个值为0的数字等待插入
else if(q[j]==0){
q[j]=t;
len++;
break;
}
}
}
quick_sort(q, 0, len-2);
//数组实际长度为len-1,在数字插入操作时,为了确保数组尾部总有一个值为0的数字,数组长度故意+1
printf("%d\n", len-1);
for (int i = 0; i < len-1; i ++ ){
if(i<len-2) printf("%d ", q[i]);
else printf("%d", q[i]);
}
return 0;
}