string类的erase函数属于stl吗_C++之STL之容器篇

92aa28ebfabf9aa3d56e9f346c153d73.png

C++STL

容器篇

vector

向量,就是可变长的数组,可以在末尾插入元素。拥有数组的所有特性。完全可以代替数组。

  • 能像数组一样随机访问
  • 可以在末尾插入元素push_back()
  • 使用insert(),在某个元素位置前插入新的元素。给出一个迭代器和插入的值,在该迭代器前插入
  • begin(),end()方法,返回vector首尾的迭代器。迭代器被设计得像一个指针,取元素就使用*end()指向的元素不属于容器
  • 给出一个迭代器定义的例子:vector<int>::iterator ite
  • erase(),clear(),后者删除全部元素,前者删除一个或者一段元素。
  • 迭代器给出的区间都是左开右闭,因为右边的迭代器是无法被访问到的size()可以知道向量的大小,empty()就是问容器是否为空,空就返回1,非空就返回0
  • reverse()反转序列,给出首尾迭代器,将范围内的元素序列反转
  • sort()升序排列,和上一个算法一样,给出首尾迭代器
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool cmp(const int& a, const int& b);
int main()
{
    // 容器的基本使用
    vector<int> v1;           //大小不确定,但是初始是3,貌似
    vector<int> v2(10);       //大小为10的容器,下标0~9,值被初始化为0
    vector<double> v3(10,8.6);//大小为10,初值为8.6
    v.push_back(2);
    v.push_back(2);
    // 迭代器的遍历
    vector<double> v4(3);
    v4[1] = 1;
    v4[2] = 2;
    v4[3] = 3;
    vector<double>::iterator ite;
    for(ite = v4.begin(); ite != v.end(); ite++)
        cout << *ite << " ";
    cout << endl;
    // 元素的删除
    v4.erase(v4.begin());
    for(ite = v4.begin(); ite != v4.end(); ite++)
        cout << *ite << " ";
    cout <<endl;
    // reverse反转序列
    vector<int> v(10);
    for(int i = 0; i < 10; i++)
        v[i] = i;
    reverse(v.begin(),v.end());
    vector<int>::iterator ite;
    for(ite = v.begin(); ite != v.end(); ite++)
        cout << *ite << " ";
    cout << endl;
    // sort从小到大排列
    vector<int> v(10);
    vector<int>::iterator ite;
    for(int i = 0; i < 10; i++)
        v[i] = 9 - i;
    for(ite = v.begin(); ite != v.end(); ite++)
        cout << *ite << " ";
    cout << endl;
    sort(v.begin(),v.end());
    for(ite = v.begin(); ite != v.end(); ite++)
        cout << *ite << " ";
    cout << endl;

}

// 自己设计一个比较函数,首先,明确问题就是
// 返回值肯定是bool,传入参数的类型就是要比较的类型
// 这里设计的是从大到小排序,所以问题就是 a 大于 b吗?
// 正常的就是直接 运算 a > b,这个问题就是 a大于b吗
// 唯一注意就是 a == b的时候,等于的时候,就随便谁大都可以
bool cmp(const int& a, const int& b)
{
    if( a == b) return a > b;
    else return a > b;
}

string

这个东西是STL提供的字符串,拥有添加,删除,替换,查找和比较的方法。

头文件就是#include<string>

  • 对象的创建
  • 对象的赋值,一般使用C语言的字符指针
// scanf输入给字符数组,然后再赋值给string
char ss[5000];
scanf("%s",ss);
string s;
s = ss;
  • 在string对象的尾部添加字符使用+或者append(),后者括号中的格式为char*
  • string插入字符串insert(),给出一个迭代器和要插入的值,这里的值是char
  • string对象的一个元素就是一个char,所以上一点插入的值就是char类型
  • 删除部分string对象,erase()函数,使用迭代器。
  • 字符串的搜索find()
  • compare()成员函数,按字典序来比较
  • reverse()函数将迭代器选择的范围的元素反转序列
  • string对象可以作为vector的元素
  • 如果我们要将一个数的每个位都求出来,就要取余,但是这样要花很多时间,直接将数字作为字符串处理就更好
  • printf输出stirng要使用c_str()这个函数
  • sscanf()可以将字符串中的子串提取出来,记住提取的格式要和源字符串契合
  • 数值和string的转化,不能直接赋值,要自己写函数,C语言也有自己的方法。C++有专门的对象ostringstream,istringstream
