排序----机试自学手记(1)

排序

文章根据王道机试书进行学习。

空间时间复杂度须知

不同的编译环境(操作系统、编辑器),可能每个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类型的组织形式。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值