紫书第5章笔记 C++与STL入土

第五章 C++与STL入门

5.1 C++

#104 问题:输入数据的每行包含若干个(至少一个)以空格隔开的整数,输出每行中所有整数之和。

#include<iostream>
#include<string>
#include<sstream>
using namespace std;

int main(){
	string line;
	while(getline(cin,line)){
		int sum = 0,x;
		stringstream ss(line);
		while(ss >> x){
			sum += x;
		}
		cout << sum << "/n";
	}
	return 0;
}

stringstream 在头文件 sstream 中,sstream 定义了三个类 istringstream 、 ostringstream 和 stringstream 分别用于流的输入、输出和操作。主要用于数据类型的转换:转为string类型。

#105 虽然 string 和 stream 都很方便,但 string 很慢, sstream 更慢。

5.2 STL

  • #108 UVa.10474 Where is the Marble?

N个大理石,每个大理石上写了一个非负整数。首先把各数从小到大排序,然后回答Q个问题。每个问题问是否有一个大理石写着某个整数x,如果是,还要回答哪个大理石上写着x。排序后的大理石从左到右编号为1~N。

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10000;

int main(){
	int n,q,x,a[maxn],Case=0;
	while(scanf("%d%d",&n,&q) == 2 && n){
		printf("CASE# %d:\n", ++Case);
		for(int i = 0;i < n;i++){
			cin >> a[i];
		}
		sort(a,a+n);
		while(q--){
			cin >> x;
			int p = lower_bound(a,a+n,x) - a;
			if(a[p] == x)
				cout << x << " found at " << p+1 <<endl;
			else
				cout << x <<" not found"  <<endl;
		}
	}
    return 0;
}

第一遍错误解答,检查好一会发现没有加endl

注意到,在UVa10474中:
scanf("%d%d",&n,&q) == 2 && n==2左式有n个未知量就==n,判断n个未知量输入是否符合标准。&& n判断n不为0。
sort(a,a+n):从小到大排普通数组。sort(a.begin(),a.end()):从小到大排vector。
lower_bound(a,a+n,x):查找“大于或者等于x的第一个位置”。

  • #110 UVa.101 The Blocks Problem

从左到右n个木块,编号为0~n-1,要求模拟以下4种操作:
• move a onto b: 将 a 和 b 归位,把 a 放在 b 上
• move a over b: 将 a 归位, a 放在 b 的顶部
• pile a onto b: 将 b 归位, a 及上面木块整体摞在 b 上
• pile a over b: 将 a 及上面木块整体摞在 b 顶
• quit: 终止
a 和 b 在同一堆时是非法指令,忽略。
所有操作结束后,输出每个位置的木块列表,按照从底到顶的顺序排列。

观察到,有且只有 onto 操作对 b 归位,move 操作对 a 归位。

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cstdio>
using namespace std;
const int maxn = 30;
vector<int> pile[maxn];
int n;

void find(int a,int& p,int& h){
	for(p=0;p<n;p++){    //wrong2
		for(h=0;h<pile[p].size();h++){
			if(pile[p][h]==a)
				return;
		}
	}
}

void back(int p,int h){
	for(int i=h+1;i<pile[p].size();i++){
		int b=pile[p][i];
		pile[b].push_back(b);
	}
	pile[p].resize(h+1);
}

void pile_over(int a,int p,int h){
	for(int i=h;i<pile[p].size();i++){
		int b=pile[p][i];
		pile[a].push_back(b);
	}
	pile[p].resize(h);
}

int main(){
	cin>>n;
	string s1,s2;
	int a,b;
	for(int i=0;i<n;i++){    //initialization
		pile[i].push_back(i);
	}
	while(cin>>s1>>a>>s2>>b){
		int pa,pb,ha,hb;
		find(a,pa,ha);
		find(b,pb,hb);
		if(pa == pb) continue;
		if(s1 == "move") back(pa,ha);
		if(s2 == "onto") back(pb,hb);
		pile_over(pb,pa,ha);    //wrong1    
	}
	for(int i=0;i<n;i++){    //print
		cout<<i<<":";
		for(int j=0;j<pile[i].size();j++){
			cout<<" "<<pile[i][j];
		}
		cout<<endl;
	}
	return 0;
}

#112 vector是一个不定长数组

wrong1:pile_over(pb,pa,ha);中的 pb 写成 b。
wrong2:循环中在已经定义过的变量前又加了一次 int 。
注意到,头文件#include<cstdio>不必要。

万能头文件 #include<bits/stdc++.h>

  • #112 UVa.10815 Andy’s First Dictionary

输入一个文本,找出所有不同的单词(连续的字母序列),按字典序从小到大输出。单词不区分大小写。

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