#include<iostream>
#include<string>
#include<sstream>
using namespace std;

// 数值转化为string 
string convertToString(double x)
{
    ostringstream o;
    if(o << x)
     return o.str();
    return "conversioin error!";
}
// string转化为数值
double convertFromString(const string& s)
{
    istringstream i(s);
    double x;
    if( i >> x)
        return x;
    return 0.0; 
} 

int main()
{
    // 对象的创建,以及赋值,上面还有一种更常用的方法,但是需要scanf
    string s;
    cout << s.length() << endl;
    s = "hello,world!";
    cout << s << endl;
    s[0] = 'l';
    cout << s << endl;

    // append()  其实 + 更方便
    string s;
    s = "hello,world!";
    s.append("a");

    // insert()
    string s;
    s = "hello,world!";
    string::iterator ite;
    ite = s.begin();
    s.insert(ite, '1');
    cout << s << endl;

    // 删除元素:赋空或者erase()
    string s;
    s = "123456789";
    string::iterator ite;
    ite = s.begin();
    s.erase(ite, ite+4);
    cout << s <<endl;

    // 元素替换,replace()方法是先删后添加,不需要使用迭代器,给出起始位置和字符串的长度,然后替代的值
    string s;
    s = "abc456789";
    s.replace(0,3,"123");
    cout << s << endl;

    // 字符串的find,找出符合的第一个字符串,返回字符串的第一个元素的下标
    // 找字符用'',找字符串用""
    string s;
    s = "cat dog cat";
    cout << s.find('c')    << endl;    // 返回 0
    cout << s.find("cat")  << endl;    // 返回 0
    cout << s.find("dong") << endl;    // 返回 4
    cout << s.find("isa")  << endl;    // 返回 18446744073709551615

    // string对象的比较,是按字典序来比较的。
    string s;
    s = "cat dog cat";  
    cout << s.compare("cat") << endl;         // >0
    cout << s.compare("cat dog cat") << endl; // ==0
    cout << s.compare("dog") << endl;         // <0

    // reverse(),将迭代器选择范围内的序列反转,记得#include<algorithm>
    string s;
    s = "hello,world!";
    reverse(s.begin(),s.end());
    cout << s << endl;

    // vector<string>
    vector<string> v;
    v.push_back("jack");
    v.push_back("mike");
    v.push_back("tom");
    cout << v[0] <<endl;              // jack
    cout << v[1] <<endl;              // mike
    cout << v[2] <<endl;              // tom
    cout << v[0][0] <<endl;           // j
    cout << v[0].length() <<endl;     // 4

    // 将读入的数作为字符串处理,求出各个位数之和
    string s;
    int sum = 0;
    s = "1234059";
    for(int i = 0; i<s.length(); i++)
    {
        if(s[i] == '0') sum+=0;
        else if(s[i] ==  '1') sum+=1;
        else if(s[i] ==  '2') sum+=2;
        else if(s[i] ==  '3') sum+=3;
        else if(s[i] ==  '4') sum+=4;
        else if(s[i] ==  '5') sum+=5;
        else if(s[i] ==  '6') sum+=6;
        else if(s[i] ==  '7') sum+=7;
        else if(s[i] ==  '8') sum+=8;
        else if(s[i] ==  '9') sum+=9;
    }
    cout << sum << endl;

    // int sscanf(const char* str, const char* format, ...)
    // 从字符串读取格式化输入
    // str事C字符串,是数据源,format也是C字符串,是一个格式
    // sscanf可以把字符串按自己需要的方式提取出子串,甚至是数字
    string a,b,c;
    char sa[100], sb[100], sc[100];
    sscanf("abc 123 pc","%s %s %s",sa,sb,sc);
    a = sa;
    b = sb;
    c = sc;
    cout << a << " " << b << " " << c <<endl;
    int x,y,z;
    sscanf("1,23$45","%d,%d$%d",&x,&y,&z);
    cout << x << " " << y << " " << z <<endl;

    // 如果直接将数值给string得到的是ASCII码 
    int num = 100;
    string b;
    b = num;
    cout << b << endl;
    // c方法,将数值转化为string 
    char data[10];
    string a;
    sprintf(data, "%d", 1984);
    a = data;
    cout << a << endl;
    // c++,数值转string
    string cc = convertToString(num);
    cout << cc << endl;
    // c++,string转数值
    string dd = "2020";
    int p = convertFromString(dd);
    cout << p + 2 << endl; 

}

