插入与冒泡排序(C++)
\一、插入排序
1 简介
插入排序,也称为直接插入排序,其排序思想和我们平时打扑克牌时排序类似。
2 算法步骤
将第一个元素看作已排序序列,第二个到最后一个看作未排序序列。
第二个元素,与之前已排序号的序列进行对比,插入正确的位置(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
循环处理剩下的未排序序列。
效果图:
3 复杂度
当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较一下就可以了,这时一共需要比较N- 1次,最优时间复杂度为O(n)
最坏的情况是待排序数组是逆序的,此时需要比较次数最多,总次数记为:1+2+3+…+N-1,所以,插入排序最坏情况下的时间复杂度为O(n^2)
空间复杂度为O(1)
4 稳定性
稳定的,数据的相对顺序不会发生改变。
5 代码实现:略
二、冒泡排序
1 简介
冒泡排序(Bubble sort),是一种简单的排序算法。
它重复地循环要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
2 算法步骤
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
效果图:
3 复杂度
若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数 和记录移动次数 均达到最小值: 所以,冒泡排序最好的时间复杂度为O(n)。
若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
冒泡排序的最坏时间复杂度为O(n^2)
综上,因此冒泡排序总的平均时间复杂度为O(n^2)
空间复杂度为O(1)
4 稳定性
冒泡排序是稳定排序,不会改变数据的大小相对位置;
5 代码实现:略
第1题 插入排序(程序填空)
输入N个整数,使用插入排序法从小到大输出。
输入格式
第一行1个正整数:N,范围在[1,1000]。
第二行N个整数,每个整数范围在[0,1000000]。
输出格式
一行N个从小到大的整数。
输入/输出例子1
输入:
4
5 3 6 1
输出:
1 3 5 6
输入/输出例子2
输入:
4 5 5 1 9
输出:
1 5 5 9
第1空:
a[i]
第2空:
a[k]<temp
第3空:
a[j+1]=a[j]
第1题 冒泡排序(程序填空)
输入N个整数,使用冒泡排序法从小到大输出。
输入格式
第一行1个正整数:N,范围在[1,1000]。
第二行N个整数,每个整数范围在[0,1000000]。
输出格式
一行N个从小到大的整数。
输入/输出例子1
输入:
4
5 3 6 1
输出:
1 3 5 6
输入/输出例子2
输入:
4
5 5 1 9
输出:
1 5 5 9
第1空
n-i
第2空
a[j]>a[j+1]
第3空
a[j]
第4空
a[j+1]
第1题 插入排序 查看测评数据信息
输入N个整数,使用插入排序法从小到大输出。
输入格式
第一行1个正整数:N,范围在[1,1000]。
第二行N个整数,每个整数范围在[0,1000000]。
输出格式
一行N个从小到大的整数。
输入/输出例子1
输入:
4
5 3 6 1
输出:
1 3 5 6
输入/输出例子2
输入:
4
5 5 1 9
输出:
1 5 5 9
#include<bits/stdc++.h>
using namespace std;
long long n,i,j,k,temp,a[100005];
int main(){
cin>>n;
for(i=1;i<=n;i++)cin>>a[i];
for(i=2;i<=n;i++){
temp=a[i];
k=1;
while(a[k]<temp&&k<i){
k++;
}
for(j=i-1;j>=k;j--){
a[j+1]=a[j];
}
a[k]=temp;
}
for(i=1;i<=n;i++){
cout<<a[i]<<" ";
}
return 0;
}
第2题 冒泡排序 查看测评数据信息
输入N个整数,使用冒泡排序法从小到大输出。
输入格式
第一行1个正整数:N,范围在[1,1000]。
第二行N个整数,每个整数范围在[0,1000000]。
输出格式
一行N个从小到大的整数。
输入/输出例子1
输入:
4
5 3 6 1
输出:
1 3 5 6
输入/输出例子2
输入:
4
5 5 1 9
输出:
1 5 5 9
#include<bits/stdc++.h>
using namespace std;
long long n,i,j,a[100005];
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
}
for(i=1;i<n;i++){
for(j=1;j<=n-i;j++){
if(a[j]>a[j+1]){
swap(a[j],a[j+1]);
}
}
}
for(i=1;i<=n;i++){
cout<<a[i]<<" ";
}
return 0;
}
第3题 排名(rank) 查看测评数据信息
期中考试后,陈老师想对同学们的成绩进行排名。共有 n 名同学,按成绩从高到低进行排名,同分的同学排名相同。陈老师希望你能帮他把名次排出来。
输入格式
第一行一个正整数,n。
第二行 n 个用空格隔开的范围为[0..100]的整数,表示 n 名同学的成绩。
输出格式
n 行,每行两个正整数,分别表示一个成绩和该成绩的排名,从高到低的输出。
输入/输出例子1
输入:
10
89 83 88 84 85 88 87 85 90 88
输出:
90 1
89 2
88 3
88 3
88 3
87 6
85 7
85 7
84 9
83 10
样例解释
【数据范围】
100%的数据 1<=n<=100
#include<bits/stdc++.h>
using namespace std;
long long n,i,j,k,temp,a[100005],b[100005];
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
}
for(i=1;i<n;i++){
for(j=1;j<=n-i;j++){
if(a[j]<a[j+1]){
swap(a[j],a[j+1]);
}
}
}
for(i=1;i<=n;i++){
b[i]=i;
}
for(i=1;i<n;i++){
if(a[i]==a[i+1]){
b[i+1]=b[i];
}
}
for(i=1;i<=n;i++){
cout<<a[i]<<" "<<b[i]<<'\n';
}
return 0;
}
第4题 交换次数 查看测评数据信息
输入N个整数,如果每次只能交换相邻的2个数,要把数组从小到大排序,至少需要交换几次?
输入格式
第一行1个正整数:N,范围在[1,1000]。
第二行N个整数,每个整数范围在[0,1000000]。
输出格式
一行N个从小到大的整数。
输入/输出例子1
输入:
4
5 3 6 1
输出:
4
#include<bits/stdc++.h>
using namespace std;
long long n,i,j,a[100005],s;
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
}
for(i=1;i<n;i++){
for(j=1;j<=n-i;j++){
if(a[j]>a[j+1]){
swap(a[j],a[j+1]);
s++;
}
}
}
cout<<s;
return 0;
}
第5题 兔子 查看测评数据信息
明明家养了N只兔子,边上种植了很多胡萝卜。平时兔子都被关在一个大笼子里,每天明明喂每只兔子3根胡萝卜。
某天饿疯了的兔子们咬坏了笼子门,跑到地里尽情地吃起胡萝卜。每只兔子的“吃货值”不一样,已知第i只兔子每分钟吃Ei个胡萝卜。
明明1分中后发现了情况,急忙开始捉拿这些兔子,已知明明每分钟可以捉一只,请问明明怎样捉才能使得被兔子吃最少的胡萝卜。计算出被兔子吃最少胡萝卜的个数。
例如:N=2, E1=4,E2=5;明明第1个捉第2个兔子(这个兔子已经吃了5根胡萝卜),第2个捉第1个兔子(这个兔子已经吃了8根胡萝卜),共被兔子吃了13根胡萝卜。
输入格式
第一行: 1 个正整数 N。N的范围[1…10000]
第二行 N 个正整数: 表示 N 只兔子每分钟可以吃的胡萝卜数,每个数的范围[1…1000000]。
输出格式
一个整数,表示最少要被吃掉多少胡萝卜。
输入/输出例子1
输入:
3
2 1 3
输出:
10
#include<bits/stdc++.h>
using namespace std;
bool f(int a,int b){
return a>b;
}
long long n,a[100005],h=0,t=0,s=0;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+1+n,f);
for(int i=1;i<=n;i++){
t++;
s=s+a[i]*t;
}
cout<<s;
return 0;
}
第6题 第K小数 knumber 查看测评数据信息
现有n个正整数,n<=10000,要求出这n个正整数中的第k个最小整数(相同大小的整数只计算一次),k<=1000,正整数均小于30000。
输入格式
第一行为n和k,第二行开始为n个正整数的值,整数间用空格隔开。
输出格式
第k个最小正整数的值;若无解,则输出“NO RESULT”。
输入/输出例子1
输入:
10 3
1 3 3 7 2 5 1 2 4 6
输出:
3
#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],k;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
int len=unique(a+1,a+n+1)-a;
if(k<len)cout<<a[k];
else cout<<"NO RESULT";
return 0;
}
第7题 火柴 (GCOI2015五4) 查看测评数据信息
有N根火柴,第i根火柴的长度是Li。小明很喜欢正方形,所以小明希望用这些火柴拼出尽量多的正方形,但要同时满足如下条件:
1、一根火柴最多只能用在一个正方形中。
2、组成正方形的四根火柴,长度必须都相同。
给出N根火柴的长度,你的任务是计算:最多可以拼出多少个正方形?
输入格式
第一行,一个整数N。
第二行,N个整数,第i个整数是Li。
输出格式
一个整数,表示最多能拼出的正方形的数量
输入/输出例子1
输入:
7
1 1 2 2 1 1 2
输出:
1
输入/输出例子2
输入:
20
1 2 3 4 1 2 3 4 1 2 3 1 2 3 4 1 2 3 3 3
输出:
3
样例解释
样例1解释:只能拼出1个正方形,正方形的边长是1。样例2解释:能拼出3个正方形,正方形的边长是1、2、3。
【数据规模】 对于60%的数据, 4 <= N <= 50, 1 <= Li <= 1000。 对于100的数据,4 <= N <= 5000,1 <= Li <= 1000000000。
#include<bits/stdc++.h>
using namespace std;
long long int a[500005],i,j,n,s=0,sum,b[500005];
int main(){
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b,b+n);
long long m=0,k=1;
while(k<n){
if(b[k]!=b[m]) b[++m]=b[k];
k++;
}
for(i=0;i<m+1;i++){
sum=0;
for(j=0;j<n;j++){
if(b[i]==a[j])sum++;
}
s=sum/4+s;
}
printf("%d",s);
return 0;
}
第8题 奖学金(scholar) 查看测评数据信息
某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。期末,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学排在前面,这样,每个学生的排序是唯一确定的。
任务:先根据输入的3门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名学生的学号和总分。注意,在前5名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。例如,在某个正确答案中,如果前两行的输出数据(每行输出两个数:学号、总分) 是:
7 279
5 279
这两行数据的含义是:总分最高的两个同学的学号依次是7号、5号。这两名同学的总分都是 279 (总分等于输入的语文、数学、英语三科成绩之和) ,但学号为7的学生语文成绩更高一些。如果你的前两名的输出数据是:
5 279
7 279
则按输出错误处理,不能得分。
输入格式
输入数据包含n+1行:
第1行为一个正整数n,表示该校参加评选的学生人数。
第2到n+1行,每行有3个用空格隔开的数字,每个数字都在O到100之间。第j行的3个数字依次表示学号为j-1的学生的语文、数学、英语的成绩。每个学生的学号按照输入顺序编号为l~n (恰好是输入数据的行号减1)。
所给的数据都是正确的,不必检验。
输出格式
输出数据共有5行,每行是两个用空格隔开的正整数,依次表示前5名学生的学号和总分。
输入/输出例子1
输入:
6
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98
输出:
6 265
4 264
3 258
2 244
1 237
输入/输出例子2
输入:
8
80 89 89
88 98 78
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98
输出:
8 265
2 264
6 264
1 258
5 258
样例解释
【限制】
50%的数据满足:各学生的总成绩各不相同;
100%的数据满足: 6≤n≤300。
#include<bits/stdc++.h>
using namespace std;
struct node{
int chinese,maths,English,zongfen,id;
}a[330];
int main(){
int n,i,j;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i].chinese>>a[i].maths>>a[i].English;
a[i].id=i;
a[i].zongfen=a[i].chinese+a[i].maths+a[i].English;
}
for(i=n-1;i>=1;i--){
for(j=1;j<=i;j++){
if(a[j].zongfen<a[j+1].zongfen)swap(a[j],a[j+1]);
else if((a[j].zongfen==a[j+1].zongfen)&&(a[j].chinese<a[j+1].chinese))swap(a[j],a[j+1]);
else if((a[j].zongfen==a[j+1].zongfen)&&(a[j].chinese==a[j+1].chinese)&&a[j].id>a[j+1].id)swap(a[j],a[j+1]);
}
}
for(i=1;i<=5;i++)cout<<a[i].id<<" "<<a[i].zongfen<<endl;
return 0;
}
第1题 分数线划定 (score) 查看测评数据信息
世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A 市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%划定,即如果计划录取m名志愿者,则面试分数线为排名第m*150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。
现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。
提示:向下取整,即把小数部分去掉。例如:4.3和4.8向下取整都是4。
输入格式
第一行,两个整数n,m(5 ≤ n ≤ 5000,3 ≤ m ≤ n),中间用一个空格隔开,其中n 表示报名参加笔试的选手总数,m 表示计划录取的志愿者人数。输入数据保证m*150%向下取整后小于等于n。
第二行到第 n+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号k(1000 ≤ k ≤ 9999)和该选手的笔试成绩s(1 ≤ s ≤ 100)。数据保证选手的报名号各不相同。
输出格式
第一行,有两个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。
从第二行开始,每行包含两个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。
输入/输出例子1
输入:
6 3
1000 90
3239 88
2390 95
7231 84
1005 95
1001 88
输出:
88 5
1005 95
2390 95
1000 90
1001 88
3239 88
#include<bits/stdc++.h>
using namespace std;
long long n,m,b[1000550],a[1000550],i,j,sum,ans=0;
int main(){
cin>>n>>m;
for(i=0;i<n;i++){
cin>>b[i]>>a[i];
}
for(i=1;i<=n-1;i++){
for(j=0;j<=n-i;j++){
if(a[j]<a[j+1]){
swap(a[j],a[j+1]);
swap(b[j],b[j+1]);
}
if(a[j]==a[j+1]){
if(b[j]>b[j+1]){
swap(a[j],a[j+1]);
swap(b[j],b[j+1]);
}
}
}
}
m=double(m*1.5);
sum=a[m-1];
for(i=0;i<n;i++){
if(a[i]>=sum)ans++;
else break;
}
cout<<sum<<" "<<ans<<'\n';
for(i=0;i<ans;i++){
cout<<b[i]<<" "<<a[i]<<'\n';
}
return 0;
}
第2题 2015GCOI六5 最大数 查看测评数据信息
计时器游戏结束后,晨晨的同学明明取了其中的N个计时器设计出拼数字游戏:明明和晨晨各自把N个计时器排成一行,看谁拼出的数最大。例如:有N=3个计时器,上面数字分别是31,3,331,两人拼的方案分别是:
明明拼的数字是333131,晨晨拼的数字是331313,显然明明赢。明明掌握了拼出最大值的核心算法,晨晨下决心也要研究。
输入格式
第一行:1个整数N。
第二行N个整数:表示N个计时器上的数。
输出格式
一个整数,表示拼成的最大数字。
输入/输出例子1
输入:
3
31 3 331
输出:
333131
输入/输出例子2
输入:
8
73 1 3 776 12 225 4 936
输出:
9367767343225121
样例解释
30%的数据,n<=10,每个数<10^3。
50%的数据,n<=100。
100%的数据,n<=1000,每个数<10^200。
#include<bits/stdc++.h>
using namespace std;
string a[100005];
int n;
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(a[i]+a[j]<a[j]+a[i]){
swap(a[i],a[j]);
}
}
}
for(int i=0;i<n;i++){
cout<<a[i];
}
return 0;
}
第3题 拯救花园(nhoixj2013) 查看测评数据信息
一天,晨晨发现自己的n(2≤n≤100)只兔子跑到自己的花园里面,它们在尽情的吃着她的宝贝花卉。晨晨看在眼里痛在心里,她现在只能把兔子逐个的抓回笼子里面。而送每只兔子回去的时间都不同,例如送第i只兔子回去需要ti(1≤ti≤100)单位时间,那么晨晨送第i只兔子来回共需要花费2*ti单位时间,另外每一只兔子单位时间的破坏力都不同,例如第i只兔子单位时间内破坏di (1≤di≤100)朵花。
现在的问题是,晨晨如何安排送这n只兔子回笼子才能使这些兔子的破坏最小。
输入格式
第一行:一个整数n(1≤n≤100);
接着有n行,每行两个空格分开的整数ti di,分别代表第i只兔子的送回去的时间,和单位时间破坏力。
输出格式
一行:一个整数,代表这些兔子破坏多少花卉。
输入/输出例子1
输入:
6
3 1
2 5
2 3
3 2
4 1
1 6
输出:
86
样例解释
样例解释:
晨晨送兔子回去的顺序分别为:6, 2, 3, 4, 1, 5。其中先送第6只兔子回去,剩余兔子破坏(1+5+3+2+1)*2=24朵花;送第2只兔子回去,剩余兔子破坏(1+3+2+1)*4=28朵花;以此类推,送第3、4、1只兔子回去剩余兔子的破坏分别为16、12和6朵花;最后送第5只兔子回去的时候,没有兔子在花园里面了,所以破坏0朵花,最后总共破坏24 + 28 + 16 + 12 + 6 = 86朵花。
#include<bits/stdc++.h>
using namespace std;
int n,x,s;
struct str{
int s1,s2;
}a[1000005];
bool f(str q,str p){
return p.s1*q.s2<q.s1*p.s2;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].s2>>a[i].s1;
}
for(int i=1;i<=n;i++){
s+=a[i].s1;
}
sort(a+1,a+1+n,f);
for(int i=1;i<=n;i++){
s-=a[i].s1;
x+=s*a[i].s2*2;
}
cout<<x;
return 0;
}
制作不易,点个三连(#^.^#)