set<string> dict;

int main(){
	string x,temp;
	while(cin>>x){
		for(int i = 0;i < x.length();i++){
			if(isalpha(x[i])){
				x[i] = tolower(x[i]);
			}
			else{
				x[i] = ' ';
			}
	    }
		stringstream ss(x);
		while(ss >> temp){
			dict.insert(temp);
		}	
	}
	for(set<string>::iterator it = dict.begin();it != dict.end();it++){
		cout<<*it<<endl;
	}
	return 0;
}

#113 set 中元素已从小到大排好序,用一个for即可从小到大遍历其中所有元素,set<string>::iterator 迭代器,类似于指针。

  • #113 UVa.156 Ananagrams

输入一些单词,找到满足条件的单词:该单词不能通过字母重排得到输入文本中的另外一个单词。判断时不区分大小写。输出时保留大小写,按字典序排列(所有大写排在小写前面)。输入 “#” 结束。

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

string stan(string s){
	for(int i = 0;i < s.size();i++){
		s[i] = tolower(s[i]);
	}
	sort(s.begin(),s.end());
	return s;
}

int main(){
	vector<string> words;
	map<string,int> cnt;
	string s;
    while(cin >> s){
		if(s[0] == '#') break;
		words.push_back(s);
		string t = stan(s);
		if(!cnt.count(t)) cnt[t] = 0;
		cnt[t]++;
	}
	vector<string> ans;
	for(int i = 0 ; i < words.size() ; i++){
		if(cnt[stan(words[i])] == 1){
			ans.push_back(words[i]);
		}
	}
	sort(ans.begin(),ans.end());
	for(int i = 0;i < ans.size();i++){
		cout << ans[i] << endl;
	}
	return 0;
}

#115 STL 的栈定义在头文件 < stark > 中,用 stark<T> s方式声明栈。操作有 push pop top。

  • #115 UVa.12096 The SetStack Computer

设计“集合栈”计算机,包括操作:
PUSH:空集合入栈。
DUP:当前栈顶元素复制一份后入栈。
UNION:出栈两个集合,把二者并集入栈。
INTRESECT:出栈两个集合,把二者交集入栈。
ADD:出栈两个集合,把先出栈的集合加入到后出栈的集合中,把结果入栈。
每次操作后,输出栈顶集合的大小。

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

#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())

typedef set<int> Set;
map<Set,int> IDcache;
vector<Set> Setcache;

int ID (Set x){					//查找给定集合x的ID。找不到则分配新ID。
	if(IDcache.count(x)){
		return IDcache[x];
	}
	Setcache.push_back(x);
	return IDcache[x] = Setcache.size() - 1;
}

int main(){
	stack<int> s;
	int t,n;
	cin>>t;
	while(t--){
		cin>>n;
		for(int i = 0;i < n;i ++){
			string op;
			cin>>op;
			if(op[0] == 'P') s.push(ID(Set()));	//空集入栈
			else if(op[0] == 'D') s.push(s.top());
			else{
				Set x1 = Setcache[s.top()]; s.pop();
				Set x2 = Setcache[s.top()]; s.pop();
				Set x;
				if(op[0] == 'U') set_union (ALL(x1),ALL(x2),INS(x));
				if(op[0] == 'I') set_intersection (ALL(x1),ALL(x2),INS(x));
				if(op[0] == 'A'){
					x = x2;
					x.insert(ID(x1));
				}
				s.push(ID(x));
			}
			cout << Setcache[s.top()].size() << endl;
		}
		cout << "***" << endl;
	}
	return 0;
}

#116 为每个不同的集合分配一个唯一的ID,则每个集合都可以表示成所包含元素的ID集合,这样就可以用STL的 set<int> 来表示,而整个栈则是一个 stack<int>
对任意集合 s (类型为自定义的 Set ),IDcache[s] 是它的 ID ,而 Setcache[IDcache] 是 s 本身。 ALL 和 INS 是两个宏,分别表示“所有的内容”以及“插入迭代器”。
set_union(A.begin() , A.end() , B.begin() , B.end() , inserter(C1, C1.begin()) )。将集合A、B取并集后的结果存入集合C中。set_union(A.begin(),A.end(),B.begin(),B.end(),ostream_iterator<T>(cout," “));将A、B取并集后的结果直接输出,(cout," ")双引号里是输出用来间隔集合元素的符号或是空格。
set 中有 set_intersection(取集合交集)、set_union(取集合并集)、set_difference(取集合差集)、set_symmetric_difference(取集合对称差集)等函数。
不难看出,这里的宏就是替代了括号中的部分。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值