C++基础的不能再基础的学习笔记——顺序容器(其他操作)

顺序容器

顺序容器基本操作:http://blog.csdn.net/fancynece/article/details/79193881

我们已经对容器的公有操作和顺序容器的操作有了一定的了解,接下来,我们要进一步学习顺序容器。

一、vector、string对象的增长

通常情况下,我们不必关心一个标准库类型是如何实现的,但是对于vector和string来说, 部分实现渗透到了接口中。

当我们向vector和string中添加元素时,若容器没有空间容纳新元素,那么不可能随意找到一个位置存放(因为元素必须连续存储)。此时,容器必须分配新的内存空间,将原来的元素拷贝并添加新元素,再释放原有空间。若每次添加元素都要进行分配内存,将会十分低效。

为了提高效率,我们规定,向容器中添加元素时,如果容器没有空间容纳新元素,那么会分配给它大于需求的内存,留作备用。

标准库给我们提供了可以管理容量的成员函数。

.
c.capacity( )容器在不扩张内存的情况下,可以容纳多少元素
c.reserve(n)将容器预先分配的内存设置为n
c.shrink_to_fit( )将capacity减少到与size同大小

其中,capacity和reserve只适用于vector、string,shrink_to_fit适用于vector、string、deque。

对于c.reserve(n);需求大小 > 当前容量 时,reserve会分配至少和需求一样大的容量(可能更大)。而当 需求大小 <= 当前容量 时,reserve什么也不做。

也就是说,reserve不会减少容器的内存空间。与此不同的是,之前了解到的resize()函数,仅仅改变容器的元素, 不会改变容器的内存空间。

capacity和size

capacity是 在不重新分配内存时,容器可以容纳元素的个数。

size是 容器当前已保存的元素个数。

vector<int> ve;

//size为0,capacity依赖于具体实现
cout << "size:" << ve.size() 
    << "capacity:" << ve.capacity() << endl;

for (vector<int>::size_type i = 0; i != 14; ++i)
    ve.push_back(i);

//size为14,capacity依赖于具体实现
cout << "size:" << ve.size() 
    << "capacity:" << ve.capacity() << endl;

//预分配30个内存空间
ve.reserve(30);
cout << "size:" << ve.size() 
    << "capacity:" << ve.capacity() << endl;

//用完这些空间
while (ve.size() != ve.capacity())
    ve.push_back(1);
cout << "size:" << ve.size() 
    << "capacity:" << ve.capacity() << endl;

//再添加元素
ve.push_back(2);
cout << "size:" << ve.size() 
    << "capacity:" << ve.capacity() << endl;

//归还内存
ve.shrink_to_fit();
cout << "size:" << ve.size() 
    << "capacity:" << ve.capacity() << endl;

运行结果如下图所示:
这里写图片描述

二、额外的string操作

在之前的学习中http://blog.csdn.net/fancynece/article/details/79084054
我们已经对string有了初步了解,而作为容器的一种,string除了顺序容器所提供的操作之外,还有许多额外的操作,一般与字符数组、下标有关。

1. 构造string的其他方法
.
string s(cp,n);cp为数组,s为cp的前n个字符
string s(s1,pos);s1为字符串,s为字符串s1自pos开始的字符
string s(s1,pos,n);s1为字符串,s为字符串s1自pos开始的n个字符
const char *cp = "Hello,world!";
char noNull[] = { 'H','i' ,'!'};

string s1(cp);        //Hello,world!
string s2(noNull, 2); //Hi
string s3(cp + 6, 5); //world
string s4(s1, 6, 5);  //world
string s5(s1, 6);     //world!
substr操作
.
s.substr(pos,n);返回一个字符串,由字符串s自pos开始的n个字符构成,pos默认为0,n默认为s.size( ) - pos
//s1为"Hello,world!"
cout << s1.substr(0, 5) << endl; //Hello
cout << s1.substr(6) << endl;    //world!
cout << s1.substr() << endl;     //Hello,world!
2. 改变string的其他方法
.
s.insert(pos,args);在pos之前插入args,pos可以是下标、迭代器。下标返回s的引用,迭代器返回第一个插入字符的迭代器
s.erase(pos,n);删除从pos开始的n个元素,若省略n,则删除pos开始的所有字符。返回s的引用
s.assign(args);将s替换为args
s.append(args);将args追加到s
s.replace(b,e,args);删除迭代器b和e范围的字符,替换为args
s.replace(pos,n,args);删除pos开始的n个字符,替换为args

其中,args可以是下列形式之一。

  • str (字符串)
  • str,pos,n (字符串从pos开始的n个字符)
  • cp,n (数组cp的前n个字符)
  • cp (数组cp)
  • n,c (n个字符c)
  • b,e (迭代器b和e范围内的字符)
  • 初始化列表

我们可以看出,assign和append操作无须给出位置参数,因为assign总是全部替换,而append总是在末尾追加。而需要给出位置参数的函数,可以是迭代器,也可以是下标。

归根结底,string的操作特殊在 它可以接受字符数组为参数,可以接受下标为参数,此前顺序容器中必须由一对迭代器表示的范围,也可由起始位置和长度来表示。

const char c[] = { 'l','o','l','i','t','a',',' };
string temp = "My sunshine";

string s;

s.insert(0, "My love,");  //下标
s.insert(s.size(),c,7);     //下标
s.append(temp,0);
cout << s << endl;

s.erase(0, 3);
cout << s << endl;

