排序
文章根据王道机试书进行学习。
空间时间复杂度须知
不同的编译环境(操作系统、编辑器),可能每个int所占的空间会不同,一般记忆一个int占32个bit,即4个字节。长度范围是-231 ~ 231 -1。
一秒的时间复杂度约等于一千万(10000000)
scanf的返回值问题
scanf是有返回值的,它的返回值是被输入函数成功赋值的变量个数。
EOF表示-1,意思是end of file,对于 scanf(“%d”,&n) 如果输入已经到达结尾(输入文件到达末尾或者在命令台中输入Ctrl+z),scanf函数无法再为变量n赋值,于是scanf函数返回EOF。
for循环中定义的变量作用域
C++标准指出,在for循环测试条件中定义的变量,其作用域仅限于for循环循环体内部(就像在for循环循环体内定义的局部变量)。而在VC6.0中则不同,在for循环退出后,指示变量i依旧可见,所以当我们在后续for循环循环条件中定义的新指示变量i会与该旧的指示变量i产生冲突,从而引发错误。
经典排序算法(冒泡、快排、Hash)
冒泡的时间复杂度O(n^2),空间复杂度O(n)
时间复杂度平均是O(nlogn),最多是O(n^2),最少O(nlogn)
冒泡
示例代码
//冒泡排序 ,从小到大
#include<stdio.h>
int main(){
int n;
int buf[100];//用这100个数的空间来保存排序的数
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%d",&buf[i]);
}//输入待排序数字
for(int i=0;i<n;i++){
for(int j=0;j<n-1-i;j++){
if(buf[j]>buf[j+1]){//从小到大判断部分
int tmp=buf[j];
buf[j]=buf[j+1];
buf[j+1]=tmp;
}
}
}//冒泡排序主体循环部分
for(int i=0;i<n;i++){
printf("%d ",buf[i]);
} //注意这里是每个数字后都有一个空格,如果不想要最后得到空格可以用定义一个first记号
printf("\n"); //一次结果后的换行
}
return 0;
}
快排
快排大致思想就是,选第一个点,把大于它的放到后面,小于它的放到前面。
可以利用直接利用内置快排t函数sort(algorithm包中),sort函数的两个参数代表待排序内存的起始地址和结束地址(sort函数还有另外的重载形式)
正序:
//利用c++中的快排库函数进行快速排序 ,从小到大
#include <stdio.h>
#include <algorithm>
using namespace std;
int main(){
int n;
int buf[10000];
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%d",&buf[i]);
}
sort(buf,buf+n);
for(int i=0;i<n;i++){
printf("%d ",buf[i]);
}
printf("\n");
}
return 0;
}
倒序:
//快排反序
#include <stdio.h>
#include <algorithm>
using namespace std;
bool cmp(int x,int y){//定义反向的排序规则
return x>y;
}
int main(){
int n;
int buf[100];
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%d",&buf[i]);
}
sort(buf,buf+n,cmp);//使用该重载形式,表示我们将要使用我们自己定义的排序规则
for(int i=0;i<n;i++){
printf("%d ",buf[i]);
}
printf("\n");
}
return 0;
}
Hash
将存储位置与数据本身对应起来的存储手段就是Hash。
问题描述:
时间限制1秒
给你n个证书,请按从小到大的顺序输出其中前m大的数。
输入:
每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n个各不相同,且都处于区间[-500000,500000]的整数。
示例代码:
#include <stdio.h>
#define OFFSET 500000//偏移量,补偿实际数字与数组之间的偏移
int Hash[1000001];
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=-500000;i<=500000;i++){
Hash[i+OFFSET]=0;//初始化
}
for(int i=0;i<n;i++){
int x;
scanf("%d",&x);
Hash[x+OFFSET]=1;//因为输入的数各不相同,只要标记出现过的就够了
}
for(int i=500000;i>=-500000;i--){
if(Hash[i+OFFSET]!=0){
printf("%d",i);
m--;
if(m!=0){
printf(" ");
}
else{
printf("\n");
break;
}
}
}
}
return 0;
}
自定义排序问题
问题描述:
给N个学术的数据,将数据按成绩高低排序,如果成绩相同则按照姓名字符的字母序排序,如果姓名的字母序也相同则按照学生的年龄排序,并输出N个同学排序后的信息。
示例代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
struct E{
char name[10];
int age;
int score;
}buf[1000];
bool cmp(E a,E b){
if (a.score!=b.score) return a.score<b.score;//升序
int tmp=strcmp(a.name,b.name);
if(tmp!=0) return tmp<0;//为了变成从小到大的升序
else return a.age<b.age;
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%s%d%d",buf[i].name,&buf[i].age,&buf[i].score);
}
sort(buf,buf+n,cmp);//利用定义好的规则
for(int i=0;i<n;i++){
printf("%s %d %d\n",buf[i].name,buf[i].age,buf[i].score);
}
}
return 0;
}
利用重载小于号来实现
需要记忆
bool operator < (const E &b) const{}的形式
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
struct E{
char name[10];
int age;
int score;
bool operator < (const E &b) const{
if (score!=b.score) return score<b.score;//升序
int tmp=strcmp(name,b.name);
if(tmp!=0) return tmp<0;
else return age<b.age;
}
}buf[1000];
int main(){
int n;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%s%d%d",buf[i].name,&buf[i].age,&buf[i].score);
}
sort(buf,buf+n);//利用定义好的规则
for(int i=0;i<n;i++){
printf("%s %d %d\n",buf[i].name,buf[i].age,buf[i].score);
}
}
return 0;
}
总结
还需要记住:strcmp函数实现字符的比较(string.h包中)struct类型的组织形式。