美文网首页
二、常用容器(String、Vector、Deque)

二、常用容器(String、Vector、Deque)

作者: 木鱼_cc | 来源:发表于2018-06-15 13:18 被阅读0次

1.string容器

1.1string特性

说到string的特性,就不得不合char *类型的字符串对比:

  • Char*是一个指针,String是一个类
    string封装了char*,管理这个字符串,是一个char*型的容器

  • String封装了很多实用的成员方法
    查找find,拷贝copy,删除delete,替换replace,插入insert

  • 不用考虑内存释放和越界
    string管理char*所分配的内存。每一次string的复制,取值都由string类负责维护,不用担心复制越界或者取值越界等

string和char*可以相互转换吗?如果能,怎么转换?

答案是可以转换。string转char*通过string提供的c_str()方法

//string转char*
string str = "string";
const char* cstr = str.c_str();
//char* 转string
string sstr(s);
1.2 string常用API

string构造函数:

string();//创建一个空字符串 例如:string str;
string(const string &str);//使用一个string对象初始化另一个string对象
string(const char *s);//使用字符串s初始化
string(int n,char c);//使用n个字符c初始化

//例子
//默认构造函数
string s1;

//拷贝构造函数
string s2(s1);
string s2 = s1;

//带参数构造函数
char *str = "string";
string s3(str);
string s4(10,'a')

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个字符赋给字符串

string存取字符操作(warning 面试)

char& operator[](int n);//通过[]方式取字符
char& at(int n);//通过at方法获取字符
//[] 访问方式访问越界的时候,不会抛异常,直接挂掉
//at 会抛出异常,可以被catch抓到
int size();//返回字符串长度


string s("abcdefg");
char c = s[1];
char c2 = s.at(1);

字符串拼接操作

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

字符串查找和替换

//不存在的话返回-1
int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置
int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置
int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
int rfind(char c, int pos = npos) const;//查找字符c最后一次出现的位置
int rfind(const char *s, int pos = npos) const;//查找s最后一次出现的位置,从pos开始查找
int rfind(const char *s, int pos = npos, int n) const;//从pos查找s的前n个字符最后一次位置
int rfind(const string &s,int pos = npos) const;//查找str最后一次位置,从pos开始查找
string& replace(int pos,int n,const string& str);//替换从pos开始n个字符为字符串str
string& replace(int pos,int n,const char* s);//替换从pos开始的n个字符为字符串s

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个字符组成的字符串

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个字符

练习

#include <iostream>
#include <string>

//1.判断邮箱有效性,是否包含@和. 并且.在@之后
//2.判断用户输入的用户名中是否包含除了小写字母之外字符
//3.判断用户输入的邮箱地址是否正确

int main()
{
    string email = "asdffas@hotmail.com";
    
    int pos1 = email.find('@');//不存在的话
    int pos2 = email.find('.');

    if (pos1 == -1 || pos2 == -1 )
    {
        cout<<"邮箱中不包含@或.  !!!"<<endl;

        return 0;
    }

    if ( pos1 > pos2)
    {
        cout<<"输入邮箱不合法"<<endl;
    }
  
    string username = email.substr(0,pos1);
    
    string::iterator pStar = username.begin();
    string::iterator pEnd = username.end();

    while(pStar != pEnd){
        if (!(*pStar >= 'a' && *pStar <= 'z')){     
            cout<<"输入字符包含非小写字母"<<endl;
            return 0;
        }

        pStar++;
    }
    string rightEmail = "zhaosi@itcast.cn";
    int ret = email.compare(rightEmail);
    if (ret != 0)
    {
        cout<<"邮箱地址不存在"<<endl;
        return 0;
    }
    cout<<"邮箱地址正确"<<endl;
    return 0;
}

2.vector容器

1.png

初始化

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));//就是指针!!!!!

vector<int> v;
vector<int> v2(10,5);
vector<int> v3(v2.begin(),v2.end());
vector<int> v4(v3);

常用赋值方法

void assign(input_iterator beg,input_iterator end);//将[beg,end]区间中的数据拷贝赋值给本身
void assign(n,elem);//将n个elem拷贝赋值给本身
vector & operator=(const vector &vec);//重载等号操作符
void swap(vec);//swap()函数交换当前vector与vector from的元素


//第一个赋值函数,可以这么写
int arr[] = {0,1,2,3,4,5};
vector<int> v1;
v1 = assign(arr,arr+5);//使用数组初始化v1

vector<int> v2;
v2 = assign(v1.begin(),v1.end());

大小操作

size_type size();//返回容器中元素的个数
bool empty();//判断容器是否为空
void resize(int num);//重新制定容器的长度为num,若容器变长,则以默认值填充新位置。
                //如果容器变短,则末尾超出容器长度的元素被删除
size_type capacity();//返回容器的容量
void reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问

注意:resize若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除

数据存取操作

