string s1; // 默认初始化,s1是一个空字符串
string s2 = s1; // s2是s1的副本,注意s2只是与s1的值相同,并不指向同一段地址
string s3 = "hiya"; // s3是该字符串字面值的副本
string s4(10, 'c'); // s4的内容是 "cccccccccc"
2.string上的操作
(1) getline读取一整行
string s;
getline(cin,s);
(2) string的比较
(3)两个string对象相加支持 >, <, >=, <=, ==, !=等所有比较操作,按字典序进行比较。
(4)字面值和string对象相加:string s1 = "hello, "", s2 = "worldn";
string s3 = s1 + s2; // s3的内容是 hello, worldn
s1 += s2; // s1 = s1 + s2
做加法运算时,字面值和字符都会被转化成string对象,因此直接相加就是将这些字面值串联起来:
string s1 = "hello", s2 = "world"; // 在s1和s2中都没有标点符号 string s3 = s1 + ", " + s2 + 'n';
当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符的两侧的运算对象至少有一个是string:
string s4 = s1 + ", "; // 正确:把一个string对象和有一个字面值相加 string s5 = "hello" + ", "; // 错误:两个运算对象都不是string string s6 = s1 + ", " + "world"; // 正确,每个加法运算都有一个运算符是string string s7 = "hello" + ", " + s2; // 错误:不能把字面值直接相加,运算是从左到右进行的3. 处理string对象中的字符
可以将string对象当成字符数组来处理:
string s = "hello world";
for (int i = 0; i < s.size(); i ++ )
cout << s[i] << endl;
for (char c: s) cout << c << endl;
4.操作string的常用函数
(1)find函数
基本用法
string的find()函数用于找出字母在字符串中的位置。
find(str,position)
str:是要找的元素
position:字符串中的某个位置,表示从从这个位置开始的字符串中找指定元素(不填第二个参数,默认从字符串的开头进行查找)
返回值为目标字符的位置(第一个字符位置为0),当没有找到目标字符时返回npos
举例
//找到目标字符的位置
string s = "hello world!";
cout << s.find("e") << endl;
输出结果:1
//未找到目标字符
string s = "hello world!";
if (s.find("a") == s.npos) {
cout << "not found" << endl;
}
输出结果:not found
//指定查找位置
string s = "hello world!";
cout << s.find("l",5) << endl;
输出结果:9
延伸用法
找到目标字符第一次出现和最后一次出现的位置
string s = "hello world!"; cout <反向查找
string s = "hello world!"; cout << s.rfind("l") << endl;//即从后往前第一次出现"l"的位置 输出: 9通常我们可以这样来使用,当正向查找与反向查找得到的位置不相同说明子串不唯一。
查找所有子串在母串中出现的位置
//查找s 中flag 出现的所有位置。 string s("hello world!"); string flag="l"; int position=0; int i=1; while((position=s.find(flag,position))!=string::npos) { cout<<"position "< (2)replace 函数用法一:
用str替换指定字符串从起始位置pos开始长度为len的字符
string& replace (size_t pos, size_t len, const string& str)
int main() { string line = "this@ is@ a test string!"; line = line.replace(line.find("@"), 1, ""); //从第一个@位置替换第一个@为空 cout << line << endl; return 0; } 输出:this is@ a that string!用法二:
用str替换 迭代器起始位置 和 结束位置 的字符
string& replace (const_iterator i1, const_iterator i2, const string& str);
int main() { string line = "this@ is@ a test string!"; line = line.replace(line.begin(), line.begin()+6, ""); //用str替换从begin位置开始的字符 cout << line << endl; return 0; } 输出:is@ a that string!用法三:
用substr的指定子串(给定起始位置和长度)替换从指定位置上的字符串
string& replace (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen)
int main() { string line = "this@ is@ a test string!"; string substr = "12345"; line = line.replace(0, 5, substr, substr.find("1"), 3); //用substr的指定子串(从1位置数共3个字符)替换从0到5位置上的line cout << line << endl; return 0; } 输出:123 is@ a test string!二、STL 1. #includevector是变长数组,支持随机访问,不支持在任意位置 O(1) 插入。为了保证效率,元素的增删一般应该在末尾进行。
(1)声明
vectora; // 相当于一个长度动态变化的int数组,默认为空 vector a(100) // a有100个值为0的元素 vector b[233]; // 相当于第一维长233,第二位长度动态变化的int数组 vector c // 相当于二维字符串数组 vector c(10,"hello") // c有10个值为hello的元素 vector c(a.begin(),a.end()) // c是a的复制 struct rec{…}; vector d; // 自定义的结构体类型也可以保存在vector中 (2)迭代器
迭代器就像STL容器的“指针”,可以用星号*操作符解除引用。
一个保存int的vector的迭代器声明方法为:
vector::iterator it; auto it = a.begin() //auto自动推断类型 vector的迭代器是“随机访问迭代器”,可以把vector的迭代器与一个整数相加减,其行为和指针的移动类似。可以把vector的两个迭代器相减,其结果也和指针相减类似,得到两个迭代器对应下标之间的距离。
(3) 遍历
begin函数返回指向vector中第一个元素的迭代器。例如a是一个非空的vector,则*a.begin()与a[0]的作用相同。
所有的容器都可以视作一个“前闭后开”的结构,end函数返回vector的尾部,即第n 个元素再往后的“边界”。*a.end()与a[n]都是越界访问,其中n = a.size()。
for (int i = 0; i < a.size(); i ++) cout << a[i] << endl; for (vector::iterator it = a.begin(); it != a.end(); it ++) cout << *it << endl; auto
for (auto it=a.begin();it!=a.end();it++) cout << *it << endl;for(auto x : a); for(auto& x : a); for(const auto& x : a);(4) 插入删除操作
a.push_back(x) //把元素x插入到vector a的尾部。 a.insert(a.begin()+i,x) //在第i个元素前面插入x a.insert(a.end(),10,5) //在尾部插入10个值为5的元素 a.pop_back() //删除vector a的最后一个元素。 a.erase(a.begin()+i,a.begin()+j) //删除区间[i,j-1]的元素 a.erase(a.begin()+2) //删除第三个元素 reverse(a.begin(),a.end()) //翻转数组2. #include头文件set主要包括set和multiset两个容器,分别是“有序集合”和“有序多重集合”,即前者的元素不能重复,而后者可以包含若干个相等的元素。set和multiset的内部实现是一棵红黑树,它们支持的函数基本相同。
(1) 声明
sets; struct rec{…}; set s; // 结构体rec中必须定义小于号 multiset s; (2)迭代器
set和multiset的迭代器称为“双向访问迭代器”,不支持“随机访问”,支持星号*解除引用,仅支持++和--两个与算术相关的操作。
设it是一个迭代器,例如set
::iterator it; 若把it ++,则it会指向“下一个”元素。这里的“下一个”元素是指在元素从小到大排序的结果中,排在it下一名的元素。同理,若把it --,则it将会指向排在“上一个”的元素。
(3) insert
s.insert(x) //把一个元素x插入到集合s中,时间复杂度为 O(logn)O(logn)。在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。
(4) find
s.find(x) //在集合s中查找等于x的元素,并返回指向该元素的迭代器。 //若不存在,则返回s.end()。 if(s.find(x)!=s.end()) //判断x是否在s中(5) erase
设it是一个迭代器,s.erase(it)从s中删除迭代器it指向的元素,时间复杂度为 O(logn)O(logn)。
设x是一个元素,s.erase(x)从s中删除所有等于x的元素,时间复杂度为 O(k+logn)O(k+logn),其中 kk 是被删除的元素个数。
s.erase(it) //删除迭代器it指向的元素 s.erase(x) //删除s中的x(6) count
s.count(x)返回集合s中等于x的元素个数,时间复杂度为 O(k+logn)O(k+logn),其中 kk 为元素x的个数。
s.count(x) //返回s中x的数量(7) lower_bound/upper_bound
这两个函数的用法与find类似,但查找的条件略有不同,时间复杂度为 O(logn)O(logn)。
s.lower_bound(x) //查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。 s.upper_bound(x) //查找大于x的元素中最小的一个,并返回指向该元素的迭代器。(8)自定义插入规则(降序排列)
//重载降序排列 struct cmp{ bool operator() (const int &a,const int&b){ return a>b; } }; //定义方法 set3. #includes;