set

set集合容器实现了红黑树的平衡二叉检索树的数据结构,不会重复插入相同键值的元素,直接忽略。

检索时采取中序遍历的方式检索效率高于vector,deque,list等容器。

采用中序遍历算法可以将键值由小到大遍历出来,所以平衡二叉检索数在插入元素时,就会自动按键值由由小到大排列。(键就是值)

构造set的目的就是为了快速检索

  • 创建insert()插入,遍历输出是中序遍历,从小到大输出,使用迭代器
  • 反向遍历有反向遍历的迭代器reverse_iterator
  • 元素的删除:删除的对象是 迭代器指向的对象,等于某个键值的对象,一个区间上的元素和清空合集。使用erase(),全部删除使用clear()
  • 元素的检索find(),查找到元素的键值,然后返回一个迭代器,没有找到就返回end()指向的位置
  • 自定义比较函数,使用insert()将元素插入到集合中去的时候,如果没有自定义比较函数,那么会使用默认的从小到大的比较函数。自己写比较函数可以根据元素是不是结构体分类
#include<set>
#include<iostream>
using namespace std;

struct myComp
{
    bool operator() (const int& a, const int& b)
    {
        if( a == b) return a > b;
        else return a > b;
//      return ( a == b) ? a > b : a > b; 这样貌似慢了0.1s
    }
};

struct Foo
{
    string name;
    double score;
    bool operator < (const Foo& a) const
    {
        // 类的内部,所以省略的一个参数,比较大小,现在的问题是 this->score < a.score吗 ?
        // 从小到大排序,排序的关键就是看return里的符号,< 就是从小到大排序
        if(score == a.score) return score < a.score;
        else return score < a.score;
    }
};

int main()
{
    // 创建set对象
    set<int> s;

    // 元素的插入以及中序遍历
    // 插入默认是从小到大插入,也可以自己写比较规则函数
    s.insert(8);
    s.insert(1);
    s.insert(12);
    s.insert(6);
    s.insert(8);
    set<int>::iterator ite;
    for(ite = s.begin();ite!=s.end();ite++)
        cout << *ite << " ";
    cout << endl;

    //使用专门的反向迭代器反向遍历set
    set<int>::reverse_iterator rit;
    for(rit = s.rbegin();rit!=s.rend();rit++)
        cout << *rit << " ";
    cout << endl;

    // 使用erase()删除指定的键值
    s.erase(6);
    for(rit = s.rbegin();rit!=s.rend();rit++)
        cout << *rit << " ";
    cout << endl;
    s.clear();
    cout << s.size() << endl;

    //使用find()寻找键值,返回迭代器
    finder = s.find(20);
    if(finder != s.end())
        cout << "find it!" << endl;
    else 
        cout << "not find!" << endl;
    // 自定义比较函数
    // 在自定义比较函数的时候没有返回值,结果是元素全部插入进去,而且是按插入顺序存储
    // 使用自定义比较函数在定义set的时候,类型中要加入自定义的结构体,相应的迭代器的类型也要改变
    // 1、元素不是结构体
    set<int,myComp> s;
    s.insert(8);
    s.insert(1);
    s.insert(12);
    s.insert(6);
    s.insert(8);
    set<int,myComp>::iterator ite;
    for(ite = s.begin();ite!=s.end();ite++)
        cout << *ite << " ";
    cout << endl;
    // 2、元素是结构体,将比较函数放在了结构体内部
    set<Foo> s;
    Foo foo;
    foo.name = "jacky";
    foo.score = 99;
    s.insert(foo);
    foo.name = "mary";
    foo.score = 88;
    s.insert(foo);
    foo.name = "dyc";
    foo.score = 100;
    s.insert(foo);
    set<Foo>::iterator ite;
    for(ite = s.begin();ite!=s.end();ite++)
        cout << (*ite).name << " " << (*ite).score << endl;;
}