TYPE at(int idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
operator[];//返回索引idx所指的元素,越界时,运行直接报错
TYPE front();//返回容器中的第一个数据元素
TYPE back();//返回容器中的最后一个数据元素

插入和删除操作

iterator insert(iterator loc,const TYPE &val);//在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器
void insert(iterator loc,size_type num,const TYPE &val);//在指定位置loc前插入num个值为val的元素
void insert(iterator pos,input_iterator start,input_iterator end);//在指定位置loc前插入区间[start, end)的所有元素 .
void push_back(elem);//尾部插入元素elem
void pop_back();//删除最后一个元素
iterator erase(const_iterator start,const_iterator end);//删除迭代器从start到end之间的元素
iterator erase(const_iterator pos);//删除迭代器指向的元素
void clear();//删除容器中的所有元素

总结
vector是个动态数组,当空间不足的时候插入新元素,vector会重新申请一块更大的内存空间,将旧空间数据拷贝到新空间,然后释放旧空间。vector是单口容器,所以在尾端插入和删除元素效率较高

size()和capacity()的区别
部分区别解释

1 发现空间不足,重新申请一块更大的内存
2 将旧空间的数据拷贝新空间
3 旧空间释放掉

#include <iostream>
#include <vector>

int main()
{
    int count;
    int *p = NULL;
    vector<int> v;
    //因为频繁的申请内存,会造成效率降低
    //所以我们可以用reserve()函数预先申请内存空间,这样容器就不需要再申请空间了
    v.reserve(100000);
    for(int i = 0;i<100000;i++){
          v.push_back(i);
          if (p != &v[0])//记录地址重新分配次数
          {
            count++;
            p = &v[0];
          }
    }
    cout<<"count:"<<count<<endl;//30   //1
    cout<<"容量:"<<v.capacity()<<endl;//看容量138255  //100000
    cout<<"大小:"<<v.size()<<endl;//100000        //100000

    return 0;
}

3.deque容器

3.1deque特性

deque是“double-ended queue”的缩写,和vector一样,deque也支持随机存取。vector是单向开口的连续性空间,deque则是一种双向开口的连续性空间,所谓双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,vector当然也可以在头尾两端进行插入和删除操作,但是头部插入和删除操作效率奇差,无法被接受

2.png
3.2deque常用API

deque构造函数

deque<T> deqT;//默认构造函数
deque(iterator beg,iterator end);//构造函数将[beg,end)区间中的元素拷贝给自身
deque(int num,const TYPE elem);//构造函数将n个elem拷贝给自身
deque(const deque &deq);//拷贝构造函数

deque赋值操作

void assign(iterator beg,iterator end);//将[beg,end)区间中的数据拷贝赋值给本身
void assign(int num,const TYPE &elem);//将n个elem拷贝赋值给本身
deque & operator=(const deque &deq);//重载等号操作符
void swap(deq);//将deq与本身的元素互换

deque大小操作

deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新制定容器的长度为Num,若容器边长,则以默认值填充新位置。
                  //如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num,const TYPE &elem);//重新制定容器的长度为Num,若容器边长,则以elem填充新位置。
                                   //如果容器变短,则末尾超出容器长度的元素被删除

deque双端插入和删除操作

void push_back(const TYPE &elem);//在容器尾部添加一个数据
void push_front(const TYPE &elem);//在容器头部插入一个数据
void pop_back();//删除容器最后一个数据
void pop_front();//删除容器第一个数据

deque数据存取

TYPE at(int index);//返回索引idex所指的数据,如果idx越界,会抛出out_of_range
TYPE operator [](int index);//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错
TYPE front();//返回第一个数据
TYPE back();//返回最后一个数据

deque插入操作

int insert(iterator pos,const TYPE &val);//在pos位置插入一个elem元素的拷贝,返回新数据的位置
iterator insert( iterator pos, size_type num, const TYPE &val );//在Pos位置插入num个elem元素
void insert( iterator pos, input_iterator start, input_iterator end );//在pos位置插入[beg,end)区间的数据


4.练习

#warning 对push_back()函数有理解!!!

#include <iostream>
#include <deque>
#include <string>
#include <vector>
#include <algorithm>

//评委打分案例(sort算法排序)
//创建5个选手(姓名,得分),10个评委对5个选手进行打分
//得分规则:去除最高分,去除最低分,取出平均分
//按得分对5名选手进行排名


//选手类
class Player
{
public:
    Player(string name,int score){
        this->name = name;
        this->score = score;
        cout<<"Player()...."<<endl;
    }
    ~Player(){
        cout<<"~Player()...."<<endl;
    }
    string name;
    int score;
private:
}

//创建选手
void Create_Player(vector<Player> &v)
{
    string name_seed = "ABCDE";
    for (int i = 0; i < 5; ++i)
    {   
        string name = "选手";
        name.append(name_seed.at[i]);

        Player p(name,0);//创建选手

        v.push_back(p);
    }
}

//打分
bool mycompare(int v1,int v2)
{
    if (v1 > v2)//从大到小
    {
        return true;
    }
    return false;
}

void Set_Player_Score(vector<Player>& plist)
{
   for(vector<Player>::iterator it = plist.begin(); it != plist.end();it++){
           
           deque<int> dscore;
           for(int i = 0; i < 10;i++){
              int score = 50 + rand() % 50;//打分
              dscore.push_back(score);
           }

          //排序 sort 算法
           sort(dscore.begin(),dscore.end(),mycompare);
           dscore.pop_back();//去除最低分
           dscore.pop_front();//去除最高分

           int totalscore = 0;
           for(deque<int>::iterator dt = dscore.begin(); dt != dscore.end();dt++){
               totalscore += *dt;
           }
           int score_avg = totalscore / dscore.size();
           (*it).score = score_avg;
   }
}

//显示选手得分
void Show_Player_Score(vector<Player> &plist)
{
    for(vector<Player>::iterator it = plist.begin(); it != plist.end();it++){
        cout<<"姓名:"<<(*it).name<<"  "<<"分数:"<<(*it).score<<endl;
    }
}

int main()
{
    vector<Player> vPlayer;//存放选手信息
    Create_Player(vPlayer);
    Set_Player_Score(vPlayer);
    Show_Player_Score(vPlayer);
    return 0;
}

相关文章

网友评论

      本文标题:二、常用容器(String、Vector、Deque)

      本文链接:https://www.haomeiwen.com/subject/iliyeftx.html