一些有用的stl知识《acm程序设计》
accepted 通过
Presentation Error 输出格式错误
Wrong Answer 答案错误
Runtime Error 多为数组访问越界 程序运行时错误
Time Limit Exceeded 超时 一般为复杂度过高
Output Limit Exceeded 超输出错误
C++ STL (标准模拟库)
容器(A。顺序容器 vector list deque string B。关联容器 set multiset map multimap)
迭代器是用来遍历容器的
算法库 排序算法 不可变序算法 变序性算法 数值算法
#include<algorithm>
sort (a,a+size)
reverse(v.begin(),v.end()) 反向排序
swap(int * a,int *b) 将两个数互换位置
在string尾部添加内容可以直接使用‘+’
也可以用append(“内容”)
string与数之间的相互转换
sstream 头文件
将用到stringstream stream
代码:
<sstream>库定义了三种类:istringstream、ostringstream和stringstream,
分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。
简单起见,我主要以stringstream为中心,因为每个转换都要涉及到输入和输出操作。
注意,<sstream>使用string对象来代替字符数组。这样可以避免缓冲区溢出的危险。
而且,传入参数和目标对象的类型被自动推导出来,即使使用了不正确的格式化符也没有危险。
string到int的转换
string result=”10000”;
int n=0;
stream<<result;
stream>>n;//n等于10000
重复利用stringstream对象
如果你打算在多次转换中使用同一个stringstream对象,记住再每次转换前要使用clear()方法;
在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。stringstream对象的构造和析构函数通常是非常耗费CPU时间的。
在类型转换中使用模板
你可以轻松地定义函数模板来将一个任意的类型转换到特定的目标类型。例如,需要将各种数字值,如int、long、double等等转换成字符串,要使用以一个string类型和一个任意值t为参数的to_string()函数。to_string()函数将t转换为字符串并写入result中。使用str()成员函数来获取流内部缓冲的一份拷贝:
template<class T>
void to_string(string & result,const T& t)
{
ostringstream oss;//创建一个流
oss<<t;//把值传递如流中
result=oss.str();//获取转换后的字符转并将其写入result
}
这样,你就可以轻松地将多种数值转换成字符串了:
to_string(s1,10.5);//double到string
to_string(s2,123);//int到string
to_string(s3,true);//bool到string
可以更进一步定义一个通用的转换模板,用于任意类型之间的转换。函数模板convert()含有两个模板参数out_type和in_value,功能是将in_value值转换成out_type类型:
template<class out_type,class in_value>
out_type convert(const in_value & t)
{
stringstream stream;
stream<<t;//向流中传值
out_type result;//这里存储转换结果
stream>>result;//向result中写入值
return result;
}
1 out_type convert(const in_value & t) 2 { 3 stringstream stream; 4 stream<<t;//向流中传值 5 out_type result;//这里存储转换结果 6 stream>>result;//向result中写入值 7 return result; 8 }
这样使用convert():
double d;
string salary;
string s=”12.56”;
d=convert<double>(s);//d等于12.56
salary=convert<string>(9000.0);//salary等于”9000”
结论
在过去留下来的程序代码和纯粹的C程序中,传统的<stdio.h>形式的转换伴随了我们很长的一段时间。但是,如文中所述,基于stringstream的转换拥有类型安全和不会溢出这样抢眼的特性,使我们有充足得理由抛弃<stdio.h>而使用<sstream>。<sstream>库还提供了另外一个特性—可扩展性。你可以通过重载来支持自定义类型间的转换。
一些实例:
stringstream通常是用来做数据转换的。
相比c库的转换,它更加安全,自动和直接。
例子一:基本数据类型转换例子 int转string
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::stringstream stream;
std::string result;
int i = 1000;
stream << i; //将int输入流
stream >> result; //从stream中抽取前面插入的int值
std::cout << result << std::endl; // print the string "1000"
}
1 int main() 2 { 3 4 std::stringstream stream; 5 6 std::string result; 7 8 int i = 1000; 9 10 stream << i; //将int输入流 11 12 stream >> result; //从stream中抽取前面插入的int值 13 14 std::cout << result << std::endl; // print the string "1000" 15 16 }
运行结果:
001
例子二:除了基本类型的转换,也支持char *的转换。
#include <sstream>
#include <iostream>
int main()
{
std::stringstream stream;
char result[8] ;
stream << 8888; //向stream中插入8888
stream >> result; //抽取stream中的值到result
std::cout << result << std::endl; // 屏幕显示 "8888"
}
1 int main() 2 3 { 4 5 std::stringstream stream; 6 7 char result[8] ; 8 9 stream << 8888; //向stream中插入8888 10 11 stream >> result; //抽取stream中的值到result 12 13 std::cout << result << std::endl; // 屏幕显示 "8888" 14 15 }
002
例子三:再进行多次转换的时候,必须调用stringstream的成员函数clear().
#include <sstream>
#include <iostream>
int main()
{
std::stringstream stream;
int first, second;
stream<< "456"; //插入字符串
stream >> first; //转换成int
std::cout << first << std::endl;
stream.clear(); //在进行多次转换前,必须清除stream
stream << true; //插入bool值
stream >> second; //提取出int
std::cout << second << std::endl;
}
1 #include <sstream> 2 3 #include <iostream> 4 5 int main() 6 7 { 8 9 std::stringstream stream; 10 11 int first, second; 12 13 stream<< "456"; //插入字符串 14 15 stream >> first; //转换成int 16 17 std::cout << first << std::endl; 18 19 stream.clear(); //在进行多次转换前,必须清除stream 20 21 stream << true; //插入bool值 22 23 stream >> second; //提取出int 24 25 std::cout << second << std::endl; 26 27 }
运行clear的结果
003
没有运行clear的结果
004
string中有用来统计某个字符出现的次数
int c1 = count(s.begin(),s.end(),'1');//统计字符1出现的次数
set容器 使用平衡二叉树原理
红黑树
注意在使用set.begin() 的时候其表示的是其开始位置要想取出其中元素要用*s.begin()的形式。
2.4.2 元素插入与中序遍历
#include<iostream>
#include<set>
using namespace std;
int main()
{
set <int> s;//定义元素类型为int 的集合对象s 。当前没有任何元素
s.insert(8);//第一次插入8可以
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8为重复元素,所以将不会插入
//cout<<s[2]<<endl; set 必须要使用迭代器遍历
set<int>::iterator it ;//定义前向迭代器
for(it = s.begin() ;it != s.end() ;it++)
{
cout<<*it<<" " ;
} //中序遍历集合中的所有元素
cout<<endl;
return 0 ;
}
1 #include<iostream> 2 3 #include<set> 4 5 using namespace std; 6 7 int main() 8 9 { 10 11 set <int> s;//定义元素类型为int 的集合对象s 。当前没有任何元素 12 13 s.insert(8);//第一次插入8可以 14 15 s.insert(1); 16 17 s.insert(12); 18 19 s.insert(6); 20 21 s.insert(8); //第二次插入8为重复元素,所以将不会插入 22 23 //cout<<s[2]<<endl; set 必须要使用迭代器遍历 24 25 set<int>::iterator it ;//定义前向迭代器 26 27 for(it = s.begin() ;it != s.end() ;it++) 28 29 { 30 31 cout<<*it<<" " ; 32 33 } //中序遍历集合中的所有元素 34 35 cout<<endl; 36 37 return 0 ; 38 39 }
运行结果是: 1 6 8 12
2.4.3 元素的反向遍历
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
s.insert(8);//第一次插入8可以
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8为重复元素,所以将不会插入
set<int>::reverse_iterator rit;//定义反向迭代器
for(rit=s.rbegin() ;rit=s.rend() ;it++)
{
cout<<*rit<<" ";
} //反向遍历容器内的所有元素
cout<<endl;
return 0 ;
}
1 #include<iostream> 2 3 #include<set> 4 5 using namespace std; 6 7 int main() 8 9 { 10 11 set<int> s; 12 13 s.insert(8);//第一次插入8可以 14 15 s.insert(1); 16 17 s.insert(12); 18 19 s.insert(6); 20 21 s.insert(8); //第二次插入8为重复元素,所以将不会插入 22 23 set<int>::reverse_iterator rit;//定义反向迭代器 24 25 for(rit=s.rbegin() ;rit=s.rend() ;it++) 26 27 { 28 29 cout<<*rit<<" "; 30 31 } //反向遍历容器内的所有元素 32 33 cout<<endl; 34 35 return 0 ; 36 37 }
运算结果 :
12 8 6 1
2.4.4元素的删除
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
s.insert(8);//第一次插入8可以
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8为重复元素,所以将不会插入
s.erase(6);//删除键值为6 的值
set<int>::reverse_iterator rit;//定义反向迭代器
for(rit=s.rbegin() ;rit=s.rend() ;it++)
{
cout<<*rit<<" ";
} //反向遍历容器内的所有元素
cout<<endl;
s.clear() ;//清空集合
cout<<s.size() <<endl;//输出集合的大小
return 0 ;
}
1 #include<iostream> 2 3 #include<set> 4 5 using namespace std; 6 7 int main() 8 9 { 10 11 set<int> s; 12 13 s.insert(8);//第一次插入8可以 14 15 s.insert(1); 16 17 s.insert(12); 18 19 s.insert(6); 20 21 s.insert(8); //第二次插入8为重复元素,所以将不会插入 22 23 s.erase(6);//删除键值为6 的值 24 25 set<int>::reverse_iterator rit;//定义反向迭代器 26 27 for(rit=s.rbegin() ;rit=s.rend() ;it++) 28 29 { 30 31 cout<<*rit<<" "; 32 33 } //反向遍历容器内的所有元素 34 35 cout<<endl; 36 37 s.clear() ;//清空集合 38 39 cout<<s.size() <<endl;//输出集合的大小 40 41 return 0 ; 42 43 }
运行结果:
12 8 1
0
2.4.5
元素的检索
使用find () 如果找到就返回键值的迭代器位置,否则返回最后一个元素后面的位置即end()
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s;
s.insert(8);//第一次插入8可以
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8为重复元素,所以将不会插入
set<int>::iterator it ;
it= s.find(6);//查找键值为6的元素
if(it!=s.end() )//找到
cout<<*it <<endl;//注意不能直接输出it 输出的时候就要输出it里的值
else//没找到
cout<<"not find it"<<endl;
it= s.find(20);
if(it!=s.end() )//找到
cout<<*it<<endl;
else
cout<<"not find it" <<endl;
return 0 ;
}
1 #include<iostream> 2 3 #include<set> 4 5 using namespace std; 6 7 int main() 8 9 { 10 11 set<int> s; 12 13 s.insert(8);//第一次插入8可以 14 15 s.insert(1); 16 17 s.insert(12); 18 19 s.insert(6); 20 21 s.insert(8); //第二次插入8为重复元素,所以将不会插入 22 23 set<int>::iterator it ; 24 25 it= s.find(6);//查找键值为6的元素 26 27 if(it!=s.end() )//找到 28 29 cout<<*it <<endl;//注意不能直接输出it 输出的时候就要输出it里的值 30 31 else//没找到 32 33 cout<<"not find it"<<endl; 34 35 it= s.find(20); 36 37 if(it!=s.end() )//找到 38 39 cout<<*it<<endl; 40 41 else 42 43 cout<<"not find it" <<endl; 44 45 return 0 ; 46 47 }
输出结果:
6
not find it
2.4.6[重点] 自定义比较函数
A set的元素不是结构体
#include<iostream>
#include<set>
using namespace std;
struct myComp{ //直接在struct后面补全{}不换行的话系统可以自动生成}后的;所以是比较好的代码格式
bool operator () (const int &a,const int &b)
{
if(a!=b) return a>b;
else return a>b;
}
};//自定义比较函数myComp,重载“() ” 操作符
int main()
{
set<int , myComp> s; //定义元素类型为int的集合对象s,当前没有任何元素,采用的比较函数是myComp
s.insert(8);
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8);//第二次插入8 重复元素不会插入
set<int ,myComp>::iterator it;//定义前向迭代器
for(it = s.begin();it!=s.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
return 0 ;
}
1 #include<iostream> 2 3 #include<set> 4 5 using namespace std; 6 7 struct myComp{ //直接在struct后面补全{}不换行的话系统可以自动生成}后的;所以是比较好的代码格式 8 9 bool operator () (const int &a,const int &b) 10 11 { 12 13 if(a!=b) return a>b; 14 15 else return a>b; 16 17 } 18 19 };//自定义比较函数myComp,重载“() ” 操作符 20 21 int main() 22 23 { 24 25 set<int , myComp> s; //定义元素类型为int的集合对象s,当前没有任何元素,采用的比较函数是myComp 26 27 s.insert(8); 28 29 s.insert(1); 30 31 s.insert(12); 32 33 s.insert(6); 34 35 s.insert(8);//第二次插入8 重复元素不会插入 36 37 set<int ,myComp>::iterator it;//定义前向迭代器 38 39 for(it = s.begin();it!=s.end();it++) 40 41 { 42 43 cout<<*it<<" "; 44 45 } 46 47 cout<<endl; 48 49 return 0 ; 50 51 }
运行结果:
12 8 6 1
B set的元素是结构体
#include<iostream>
#include<string>
#include<set>
using namespace std;
struct Info{
string name;
float score;
bool operator < (const Info &a) const
{
return a.score<score;//按score 由大到小的顺序排列。如果要是由小到大用 > 号
}
};
int main()
{
set<Info> s; //定义Info 类型的元素
Info info;//插入3个元素
info.name = "Jack";
info.score = 80.5;
s.insert(info);
info.name = "Tomi";
info.score = 20.5;
s.insert(info);
info.name = "Nacy";
info.score = 60.5;
s.insert(info);
set<Info>::iterator it;
for(it = s.begin();it!=s.end();it++)
{
cout<<(*it).name<<" : "<<(*it).score<<endl;
}
return 0;
}
1 #include<iostream> 2 3 #include<string> 4 5 #include<set> 6 7 using namespace std; 8 9 struct Info{ 10 11 string name; 12 13 float score; 14 15 bool operator < (const Info &a) const 16 17 { 18 19 return a.score<score;//按score 由大到小的顺序排列。如果要是由小到大用 > 号 20 21 } 22 23 }; 24 int main() 25 { 26 27 set<Info> s; //定义Info 类型的元素 28 29 Info info;//插入3个元素 30 31 info.name = "Jack"; 32 33 info.score = 80.5; 34 35 s.insert(info); 36 37 info.name = "Tomi"; 38 39 info.score = 20.5; 40 41 s.insert(info); 42 43 info.name = "Nacy"; 44 45 info.score = 60.5; 46 47 s.insert(info); 48 49 set<Info>::iterator it; 50 51 for(it = s.begin();it!=s.end();it++) 52 { 53 cout<<(*it).name<<" : "<<(*it).score<<endl; 54 } 55 return 0; 56 }
运行结果
Jack : 80.5
Nacy : 60.5
Tomi : 20.5
2.5 multiset
multiset 允许插入相同的元素
删除的时候返回为删除元素的个数
#include<iostream>
#include<set>
#include<string>
using namespace std;
int main()
{
multiset <string> ms;
ms.insert("abc");
ms.insert("123");
ms.insert("111");
ms.insert("aaa");
ms.insert("123");
multiset<string>::iterator it;
for(it = ms.begin();it!=ms.end();it++)
{
cout<<(*it)<<endl;
}
int n = ms.erase("123");//返回其删除的元素个数 输出2
cout<<n;
return 0 ;
}
1 #include<iostream> 2 #include<set> 3 #include<string> 4 using namespace std; 5 int main() 6 { 7 multiset <string> ms; 8 ms.insert("abc"); 9 ms.insert("123"); 10 ms.insert("111"); 11 ms.insert("aaa"); 12 ms.insert("123"); 13 multiset<string>::iterator it; 14 for(it = ms.begin();it!=ms.end();it++) 15 { 16 cout<<(*it)<<endl; 17 } 18 int n = ms.erase("123");//返回其删除的元素个数 输出2 19 cout<<n; 20 return 0 ; 21 }
2.6 map 映照容器
由 键值 映照数据 组成
2.6.1 map 创建,元素插入,和遍历访问
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{
map<string,float> m;//定义map对象,当前没有任何元素,前面的为键值 后面的为映照数据
m["Jake"]=98.5;
m["Bomi"]=96.0;
m["Kate"]=97.5;//插入元素 map与set一样都默认从小到大排序
map<string,float>::iterator it;
for(it = m.begin();it!=m.end();it++)
{
cout<<(*it).first<<" : "<<(*it).second<<endl;//输出键值与映照数据
}
return 0 ;
}
1 #include<iostream> 2 #include<map> 3 #include<string> 4 using namespace std; 5 int main() 6 { 7 map<string,float> m;//定义map对象,当前没有任何元素,前面的为键值 后面的为映照数据 8 m["Jake"]=98.5; 9 m["Bomi"]=96.0; 10 m["Kate"]=97.5;//插入元素 map与set一样都默认从小到大排序 11 map<string,float>::iterator it; 12 for(it = m.begin();it!=m.end();it++) 13 { 14 cout<<(*it).first<<" : "<<(*it).second<<endl;//输出键值与映照数据 15 } 16 return 0 ; 17 }
运行结果:
Bomi : 96
Jake : 98.5
Kate : 97.5
注意使用map的时候有可能会产生warning C5786 的错误
所以在头文件前使用#pragma Warning(disable : 4786)
map也可以自己定义比较函数 和set一样
2.6.6
用map实现数字分离
A 字符映照数字
1 #pragma warning(disable : 4786) 2 #include<iostream> 3 #include<map> 4 #include<string> 5 using namespace std; 6 int main() 7 { 8 map<char,int> m;//定义map对象,其中没有任何元素、 9 m['0'] = 0; 10 m['1'] = 1; 11 m['2'] = 2; 12 m['3'] = 3; 13 m['4'] = 4; 14 m['5'] = 5; 15 m['6'] = 6; 16 m['7'] = 7; 17 m['8'] = 8; 18 m['9'] = 9; 19 /*上面的语句也可以采用循环简化 20 for(int i = 0; i < 10; i ++) 21 { 22 m['0'+i] = j; 23 } 24 */ 25 string sa,sb; 26 sa = "6234"; 27 int i ,sum = 0; 28 for( i = 0; i<sa.length();i++) 29 { 30 sum+=m[sa[i]]; 31 } 32 cout<<"sum = "<<sum<<endl; 33 return 0; 34 }
运行结果:
sum = 15
B 数字映照字符
1 #pragma warning(disable : 4786) 2 #include<iostream> 3 #include<map> 4 #include<string> 5 using namespace std; 6 int main() 7 { 8 map<int ,char> m;//定义map对象,其中没有任何元素、 9 m[0] = '0'; 10 m[1] = '1'; 11 m[2] = '2'; 12 m[3] = '3'; 13 m[4] = '4'; 14 m[5] = '5'; 15 m[6] = '6'; 16 m[7] = '7'; 17 m[8] = '8'; 18 m[9] = '9'; 19 /*上面的语句也可以采用循环简化 20 for(int i = 0; i < 10; i ++) 21 { 22 m[i] = '0'+i; 23 } 24 */ 25 int n = 7; 26 string s = "The number is "; 27 cout<<s + m[n]<<endl; 28 return 0; 29 }
multimap 与map用法基本一样,但是允许插入重复的键值
1 #pragma warning(disable : 4786) 2 #include<iostream> 3 #include<map> 4 #include<string> 5 using namespace std; 6 int main() 7 { 8 multimap <string,double> m; 9 m.insert(pair<string,double>("Jack",300.5)); 10 m.insert(pair<string,double>("Kity",200)); 11 m.insert(pair<string,double>("Memi",500)); 12 m.insert(pair<string,double>("Jack",360));//插入重复的键值 “Jack” 13 multimap<string,double>:: iterator it ; 14 for(it = m.begin() ;it!=m.end() ;it++) 15 { 16 cout<<(*it).first<<" : "<<(*it).second<<endl; 17 } 18 return 0; 19 }
运行结果:
Jack : 300.5
Jack : 360
Kity : 200
Memi : 500
元素的删除:
m.erase("Jack");//删除所有键值为“Jack”的元素
2.8 deque 双端队列容器
可以在头部和尾部都可以插入和删除元素而不需要移动其他元素
用法与vector类似
用头文件#include<deque>
在头部插入新的数的时候会将原有的数覆盖
p.push_front(10);//如果原来的第一个元素是1 则现在为10;
p.push_back(13);//会不断扩充其大小
用d.size()来检测其大小
既可以以数组的方式遍历也可以用迭代器
反向遍历与之前的用法相同
采用pop_front() 方法从头部删除元素
采用pop_back() 方法从尾部删除元素
采用erase() 方法从中间删除元素(参数是迭代器位置《和vector 一样》而set与map的erase函数的参数都是键值)
用clear() 方法清空容器
2.9 list双向链表容器
list对象的节点并不要求在一段连续的内存中所以对于迭代器,只能通过‘++’不可以+n操作这是与vector不同的地方
元素的插入与遍历
1 #include<iostream> 2 #include<list> 3 using namespace std; 4 int main() 5 { 6 list<int> l; 7 l.push_back(2); 8 l.push_back(1); 9 l.push_back(5);//在尾部插入值,链表自动扩充 10 l.push_front(8);//在头部插入值,开始有的值不会被覆盖,链表自动扩充 11 list<int>::iterator it; 12 it = l.begin(); 13 it++; 14 l.insert(it,20);//在迭代器为1的位置上插入20的键值 15 for(it = l.begin();it!=l.end();it++) 16 { 17 cout<<*it<<" "; 18 } 19 cout<<endl; 20 return 0 ; 21 }
运行结果
8 20 2 1 5
反向遍历同前面
使用remove()方法删除链表中的一个元素,值相同的元素都会被删除
参数为键值
eg l.remove(1)//键值为1的值都被删除了
使用l.pop_back(2)//参数也为键值,删除尾部的值
使用l.pop_front(2)//参数也为键值,删除头部的值
用erase()的方法删除某迭代器位置上的值
eg 删除第2个元素
it=l.begin();//从0 开始计数
it++;
it++;
l.erase(it);
l.sort( );//对list进行升序排序(不用加algorithm的头文件,list的头文件就包含了)
l.unique()//剔除连续重复元素,只保留一个
eg 2 5 1 1 1 5 1
l.unique() ; 后值为 2 5 1 5 1
2.10 bitset位集合容器
在头文件#include<bitset>中
创建bitset对象的时候必须要指定容器的大小 而且大小一定义,之后就不能再修改了
bitset<100000> b 定义了一个100000位的bit容器且所有的元素值都是0;
设置元素的值
方法 |
功能 |
b.any() |
B中是否存在置为1 的二进制位 |
b.none() |
B中不存在置为1的二进制位 |
b.count() |
B中的置为1的二进制位数 |
b.size() |
B中的二进制位的个数 |
b[pos] |
访问在b中的二进制位 |
b.test(pos) |
B中的在pos处的二进制位数值是否为1 |
b.set() |
把所有的二进制位都设置为1 |
b.set(pos) |
把b中的pos位的值设置为1 |
b.reset() |
把b中的所有值都设置为0 |
b.reset(pos) |
把b中的pos位的值设置为0 |
b.flip() |
把b中的所有值都按位取反 |
b.flip(pos) |
把b中的pos位的值设置按位取反 |
b.to_ulong() |
用b中的同样的二进制位返回一个unsigned long 值 |
os<<b 即可以直接cout<<b<<endl; |
把b中的位集输出到os流 |
2.11 stack堆栈容器
在头文件#include<stack>中
1 #include<iostream> 2 #include<stack> 3 using namespace std; 4 int main() 5 { 6 stack <int> s; 7 s.push(1); 8 s.push(2); 9 s.push(3); 10 s.push(9);//元素入栈 11 cout<<s.top()<<endl;//读取栈顶元素 12 cout<<s.size()<<endl;//读取元素数量 13 cout<<s.empty()<<endl;//判断堆栈是否为空 14 while(s.empty()!=true) 15 { 16 cout<<s.top()<<" ";//读取栈顶元素 17 s.pop();//删除栈顶元素 18 } 19 cout<<endl; 20 return 0; 21 }
运行结果:
9
4
0
9 3 2 1
2.12queue 队列容器
注意:queue插入元素的时候是用的push而不是push_back
注意:queue中没有迭代器,不可以定义迭代器,只有出队和入队的操作
1 #include<iostream> 2 #include<queue> 3 using namespace std; 4 int main() 5 { 6 queue<int> q; 7 q.push(1); 8 q.push(2); 9 q.push(3); 10 q.push(9);//入队即插入元素 11 cout<<q.size() <<endl;//返回队列元素数量 12 cout<<q.empty()<<endl;//返回队列是否为空,是空为返回真 13 cout<<q.front() <<endl;//返回队首元素 14 cout<<q.back() <<endl;//返回队尾元素 15 while(q.empty() !=true) 16 { 17 cout<<q.front() <<" "; 18 q.pop() ;//队首元素出队 19 } 20 cout<<endl; 21 return 0; 22 }
2.13 priority_queue 优先队列容器
8 要是直接变成小顶堆可以直接priority_queue<int,vector<int>,greater<int> >que;
priority_queue<int ,vector<int>,greater<int >>que;直接就可以变成是由小到大排序
在头文件#include<queue>中
1 #include<iostream> 2 #include<queue> 3 #include<string> 4 using namespace std; 5 6 struct Info{ 7 string name; 8 float score; 9 bool operator < (const Info &a) const//重载“<”操作符 ,指定优先规则 10 { 11 return a.score<score;//按score由小到大 >为由大到小 12 } 13 }; 14 int main() 15 { 16 priority_queue<Info> pq; 17 Info info;//定义结构体变量 18 info.name = "Jack"; 19 info.score = 68.5; 20 pq.push(info); 21 22 info.name = "Bomi"; 23 info.score = 18.5; 24 pq.push(info); 25 26 info.name = "Peti"; 27 info.score = 90; 28 pq.push(info);//入队 29 30 while(pq.empty()!=true) 31 { 32 cout<<pq.tp().name<<" : " <<pq.top().score<<endl; 33 pq.pop();//出栈 34 } 35 return 0 ; 36 }
1 #include<iostream> 2 #include<queue> 3 #include<string> 4 using namespace std; 5 6 struct Info{ 7 string name; 8 float score; 9 bool operator < (const Info &a) const//重载“<”操作符 ,指定优先规则 10 { 11 return a.score<score;//按score由小到大 >为由大到小 12 } 13 }; 14 int main() 15 { 16 priority_queue<Info> pq; 17 Info info;//定义结构体变量 18 info.name = "Jack"; 19 info.score = 68.5; 20 pq.push(info); 21 22 info.name = "Bomi"; 23 info.score = 18.5; 24 pq.push(info); 25 26 info.name = "Peti"; 27 info.score = 90; 28 pq.push(info);//入队 29 30 while(pq.empty()!=true) 31 { 32 cout<<pq.tp().name<<" : " <<pq.top().score<<endl; 33 pq.pop();//出栈 34 } 35 return 0 ; 36 }
重载()定义优先级
经典的排序::按绩点排序
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<algorithm> 5 #include<iomanip> 6 using namespace std; 7 8 struct student { 9 string s; 10 double d; 11 }; 12 13 bool myComp (const student &s1,const student &s2) 14 { 15 if(s1.d!=s2.d) return s1.d>s2.d; 16 if(s1.s!=s2.s) return s1.s<s2.s; 17 } 18 19 int main() 20 { 21 int n;//班级数 22 int c;//课程数 23 double xf;//学分 24 vector<double>vxf ;//学分向量 25 int p ;//班级人数 26 string name;//学生名称 27 double score ;//成绩 28 student xs;//学生名称与总学分结构体 29 vector<student>vxs;//最终学生名称与总学分 30 cin>>n; 31 for(int i = 0 ; i< n ; i++ )//处理每一个班 32 { 33 cin>>c;//读入课程数量 34 for(int j = 0 ; j< c; j ++) 35 { 36 cin>>xf; 37 vxf.push_back(xf); 38 } 39 cin>>p;//读入班级人数 40 for(int k = 0 ; k<p ;k++) 41 { 42 cin>>name; 43 xs.s = name ; 44 xf = 0.0; 45 for(int m = 0 ;m < c ; m++) 46 { 47 cin>>score ; 48 if(score<60) continue ; 49 xf= xf+ (score-50)/10*vxf[m]; 50 } 51 xs.d=xf/10; 52 vxs.push_back(xs); 53 } 54 cout<<(i?"\n":""); 55 cout<<"class"<<i+1<<":"<<endl; 56 sort(vxs.begin(),vxs.end(),myComp); 57 for(vector<studet>::iterator it = vxs.begin();it<vxs.end();it++) 58 { 59 cout<<fixed<<setprecision(2); 60 cout<<left<<setw(11); 61 cout<<(*it).s<<(*it).d<<endl; 62 } 63 vxf.clear(); 64 vxs.clear(); 65 } 66 return 0; 67 }
按1的个数排序
1 #include<iostream> 2 #include<vector> 3 #include<string> 4 #include<algorithm> 5 using namespace std; 6 bool myComp (const string &s1,const string &s2) 7 { 8 int c1= count(s1.begin(),s1.end(),'1'); 9 int c2= count(s2.begin(),s2.end(),'1'); 10 return c1!=c2?c1<c2:c1<c2;//彻底修改排序规则,只按1的出现个数排序 11 //如果1的数量相等,则只按1数量排序 12 //如果1的数量相等则按出现的先后顺序 13 //否则会按ASC11码的大小排序 14 //只能用“>或者< ”不可以用“=”号 15 } 16 int main() 17 { 18 vector<string> vstr; 19 string str; 20 while(cin>>str) 21 { 22 vstr.push_back(str); 23 } 24 sort(vstr.begin(),vstr.end(),myComp); 25 vector <string> ::iterator it; 26 for(it = vstr.begin();it!=vstr.end();it++) 27 { 28 cout<<*it<<endl; 29 } 30 return 0; 31 }
这里用到的 string中count的函数来统计string中某个字符出现的次数
注意在用到自定义的比较函数中对vector排序时候要将头文件algorithm加上
用到其头文件中的sort函数
查找文件
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 vector<string> v,end; 7 int main() 8 { 9 string s,ss,left,right; 10 int m , n; 11 int i ,j, k; 12 int p,q; 13 int c = 0 ; 14 while(cin>>m) 15 { 16 c++;//案例数目 17 if(c>1)cout<<endl; 18 v.clear() ; 19 for( i= 0 ; i< m ;i++) 20 { 21 cin>>s; 22 v.push_back(s); 23 } 24 cin>>n; 25 for(i = 0 ; i <n ; i++) 26 { 27 cin>>ss; 28 left = ""; 29 right = ""; 30 p = ss.find("*"); 31 for(j = 0 ; j < p ; j++) 32 { 33 left += ss[j]; 34 } 35 for( j = p+1 ; j<ss.length() ; j++) 36 { 37 right +=ss[j] ; 38 } 39 end.clear(); 40 for(j = 0 ; j< v.size() ; j++) 41 { 42 if(v[j].size()<(left.size()+right.size())) 43 continue; 44 if(left.size()!=0) 45 { 46 if(v[j].find(left)!=0) continue ; 47 } 48 if(right.size()!=0) 49 { 50 reverse(right.begin(),right.end()); 51 reverse(v[j].begin(),v[j].end()); 52 if(v[j].find(right)!=0) 53 { 54 reverse(right.begin(),right.end()); 55 reverse(v[j].begin(),v[j].end()); 56 continue; 57 } 58 reverse(right.begin(),right.end()); 59 reverse(v[j].begin(),v[j].end()); 60 } 61 end.push_back(v[j]); 62 } 63 for(k = 0 ;k<end.size() ;k++) 64 { 65 cout<<end[k]; 66 if(k!=end.size()-1) 67 cout<<", "; 68 else 69 cout<<endl; 70 } 71 if(end.size()==0) 72 cout<<"FILE NOT FOUND"<<endl; 73 } 74 } 75 return 0 ; 76 }
测试案例
4
command.com
msdos.sys
io.sys
config.sys
2
com*.com
*.sys
3
a.txt
b.txt
c.txt
1
*.doc
4.45 让气球升起来
#include<iostream>
#include<string>
#include<map>
using namespace std;
map<string,int> m;
int main()
{
int n ;
while(cin>>n&&n!=0)
{
m.clear() ;
string s;
while(n--)
{
cin>>s;
if(m.find(s)!=m.end() )
{
m[s] = m[s]+1;
}
else
m[s] = 1;
}
map<string,int> ::iterator i ,j;
j = m.begin() ;
for( i = m.begin() ; i <m.end() ; i++)
{
if( i->second>j->second) j = i ;
}
cout<<j->first<<endl;
}
return 0 ;
}