multiset

set一样,就是可以插入重复元素。

所以,它在插入元素,删除元素,查找元素有所不同。

  • insert()元素后会排序,然后遍历输出的时候,对于字符串,数字排在了字母前面,可能是按ascii来排的。
  • erase()函数删除元素的时候,会把和键值匹配的所有元素全部删除,并且返回删除元素的个数。
  • find()寻找元素,返回找到第一个元素的迭代器,没有找到,返回end()
#include<set>
#include<iostream>
#include<string>
using namespace std;

int main()
{
    // multiset集合的创建
    multiset<string> ms;
    ms.insert("abc");
    ms.insert("123");
    ms.insert("111");
    ms.insert("aaa");
    ms.insert("123");
    multiset<string>::iterator ite;
    for(ite = ms.begin();ite!=ms.end();++ite)
        cout << *ite << " ";
    cout <<endl;    

    // multiset元素的删除,erase(),并且返回删除元素的个数
    int delete_num = ms.erase("123");
    cout << "delete_num: " << delete_num << endl;
    for(ite = ms.begin();ite!=ms.end();++ite)
        cout << *ite << " ";
    cout <<endl;    

    // find()的使用
    multiset<string>::iterator finder;
    finder = ms.find("abc");
    if(finder!=ms.end())
        cout << "find it!" << endl;
    else 
        cout << "not find!" << endl;
}

map

map就是键值对组成的红黑树,不允许重复的键插入。比较函数只对元素的键值进行比较。

  • 创建数据结构的基础方法还是一样的,就是取元素的时候,键是first,值是second
  • 删除元素就是erase()根据键值删除,clear()清空数据。
  • 反向遍历reverse_iteratorrbegin(),rend()
  • find进行搜索,找到了就返回迭代器,没有就返回end()
  • 自定义比较函数,和set一样。根据元素是否是结构体来写。如果不是结构体,就写一个结构体,然后内部就重载一下operator(),如果是一个结构体,就重载成员函数operator<等。
  • 自定义比较函数,比较的是,所以传入的参数类型就是的类型。
  • map实现数字分离,主要就是先对一个map预设好数字,或者字符。
  • 字符转数字就是map<char,int> cim;,数字转字符就是map<int,char> icm;
#include<map>
#include<iostream>
#include<string> 
using namespace std;

int main()
{
    // map的建立
    map<string,float> m;    
    m["jack"] = 99;
    m["mary"] = 100;
    m["dyc"] = 78;
    map<string,float>::iterator ite;
    for(ite = m.begin();ite != m.end();++ite)
        cout << ite->first << " " << ite->second << endl;
        //cout << (*ite).first << " " << (*ite).second << endl;

    // map元素的删除
    m.erase("dyc");

    // 数字地图 nm  
    // 实现了 字符'1'到'9' 于数字 1到9的映射
    map<char,int> cim;
    for(int i = 0; i<10; i++)
    {
        cim['0'+i] = i;
    }
    string sa;
    sa = "6543";
    int sum = 0;
    for(int i = 0;i < s.length();++i)
        sum += cim[sa[i]];

    // 将数字映射字符的写法。
    map<int,char> icm;
    for(int i = 0; i<10; ++i)
        icm[i] = '0' +i;
    int n = 7;
    string s = "The number is ";
    cout << s + icm[n] << endl;
}

