小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
一、常用容器
1.1 string容器
1.1.1 相关概念
C
风格字符串(以空字符结尾的字符数组)太过复杂难于掌握,不适合大程序的开发,所以C++
标准库定义了一种string
类,定义在头文件<string>
。
String
和c
风格字符串对比:Char*
是一个指针,String
是一个类
string
封装了char
,管理这个字符串,是一个char
型的容器。
String
封装了很多实用的成员方法查找find
,拷贝copy,删除delete
替换replace
,插入insert
,不用考虑内存释放和越界,string
实例化的对象释放空间时,会自动调用析构函数,所以在析构函数中释放空间了,所以不需要我们手动释放
string
管理char*
所分配的内存。每一次string
的复制,取值都由string类负责维护,不用担心复制越界和取值越界等。
string开辟空间问题
如果string类实例化的对象前期赋值不超过15个字节,默认最大存放的字符串的长度为15个字节,所以如果赋值超过15个字节,==会释放原来的空间,开辟新的空间==,所以不要事先保存string的地址,因为有可能操作的地址已经不再是当前对象的了,所以最好实时保存
cout << "容量:" << s1.capacity() << endl;
1.1.2 string容器常用操作
1.1.2.1 string构造函数
string();//创建一个空的字符串 例如: string str;
string(const string& str);//使用一个string对象初始化另一个string对象
string(const char* s);//使用字符串s初始化
string(int n, char c);//使用n个字符c初始化
void test1()
{
//创建一个string容器
string s1("hello world");
cout << s1 << endl;
string s2 = s1;
cout << s2 << endl;
string s3(10, 'w');
cout << s3 << endl;
}
1.1.2.2 string基本赋值操作
string& operator=(const char* s);//char*类型字符串 赋值给当前的字符串
string& operator=(const string &s);//把字符串s赋给当前的字符串
string& operator=(char c);//字符赋值给当前的字符串
string& assign(const char *s);//把字符串s赋给当前的字符串
string& assign(const char *s, int n);//把字符串s的前n个字符赋给当前的字符串
string& assign(const string &s);//把字符串s赋给当前字符串
string& assign(int n, char c);//用n个字符c赋给当前字符串
string& assign(const string &s, int start, int n);//将s从start开始n个字符赋值给字符串
void test2()
{
string s1;
s1 = "nihao beijing";
cout << s1 << endl;
string s2;
s2 = s1;
cout << s2 << endl;
string s3;
s3 = 'p';
cout << s3 << endl;
string s4;
s4.assign("nihao beijing", 5);
cout << s4 << endl;
s4.assign(s1, 3, 8);
cout << s4 << endl;
}
1.1.2.3 string存取字符操作
char& operator[](int n);//通过[]方式取字符
char& at(int n);//通过at方法获取字符
string拼接操作
string& operator+=(const string& str);//重载+=操作符
string& operator+=(const char* str);//重载+=操作符
string& operator+=(const char c);//重载+=操作符
string& append(const char *s);//把字符串s连接到当前字符串结尾
string& append(const char *s, int n);//把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s);//同operator+=()
string& append(const string &s, int pos, int n);//把字符串s中从pos开始的n个字符连接到当前字符串结尾
string& append(int n, char c);//在当前字符串结尾添加n个字符c
void test3()
{
string s1("hello world");
//[]运算符重载函数和at函数都是用于获取一个字符,
//但是at函数内部有异常处理机制,越界操作会抛出异常,
//而[]运算符重载函数则不会
//cout << s1[100] << endl;
try {
cout << s1.at(20) << endl;
} catch (exception &e) {
cout << e.what() << endl;
}
s1 = s1 + "nihao beijing";
cout << s1 << endl;
s1 += "hahaha";
cout << s1 << endl;
string s2;
s2.append(s1, 0, 11);
cout << s2 << endl;
}
1.1.2.4 string查找和替换
int find(const string& str, int pos = 0) const; //查找str第一次出现位置,从pos开始查找
int find(const char* s, int pos = 0) const; //查找s第一次出现位置,从pos开始查找
int find(const char* s, int pos, int n) const; //从pos位置查找s的前n个字符第一次位置
int find(const char c, int pos = 0) const; //查找字符c第一次出现位置
int rfind(const string& str, int pos = npos) const;//查找str最后一次位置,从pos开始查找
int rfind(const char* s, int pos = npos) const;//查找s最后一次出现位置,从pos开始查找
int rfind(const char* s, int pos, int n) const;//从pos查找s的前n个字符最后一次位置
int rfind(const char c, int pos = 0) const; //查找字符c最后一次出现位置
string& replace(int pos, int n, const string& str); //替换从pos开始n个字符为字符串str
string& replace(int pos, int n, const char* s); //替换从pos开始的n个字符为字符串s
1.1.2.5 string比较操作
/*
compare函数在>时返回 1,<时返回 -1,==时返回 0。
比较区分大小写,比较时参考字典顺序,排越前面的越小。
大写的A比小写的a小。
*/
int compare(const string &s) const;//与字符串s比较
int compare(const char *s) const;//与字符串s比较
string子串
string substr(int pos = 0, int n = npos) const;//返回由pos开始的n个字符组成的字符串
1.1.2.6 string插入和删除操作
string& insert(int pos, const char* s); //插入字符串
string& insert(int pos, const string& str); //插入字符串
string& insert(int pos, int n, char c);//在指定位置插入n个字符c
string& erase(int pos, int n = npos);//删除从Pos开始的n个字符
string和c-style字符串转换
//string 转 char*
string str = "itcast";
const char* cstr = str.c_str();
//char* 转 string
char* s = "itcast";
string str(s);
2.2 vector容器
3.2.1 相关概念
vector容器的操作类似数组,本质就是一个数组的操作
3.2.2 vector容器的未雨绸缪机制
//vector容器的未雨绸缪机制
//vector当空间容量不够用时,会开辟新的空间,将原本空间的内容拷贝到
//新的空间,然后将原来的空间释放,如果每次都这样做,效率比较低,所以
//vector开辟新空间时,会多预留出来一部分,这样做就不会多次开辟空间了
#include <iostream>
#include <vector>
using namespace std;
void test1()
{
vector<int> v;
for(int i = 0; i <= 30; i++)
{
v.push_back(i);
cout << "容量:" << v.capacity() << ",实际:" << v.size() << endl;
}
}
int main()
{
test1();
return 0;
}
执行结果
2.2.3 vector常用API操作
2.2.3.1 vector构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。
vector(n, elem);//构造函数将n个elem拷贝给本身。
vector(const vector &vec);//拷贝构造函数。
//例子 使用第二个构造函数 我们可以...
int arr[] = {2,3,4,1,9};
vector<int> v1(arr, arr + sizeof(arr) / sizeof(int));
2.2.3.2 vector常用赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
vector& operator=(const vector &vec);//重载等号操作符
swap(vec);// 将vec与本身的元素互换。
#include <iostream>
#include <vector>
using namespace std;
void Printfvector(vector<int> v)
{
for(vector<int>::iterator it = v.begin(); it < v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test1()
{
int arr[] = {100, 200, 300, 400, 500, 600};
vector<int> v(arr, arr+4);
vector<int> v1;
Printfvector(v);
v1.assign(v.begin(), v.end());
Printfvector(v1);
v1.assign(10, 666);
Printfvector(v1);
cout << "v: 容量=" << v.capacity() << ",实际=" << v.size() << endl;
cout << "v1: 容量=" << v1.capacity() << ",实际=" << v1.size() << endl;
//调用swap函数交换两个容器之后,同两个容器的容量和实际使用都会发生变化
v1.swap(v);
cout << "*********************" << endl;
cout << "v:";
Printfvector(v);
cout << "v1:";
Printfvector(v1);
cout << "v: 容量=" << v.capacity() << ",实际=" << v.size() << endl;
cout << "v1: 容量=" << v1.capacity() << ",实际=" << v1.size() << endl;
cout << "*********************" << endl;
}
int main()
{
test1();
return 0;
}
2.2.3.3 vector大小操作
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长>度的元素被删除。
capacity();//容器的容量
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。
vector数据存取操作
at(int idx); //返回索引idx所指的数据,如果idx越界,抛出out_of_range异常。
operator[];//返回索引idx所指的数据,越界时,运行直接报错c
front();//返回容器中第一个数据元素
back();//返回容器中最后一个数据元素
#include <iostream>
#include <vector>
using namespace std;
void Printfvector(vector<int> v)
{
for(vector<int>::iterator it = v.begin(); it < v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test1()
{
int arr[] = {100, 200, 300, 400, 500, 600};
vector<int> v(arr, arr+6);
cout << "第一个元素:" << v.front() << endl;
cout << "最后一个元素:" << v.back() << endl;
cout << v[0] << endl;
//at函数内部有异常处理机制
cout << v.at(3) << endl;
cout << "*************" << endl;
Printfvector(v);
cout << "v: 容量=" << v.capacity() << ",实际=" << v.size() << endl;
//resize的使用
//如果设置的值大于原本的容量,则容量和实际使用都会改变,并且将多与实际使用的位置填0
//如果设置的值小于原本的容量,则容量不变,实际使用的变为设置的值,其他位置的值会移除
//v.resize(10);
//v.resize(4);
//reserve的使用
//如果设置的值大于原本的容量,则容量改变,但是实际使用不变
//如果设置的值小于原本的容量,则容量和实际使用都不变
//v.reserve(10);
v.reserve(4);
Printfvector(v);
cout << "v: 容量=" << v.capacity() << ",实际=" << v.size() << endl;
}
int main()
{
test1();
return 0;
}
2.2.3.4 vector插入和删除操作
insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele.
push_back(ele); //尾部插入元素ele
pop_back();//删除最后一个元素
erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
erase(const_iterator pos);//删除迭代器指向的元素
clear();//删除容器中所有元素
for_each
for_each内部实现:
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function fn)
{
while (first!=last) {
fn (*first);
++first;
}
return fn; // or, since C++11: return move(fn);
}
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function fn);
功能:获取容器中的元素
参数:
first:起始迭代器
last:结束迭代器
fn:回调函数,for_each函数会将每一个元素传递给回调函数,没传一次,回调函数调用一次
for_each(v.begin(), v.end(), printVectorInt);
void printVectorPerson(Person obj)
{
cout << obj.name << ", " << obj.score << endl;
}
sort
//排序算法
//sort是一个全局函数
//默认按照从小到大的顺序排列
//sort(v.begin(), v.end());
//也可以自己设置策略来排序
//sort(v.begin(), v.end(), greater<int>());
class Person{
public:
Person(){}
Person(string name, int score):name(name),score(score){}
string name;
int score;
};
void printVectorPerson(Person obj)
{
cout << obj.name << ", " << obj.score << endl;
}
//编写策略
bool myCompare(Person obj1, Person obj2)
{
return obj1.score < obj2.score;
}
void test6()
{
vector<Person> v;
v.push_back(Person("zhangsan", 90));
v.push_back(Person("lisi", 80));
v.push_back(Person("wangwu", 100));
for_each(v.begin(), v.end(), printVectorPerson);
//sort函数默认只能排序数值型数据,如果要排序类的对象,需要自己编写策略
sort(v.begin(), v.end(), myCompare);
for_each(v.begin(), v.end(), printVectorPerson);
}
int main()
{
test6();
return 0;
}
截取字符串
void test()
{
string s1("123:456:789:666");
string s2;
int n = 0, pos = 0;
while(1)
{
if(n == -1)break;
n = s1.find(':',pos);
//cout << pos << endl;
s2 = s1.substr(pos,n-pos);
cout << s2 << endl;
pos = n + 1;
}
}
作业:
学习deque容器
有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除最低分,取平均分,最终将前三名选手的姓名和分数输出 rand函数,srand设置随机种子 rand()%41 + 60; 排序sort,然后删除头尾
#include <iostream>
#include <vector>
#include <algorithm>
#include <deque>
#include <time.h>
using namespace std;
//有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,
//去除最低分,取平均分,最终将前三名选手的姓名和分数输出
class Person{
public:
Person(){}
Person(string name, double score):name(name),score(score){}
void pringMsg()
{
cout << "姓名:" << this->name << ",平均分:" << this->score << endl;
}
void setScore(double score)
{
this->score = score;
}
string getName()
{
return this->name;
}
double getScore()
{
return this->score;
}
private:
string name;
double score;
};
void printDeque(double val)
{
cout << val << " ";
}
void getScore(Person &obj)
{
cout << "选手" << obj.getName() << "的分数为:" << endl;
//创建一个deque容器保存每一位选手的分数
deque<double> myscore;
for(int i = 0; i < 10; i++)
{
myscore.push_back(rand() % 41 + 60);
}
//排序
sort(myscore.begin(), myscore.end());
for_each(myscore.begin(), myscore.end(), printDeque);
cout << endl;
//删除最大和最小的成绩
cout << "删除最高分和最低分:" << endl;
myscore.pop_back();
myscore.pop_front();
for_each(myscore.begin(), myscore.end(), printDeque);
cout << endl;
//求平均值
double sum = 0;
for(deque<double>::iterator it = myscore.begin(); it < myscore.end(); it++)
{
sum += *it;
}
cout << "平均值为:" << sum / 8.0 << endl;
obj.setScore(sum / 8.0);
}
void printVector(Person obj)
{
obj.pringMsg();
}
bool myCompare(Person obj1, Person obj2)
{
return obj1.getScore() > obj2.getScore();
}
int main()
{
//设置随机种子,保证每次执行获取到的随机值不一样
srand(time(NULL));
//创建保存选手姓名和平均分的容器
vector<Person> v;
v.push_back(Person("张三", 0));
v.push_back(Person("李四", 0));
v.push_back(Person("王五", 0));
v.push_back(Person("赵六", 0));
v.push_back(Person("田七", 0));
vector<Person>::iterator it = v.begin();
for(int i = 0; i < 5; i++)
{
getScore(*it);
it++;
}
//获取完分数之后进行排序
sort(v.begin(), v.end(), myCompare);
cout << "*******************" << endl;
cout << "最终的选手成绩为:" << endl;
for_each(v.begin(), v.end(), printVector);
cout << "冠军为:";
(*(v.begin())).pringMsg();
cout << "亚军为:";
(*(v.begin() + 1)).pringMsg();
cout << "季军为:";
(*(v.begin() + 2)).pringMsg();
return 0;
}
#include <iostream>
#include <exception>
#include <vector>
#include <algorithm>
#include <numeric>
#include <stdlib.h>
#include <time.h>
#include <deque>
#include <iterator>
using namespace std;
class Person{
public:
Person(){}
Person(string name, int score):name(name),score(score){}
string Getname()
{
return this->name;
}
int Getscore()
{
return this->score;
}
void Setname(string name)
{
this->name = name;
}
void Setscore(int score)
{
this->score = score;
}
private:
string name;
int score;
};
void printVectorPerson(Person obj)
{
cout << obj.Getname() << ", " << obj.Getscore() << endl;
}
//编写策略
bool myCompare(Person obj1, Person obj2)
{
return obj1.Getscore() > obj2.Getscore();
}
Person Average_scores(Person &p)
{
deque<int> d;
deque<int>::iterator it;
int add = 0;
for(int i=0; i<10; i++)
{
d.push_back(int(rand()%41 + 60));
}
sort(d.begin(), d.end());
d.pop_back();
d.pop_front();
for(it = d.begin(); it < d.end(); it++)
{
add += (*it) ;
}
add=add/8;
p.Setscore(add);
cout << p.Getname() << "的平均成绩为:" << add << endl;
return p;
}
void test()
{
srand((unsigned)time(NULL));
Person A, B, C, D, E;
vector<Person> v;
A.Setname("A");
B.Setname("B");
C.Setname("C");
D.Setname("D");
E.Setname("E");
A = Average_scores(A);
B = Average_scores(B);
C = Average_scores(C);
D = Average_scores(D);
E = Average_scores(E);
v.push_back(Person(A.Getname(),A.Getscore()));
v.push_back(Person(B.Getname(),B.Getscore()));
v.push_back(Person(C.Getname(),C.Getscore()));
v.push_back(Person(D.Getname(),D.Getscore()));
v.push_back(Person(E.Getname(),E.Getscore()));
sort(v.begin(), v.end(),myCompare);
cout << endl << "前三名为:" << endl;
for_each(v.begin(), v.begin()+3, printVectorPerson);
}
int main()
{
test();
return 0;
}