s.replace(12, 6, 4, 'o');
cout << s << endl;
3. string搜索操作

string提供了6个不同的搜索函数,每个函数都有4个重载版本。若找到则返回匹配发生位置的下标(string::size_type类型),若找不到则返回string::npos。

.
s.find(args)查找s中args第一次出现的位置
s.rfind(args)查找s中args最后一次出现的位置
s.find_frist_of(args)在s中查找args中任何一个字符第一次出现的位置
s.find_last_of(args)在s中查找args中任何一个字符最后一次出现的位置
s.find_frist_not_of(args)在s中查找第一个不在args中的字符
s.find_last_not_of(args)在s中查找最后一个不在args中的字符

其中,args可以是下列之一。

  • c,pos (从位置pos开始查找字符c,pos默认为0)
  • s2,pos (从位置pos查找字符串s2,pos默认为0)
  • cp,pos (从位置pos查找字符数组cp,pos默认为0)
  • cp,pos,n (从位置pos查找字符数组的前个字符,pos和n无默认值)
string name("fancynaomi");
cout << name.find("fancy") << endl;
cout << name.find('n', 4) << endl;

string  ch("suorn");
cout << name.find_first_of(ch) << endl; //name中第一个在ch中的为n
cout << name.find_last_of(ch) << endl;  //name中最后一个在ch中的为o
cout << name.find_first_not_of(ch) << endl;  //name中第一个不在ch中的为f
cout << name.find_last_not_of(ch) << endl;   //name中最后一个不在ch中的为i

查找一个字符串中的所有子串。

string ct = "My name is fancy.My bro is cute.";
string::size_type st = 0;

while ((st = ct.find("is", st)) && st != string::npos) {
    cout << "在" << st << "处发现" << "is" << endl;
    ++st;
}
4. compare函数

除了关系运算符之外,标准库string还提供了一组compare函数,根据 s 是等于、大于、小于参数指定的字符串,返回0、正数、负数

可以比较两个字符串一个字符串和一个字符数组,并且都可以比较一部分字符。

s.compare重载的几种形式。

  • s.compare(s1): 比较s和s1
  • s.compare(pos,n,s1): 将 s中从pos开始的n个字符 与s2 比较
  • s.compare(pos,n,s1,pos1,n1): 将 s从pos开始的n个字符 与 s1从pos1开始的n1个字符 比较
  • s.compare(cp): 比较s和字符数组cp
  • s.compare(pos,n,cp): 将 s中从pos开始的n个字符 与cp 比较
  • s.compare(pos,n,cp,n1): 将 s中从pos开始的n个字符 与cp的前n1个字符 比较
5. 数值转换

新标准引入了多个函数,实现数值数据和string之间的转换。string可以和任何算术类型进行转换。当string不能转换为一个数值时,会抛出异常。

.
to_string(value);value为任意算术类型
stoi(s,p,b);将字符串s转换为int类型。p是size_t的指针,保存s中第一个非数值字符的下标,默认不保存。b是转换所用的基数。相同的,也可以转换为long、unsigned long、long long、unsigned long long。
stof(s,p);将字符串s转换为float类型。p是size_t的指针,保存s中第一个非数值字符的下标,默认不保存。相同的,也可以转换为double、long double。
三、容器适配器

除了顺序容器外,标准库还定义了三个顺序容器适配器:stack、queue、priority_queue(优先队列)。

什么是适配器?适配器是一种机制,能使某种事物的行为看起来像另一种事物。容器、迭代器、函数都有适配器。

例如,stack适配器接受一个顺序容器,并使其操作起来像一个stack一样。

容器适配器支持的操作如下。

.
size_type
value_type元素类型
container_type底层容器类型
A a;创建空适配器
A a(b);创建适配器,带有容器b的拷贝
== != > >= < <=返回底层容器的比较结果
a.empty()判空
a.size()返回a中元素数目
swap(a,b)交换a和b,类型必须相同
1. 定义适配器

默认情况下,stack和queue是基于deque实现的,默认容器类型为deque。而priority_queue是基于vector实现的,默认容器类型为vector。但是可以显示地改变容器类型。

  • 默认构造函数stack<int> stk;其中stk可以接受一个deque<int>类型的对象。
  • 将顺序容器作为第二个类型参数,重载默认容器类型。
vector<string> vs(5, "st");
stack<string, vector<string>> stk(vs);//stack现在为vector的适配器

所有的适配器都要求容器可以添加、删除元素,因此适配器不能构造在array、forward_list上。(array不可增删元素,forward_list不可增删尾元素)。

stack只要求push_back、pop_back、back操作,可以使用除array和forward_list外的所有容器。

queue要求push_back、pop_front、back、front操作,因此只能使用deque和list。

priority_queue要求push_back、pop_back、front、随机访问操作,因此只能使用deque、vector。

2. 栈适配器
.
s.pop();删除栈顶元素,不返回该元素的值
s.top();返回栈顶元素的值,不删除元素
s.push(item);压入元素
s.empalce(args);压入由args构造的元素
3. 队列适配器

queue和priority_queue定义在queue头文件中。

.
q.pop( );删除queue首元素/priority_queue优先级最高的元素,不返回元素
q.front( );返回首元素/尾元素,不删除元素
q.back( );只适用于queue
q.top( );只适用于priority_queue,返回优先级最高的元素,不删除元素
q.push(item);压入元素
q.emplace(args);压入由args构造的元素
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值