算法笔记 计算资源&STL-vector

算法笔记

本笔记的参考教材是《算法竞赛 从入门到进阶》,算法新手一枚,以后每天都把自己学习笔记分享到这里😃😃

第二章 计算的资源

复杂度

程序运行需要的资源是有限的,oj上的题目一般会对时间和空间有说明,例如:

  • Time Limit:2000/1000ms
  • Memory Limit:65536/65536KB

队员拿到题目的第一时间就是分析程序需要的 计算时间存储空间

这是一个for循环的例子,输出的是程序运行的时间

# include<bits/stdc++.h>
using namespace std;

int main(){
	int i,k,n = 1e8;
	clock_t start,end;
	start = clock();
	for(i=0;i<n;i++) k++;
	end = clock();
	cout << double(end-start) / CLOCKS_PER_SEC << endl;
} 

输出结果:0.179s

当将循环次数改成1e9的时候,结果变为1.794s

不同排序算法的复杂度对比

Ques: 给定n个整数,请按从大到小的顺序输出其中前n大的数

  • 输入:数据有两行,第一行有两个数m、n,第二行是m个整数 [-500000,500000]
  • 输出:前m大的数
冒泡排序
# include<bits/stdc++.h>
using namespace std;

int n,m;
int a[10001];

# define swap(a,b) {int temp = a; a=b; b=temp;}
void bubble_sort(){
	for(int i=1;i<=n-1;i++){
		for(int j=1;j<=n-1;j++){
			if(a[j]>a[j+1]){
				swap(a[j],a[j+1]);
			}
		}
	}
}

int main(){
	while(~scanf("%d %d",&n,&m)){
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		bubble_sort();
		for(int i = n;i>=n-m+1 ;i--){
			if(i == n-m+1) printf("%d\n",a[i]);
			else printf("%d ",a[i]);
		}
	}
	return 0;
} 

结果:

1

时间上,时间复杂度为O(n^2),因为swap有两层循环;空间上,不耗费额外空间,只有a数组占空间

快速排序

快速排序是基于分治法的排序算法,可直接用STL里面的sort()函数,将上面冒泡排序的代码中的 bubble_sort 换成 sort(a+1,a+n+1)就行。

算法的时间复杂度是O(n*log2 n)

哈希算法

哈希算法以空间换取时间,在输入数字t的时候,在a[500000+t]这个位置上记录a[500000+t]=1,输出的时候逐个检查。

# include<bits/stdc++.h>
using namespace std;
const int MAX = 1000001;
int a[MAX];

int main(){
	
	int n,m;
	while(~scanf("%d %d",&n,&m)){
		memset(a,0,sizeof(a));
		for(int i=0;i<n;i++){
			int t;
			scanf("%d",&t);
			a[500000+t]=1;
		}
	
	for(int i = MAX-1;m>0;i--){
		if(a[i]){
			if(m>1) printf("%d ",i-500000);
			else printf("%d\n",i-500000);
			m--;
		}
	}
}
	return 0;
}

第三章 STL和基本数据结构

容器

顺序式容器
  • vector : 动态数组,从末尾能快速插入和删除,直接访问任何元素
  • list :双链表,从任何地方能快速插入和删除
  • deque :双向队列,从前面或末尾能快速插入和删除,直接访问任何元素
  • queue :队列,先进先出
  • priority_queue :优先队列,最高优先级元素总是第一个出列
  • stack :栈,先进后出
关联式容器
  • set :集合,快速查找,不允许重复值
  • multiset :快速查找,允许重复值
  • map :一对一映射,不允许重复值
  • multimap : 一对多映射,基于关键字查找,允许重复值

1. vector

数组是基本的数据结构,分为动态数组合静态数组。在竞赛中,一般采用的规则是:如果空间够用居勇静态数组,这样不容易出错;如果空间比较紧张,就用vector建立动态数组。

vector能在运行中改变数组的大小,在空间存储是连续的,所以索引在常数时间内是可以完成的,但在中间差值和删除操作会造成内存块的复制,会影响效率。

定义
功能例子说明
定义int型数组 vector<int>a 默认初始化,a为空
vector<int>b(a)用a定义b
vector<int>a(100)a有100个值为0的元素
vector<int>a(100,6)a有100个值为6的元素
定义string型数组 vector<string>a(10,"null") 10个值为null的元素
vector<string>a(10,"hello")10个值为hello的元素
vector<string>b(a.begin(),a.end())b是a的复制
定义结构型数组struct point { int x,y; }
vector <point> a
a用来存坐标

还可以定义二维数组:vector<int> a[MAXN];

这个数组的第一维是固定大小的,第二维是动态的,经常用语实现图的邻接表中

常用操作
功能例子说明
赋值a.push_back(100)在尾部添加元素100
元素个数int size = a.size()元素个数
是否为空bool isEmpty = a.empty()判断是否为空
打印cout << a[0] << endl;打印第一个元素
中间插入a.insert(a.begin()+i,k)把k插到第i个元素前面
尾部插入a.insert(a.end(),10,5)在尾部插入10个整数5
尾部删除a.pop_back()删除尾部元素
删除区间a.erase(a.begin()+i,a,a.bejin()+j)删除区间[i,j-1]的元素3
删除元素a.erase(a.begin()+2)删除第三个元素
调整大小a.resize(n)数组大小调整为n
清空a.clear()清空数组
翻转a.reverse(a.begin(),a.end())翻转数组
排序sort(a.begin(),a.end())对数组进行从小到大的排序
vector 例题

圆桌上围坐着2n个人。其中n个人是好人,另外n个人是坏人。如果从第一个人开始数数,数到第m个人,则立即处死该人;然后从被处死的人之后开始数数,再将数到的第m个人处死…… 依此方法不断处死围坐在圆桌上的人。试问预先应如何安排这些好人与坏人的座位,能使得在处死n个人之后,圆桌上围坐的剩余的n个人全是好人。

输入: n ,m

输出:对于每一组数据,输出2n个大写字母,“G”表示好人,“B”表示坏人,五十个祖母为一行,不允许出现空白行,相邻数据间留有一个空行。

代码:

# include<bits/stdc++.h>
using namespace std;

int main(){
	vector<int>table;
	int n,m;
	while(cin >> n >> m){
		table.clear();
		for(int i=0;i<2*n;i++) table.push_back(i);
		int pos = 0;
		for(int i=0;i<n;i++){
			pos = (pos+m-1)%table.size(); //圆桌成环问题,取余就可以
			// pos 存储的是应该标记成坏人的位置 
			table.erase(table.begin()+pos);
		}
		int j=0;
		for(int i=0;i<2*n;i++){
			if(!(i%50) && i) cout << endl; // 五十个为一行
			if(j < table.size() && i == table[j]){
				j++;
				cout << "G" ;
			}
			else cout << "B";
		}
		cout << endl << endl;
	} 
	return 0;
}

结果:
2

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值