multimap

就是可以插入重复的键

  • insert()插入元素,不能直接m[key] = value,使用pair<>()创建插入的临时对象
  • erase()会把所有键值一样的元素全部删除,并且返回删除的数量。
  • find()找到第一个匹配的键值,如果没有找到就返回end()
#include<map>
#include<iostream>
using namespace std;

int main()
{
    // 元素的插入与遍历
    // insert()与pair<>()
    multimap<char,int> mm;
    mm.insert(pair<char,int>('a',12));
    mm.insert(pair<char,int>('b',13));
    mm.insert(pair<char,int>('a',50));
    multimap<char,int>::iterator ite;
    for(ite = mm.begin();ite!=mm.end();++ite)
        cout << ite->first << " " << ite->second << endl;
}

deuqe

双端队列容器dequevector一样都是顺序表存储结构

  • 考虑到容器元素的内存分配策略和操作的性能的时候,dequevector更有优势。
  • 创建元素和vector一样。
  • 插入元素,从尾部插入push_back(),会不断扩张队列
  • 插入元素,从首部插入push_front,不会扩张队列,会挤掉已有的元素。
  • 插入元素,从中间插入insert(),不会扩张队列,使用迭代器,会挤掉已有的元素
  • 遍历元素.size()查看元素的个数。
  • 遍历元素,迭代器deque<type>::iterator
  • 反向遍历元素,使用反向遍历的迭代器deque<type>::iterator
  • 删除元素,可以从前pop_front(),中erase(),后pop_back()删除,或者清空容器clear()
#include<deque>
#include<iostream>

using namespace std;

int main()
{
    // 创建容器,从尾部插入元素
    deque<int> di;
    di.push_back(1);
    di.push_back(2);
    di.push_back(3);
    cout << di[0] << " " << di[1] << " " << di[2] << endl;
    // 输出 1,2,3

    // 从首部插入元素
    di.push_front(10);
    di.push_front(20);
    di.push_front(30);
    di.push_front(40);
    cout << di[0] << " " << di[1] << " " << di[2] << endl;
    // 输出 40 30 20

    // 从中间插入元素,用迭代器 , 输出 40 88 20
    di.insert(di.begin()+1,88);
    cout << di[0] << " " << di[1] << " " << di[2] << endl;

    // pop_front() erase() pop_back() clear()
    di.pop_front();
    di.erase(di.begin());
    di.pop_back();
    di.clear();    
}

list

双向循环链表

元素的插入,删除,查找是非常快速的。list每个结点都有三部分,前驱指针,数据,后继指针

list的迭代器只能++,--,而不能+2。因为他们是存储在不连续的内存中。

  • 容器的创建以及元素的插入push_back(),push_front()和遍历
  • 元素删除,remove()根据元素的值删除。值相同的元素全部删除
  • 元素删除,pop_front(),pop_back()
  • 元素删除,erase()使用迭代器删除,但是注意迭代器不能使用+n的格式
  • 元素删除,clear()全部删除
  • 元素查询,这里使用的是#include<algorithm>中的find()。找到了就是返回迭代器,没有就是返回`end()
  • 元素排序,是list自带的sort(),从小到大。
  • 剔除重复元素,unique(),将值相同的元素只留一个
#include<list>
#include<iostream>

using namespace std;

int main()
{
    // 容器的创建,元素的插入
    list<int> l;
    l.push_back(5);
    l.push_back(6);
    l.push_front(4);
    list<int>::iterator ite;
    for(ite = l.begin();ite!=l.end();++ite)
        cout << *ite << endl;

    // 反向遍历
    list<int>::reverse_iterator rite;
    for(rite = l.rbegin();rite!=l.rend();++rite)
        cout << *rite << endl;

    // remove()删除元素
    l.remove(8);

    // 自带的sort()
    l.sort()

    // unique()
    l.unique();
}

bitset

bitset()容器的元素的大小为一个bit。值为0/1。

  • 容器的大小在创建的时候就要给出,而且不能扩张。
  • set(),所有元素全部为1,reset(pos)pos位变成0
  • 输出方式
  • 直接cout
  • 或者for(int i = b.size()-1;i>=0;i--)

5af3480ae42ddbea6197c55d2e21622c.png
#include<bitset>
#include<iostream>

using namespace std;

int main()
{
    bitset<10> b;
    b[1] = 1;
    b[6] = 1;
    b[9] = 1; // 9是最高位 
    for(int i = b.size()-1;i>=0;--i)
        cout << b[i];
    cout << endl;

    // set(pos, value) value默认是1
    b.set();
    for(int i=b.size()-1;i>=0;i--)
        cout << b[i];
    cout << endl;

    // reset(pos) 设置为0
    b.reset(0);

    // for循环输出
    for(int i=b.size()-1;i>=0;i--)
        cout << b[i];
    cout << endl;

    // 直接cout
    cout << b <<endl;
}

stack

堆,后进先出的一个线性表,插入和删除元素都只能在栈顶操作,插入元素Push,删除元素Pop

  • 入栈,出栈 push(),`pop()
  • 栈顶元素访问 top()
  • 判空empty()
  • 栈内元素size()
#include<stack>
#include<iostream>

using namespace std;

int main()
{
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    s.push(4);
    cout << s.top() << endl;
    cout << s.empty() << endl;
    while(!s.empty())
    {
        cout << s.top() <<endl;
        s.pop();
    }

}

queue

队列容器是一个先进先出的线性表,插入只能在队尾,删除只能在队首

  • 入队push,出队pop()
  • 查看队首front(),查看队尾back()
  • 判空empty(),队列元素数量size()
#include<queue>
#include<iostream>

using namespace std;

int main()
{
    queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);
    q.push(4);
    while(!q.empty())
    {
        cout << q.front() << endl;
        q.pop();
    }
    cout << q.size();
}

priority_queue

优先队列,保持了队列的基本属性,元素从队尾进入,从队首出队。但是它有一个特性,就是队列中最大的数总是位于队首,就相当于给元素排了个序。可以自己重载operator <来定义比较规则。

  • 入队push(),出队pop()
  • 读取队首元素top()
  • 判空empty(),读取元素数量`size()
  • 自己写的结构体重载operator<可以定义优先级
  • 直接重载operator()
#include<queue>
#include<iostream>

using namespace std;

// priority_queue默认就是从大到小排序
// 所以,函数内部用<就是从大到小
struct Info
{
    string name;
    float score;
    bool operator < (const Info& f) const
    {
        if(score != f.score) return score > f.score;
        else return score > f.score;
    }
};

//  > 就是从小到大
//  < 就是从大到小
struct myComp
{
    bool operator() (const int& a, const int& b)
    {
        if( a != b) return a > b;
        else return a > b;
    }
};

int main()
{
    priority_queue<int> pq;
    pq.push(1);
    pq.push(2);
    pq.push(3);
    pq.push(9);
    cout << pq.size() << endl;
    while(!pq.empty())
    {
        cout << pq.top() << endl;
        pq.pop();
    }

    // 结构体存入priority_queue
    // 重载< 
    priority_queue<Info> pq;
    Info i1,i2,i3;
    i1.name = "dyc";
    i1.score = 100;
    i2.name = "zyx";
    i2.score = 120;
    i3.name = "lzy";
    i3.score = 150;
    pq.push(i1);
    pq.push(i2);
    pq.push(i3);
    cout << pq.size() << endl;
    while(!pq.empty())
    {
        cout << (pq.top()).name << " " << (pq.top()).score << endl;
        pq.pop();
    }

    // 定义:priority_queue<Type, Container, Functional>
    // Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque     // 等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。
    // 当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型。
    // 这里要使用自己的比较函数,所以3个全写
    priority_queue<int,vector<int>,myComp> pq;
    pq.push(1);
    pq.push(9);
    pq.push(2);
    pq.push(30);
    while(!pq.empty())
    {
        cout << pq.top() << endl;
        pq.pop();
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值