C++学习笔记(七)

一、string字符串容器

#include <iostream>

using namespace std;

int main()
{

    string name;
    name = "hello";
    string str(10,'w');

    cout << str << endl;
    name = "hello world";

    string sub1(name,0,5);
    cout << sub1 << endl;4

    string sub2("www.hqyj.com");
    cout << sub2 << endl;

    string sub3(sub2.begin() + 4,sub2.begin() + 8);
    cout << sub3 << endl;

    //string* str3 = new string();
    string str3 = "hello world";

    //string容器对象中使用迭代器遍历有效元素的方式:
-----------------------------------------------------------------------------------------------
    //逆序
    for(string::reverse_iterator it = str3.rbegin(); it != str3.rend(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
---------------------------------------------------------------------------------------
	//正序
---------------------------------------------------------------------------------------

     //    for(string::iterator it = str1.begin();it != str1.end();++it)
     //    {
     //        cout << *it <<" ";
     //    }

     //    cout << endl;

------------------------------------------------------------------

    //枚举for循环遍历:必须有迭代器的支持:

    for(char s : str3)
    {
        cout << s << " ";
    }
    cout << endl;


    //获取string对象的有效字符的个数:
    cout << str3.size() << endl;
    cout << str3.max_size() << endl;


    string str5;
    for(int i = 0; i < 20; i++)
    {
        cout << "str5的有效的字符个数:" << str5.size() << "str5的有效的空间大小" << str5.capacity() << endl;


        //string的栈上容器对象默认起始空间为15bytes,之后按按照2倍扩容的方式进行扩容。
        str5.push_back('a');
    }


    //后符字符串到结尾,改变原字符串对象:

    string str6  = "hello";

    cout << str6.append("world") << endl;

    cout << str6.replace(0,5,"Big") << endl;

    string str7 = "1314";

    cout << stoi(str7) + 100 << endl;

    return 0;
}

二、vector容器

ector容器:(单向开口的连续内存空间)
--------------------

vector与array无乎是一样的,连续的存储结构,

两者的唯一的区别在于在空间上的灵活,


数组需要提前指定长度,不量确定了就不能发生改变了,


比较死板,不够灵活。
----------------------------------------

vector容器是动态空间,随着元素的加入,


它的内部机制会自动扩充空间以容纳新的元素。

vector中的默认的空间配置策略是2倍进行扩容的。
---------------------------------------------------------------
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> v;
    for(int i = 0; i < 20; i++)
    {
        cout << "vector中的有效元素个数:" << v.size() << " ,vector的有效空间大小" << v.capacity() << endl;
        v.push_back(rand() % 100 + 1);
    }
    //遍历vector中的元素:
    for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
    //有迭代器支持的枚举for循环:
    for(int k : v)
    {
        cout << k << " ";
    }
    cout << endl;
    //原始的C的方式:
    for(int i = 0; i < v.size();i++)
    {
        cout << v[i] <<  " ";
    }
    cout << endl;
    return 0;
}


迭代器非法化(迭代器失效问题)
--------------------------------------------

通过迭代器解引用之后找到的值并非原来的值,

因为插入或擦除之后该地址上的元素发生了移动,

通过迭代器解引用后是不能得到与之前的值相同的内容。

---------------------------------


解决方法:
-------------
使用insert或erase时,使用返回值更新一下迭代器



-------------------------------------------
#include <iostream>
#include <vector>
using namespace std;


int main()
{
    vector<int> v;

    for (int i = 0; i < 20; i++)
    {
        cout << "vector中的有效元素个数:" << v.size() << " ,vector的有效空间大小" << v.capacity() << endl;
        v.push_back(rand() % 100 + 1);
    }

    //遍历vector中的元素:
    for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    //有迭代器支持的枚举for循环:
    for (int k : v)
    {
        cout << k << " ";
    }
    cout << endl;

    //原始的C的方式:
    for (int i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;

    //需求:在20随机数中偶数前插入一个88的值:
    for (auto it = v.begin(); it != v.end(); ++it)
    {
        if (*it % 2 == 0)
        {
            //请务必:使用返回值更新一下迭代器:
            it = v.insert(it, 88);
            it++;
        }
    }

    for (int k : v)
    {
        cout << k << " ";
    }
    cout << endl;
    cout << "---------------------------------------" << endl;

    //需求:把所有的偶数删除:
    for (auto it = v.begin(); it != v.end();)
    {
        if (*it % 2 == 0)
        {
            //请务必:使用返回值更新一下迭代器:
            it = v.erase(it);
        }
        else {
            it++;
        }
    }
    

    for (int k : v)
    {
        cout << k << " ";
    }
    
    return 0;
}

三、deque容器

deque:双向开口的连续线性空间

-----------------------------------------

头尾两端分别做元素的插入和删除

四、容器适配器

容器适配器是没有迭代器,是不能使用泛型算法的
------------------------------------------------------------

栈:
-------------------------------------------
#include <iostream>
#include <deque>


using namespace std;


template <class T, class Container = deque<T>>

class Stack
{
private:
    Container _container;

public:
    void push(const T& val)
    {
        this->_container.push_front(val);
    }
    void pop()
    {
        this->_container.pop_front();
    }
    T& top()
    {
        return this->_container.front();
    }
    bool empty()
    {
        return this->_container.empty();
    }
};

int main()
{
    Stack<int> s;

    s.push(1);
    s.push(2);
    s.push(3);
    while (!s.empty()) {
        cout << s.top() << endl;
        s.pop();
    }
    return 0;
}




---------------------------------------------------

优先级队列:
--------------------

#include <iostream>
#include <vector>
#include <algorithm>


using namespace std;

template <class T,class Container = vector<T>, class Compair = std::less<T>>
class Priority_queue
{
private:
    Container _container;
    Compair _compair;


public:
    void push(const T& val)
    {
        this->_container.push_back(val);
        sort(this->_container.begin(),this->_container.end(),this->_compair);
    }
    void pop()
    {
        this->_container.pop_back();
    }
    T& top()
    {
        return this->_container.back();
    }
    bool empty()
    {
        return this->_container.empty();
    }
};
int main()
{
    Priority_queue<int> pq;
    for(int i = 0; i < 20; i++)
    {
        pq.push(rand() % 100 + 1);
    }
    while (!pq.empty()) {
        cout << pq.top() << " ";
        pq.pop();
    }
    return 0;
}


优先级队列标准库中使用的堆排序:
----------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template <class T,class Container = vector<T>, class Compair = std::less<T>>
class Priority_queue
{
private:
    Container _container;
    Compair _compair;
public:
    Priority_queue()
    {
        make_heap(this->_container.begin(),this->_container.end(),this->_compair);
    }
    void push(const T& val)
    {
        this->_container.push_back(val);
        push_heap(this->_container.begin(),this->_container.end(),this->_compair);
    }

    void pop()
    {
        pop_heap(this->_container.begin(),this->_container.end(),this->_compair);
        this->_container.pop_back();
    }
    T& top()
    {
        return this->_container.front();
    }
    bool empty()
    {
        return this->_container.empty();
    }
};
int main()
{
    Priority_queue<int> pq;
    for(int i = 0; i < 20; i++)
    {
        pq.push(rand() % 100 + 1);
    }
    while (!pq.empty()) {
        cout << pq.top() << " ";
        pq.pop();
    }
    return 0;
}

五、list容器

链表是一种物理存储单元上非连续、非顺序的存储结构,

数据元素的逻辑顺序是通过链表链接次序实现的
-----------------------------------------------------------

-------------------------------------------------------------
List容器:
------------------
双向循环链表
----------------------


---------------------
在list中插入或删除元素时,

不会引用非它元素的迭代器的失效。

在listAPI有专门的排序算法。
----------------------------------



----------------------------------
list相关API接口:
------------------------
#include <iostream>
#include <list>


using namespace std;


int main()
{
    list<int> ll;


    for(int i = 0; i < 20; i++)
    {
        ll.push_front(rand() % 100 + 1);
    }
    ll.sort([](int val1, int val2){return val1 > val2;});
    for(int k : ll)
    {
        cout << k << " ";
    }
    cout << endl;
    return 0;
}

-------------------------------------------

六、set容器

-------------------------------------
非线性容器之set/multiset容器(俗称有序容器)树结构,


平衡二叉树
-------------------------


set容器的数据结构:
---------------------------------
Set特性是:所有元素都会根据元素的键值自动被排序。

(set 与 map都会按照键值来自动排序,只不过set的键与值是一体的相同的)

Set的元素不像map那样,可以同时拥有实值与键值,set的元素即是键值又是实值。



(你也可以理解为只有一个值,键与值相同)Set不允许两个元素有相同的键值。

(即然是自动排序,set与map是不允许有相同的键的存在。这一点与map是共同的。)

,而multiset是可以存相同键值的元素。(这是set与multiset的唯一区别。)。

所以set容器的迭代器是一个常双向迭代器,只支持什么:++--==!=的操作。

--------------------------------------------------------------
我们可以通过set的迭代器改变set元素的值吗?
-----------------------------------------------------------

不行,因为set元素值就是其键值,

关系到set元素排序规则,如果任意改变set元素值,

会严重破坏set组织结构。换句话说,set的迭代器是一个只读迭代器。

set容器拥有与list某些相同的性质,

当对容器中的元素进行插入操作或者删除操作的时候,

操作之前所有迭代器,在操作完成之后依

multiset的底层实现是红黑树,红黑树是平衡二叉树的一种。
-----------------------------------------------------------------------


set相关API的介绍及相关策略
-------------------------------------

#include <iostream>
#include <set>
using namespace std;
class Stu
{
private:
    string name;
    int id;
public:
    Stu(string name, int id)
    {
        this->name = name;
        this->id = id;
    }
    void showInfo()
    {
        cout << "学号:" << this->id << " ,姓名:" << this->name << endl;
    }
    //如果要把一个自定义对象插入到set集合中,那么请重载<运算符,并以const修饰。
    bool operator<(const Stu& other)const
    {
        return this->id < other.id;
    }
};

int main()
{
    //set集合最大的用法:就是去重操作及自动排序。
    set<int> s;
    std::pair<set<int>::iterator,bool> p;
    for(int i = 0; i < 20; i++)
    {
        p = s.insert(rand() % 100 + 1);
        if(!p.second)
        {
           cout << *p.first << "没有插入成功" << endl;
        }
    }
    for(int k : s)
    {
        cout << k << " ";
    }
    cout << endl;
    cout << "---------------------------------------------" << endl;
    Stu stu1("zhangsan",1003);
    Stu stu2("lisi",1001);
    Stu stu3("wangWu",1002);
    set<Stu> s1;
    s1.insert(stu1);
    s1.insert(stu2);
    s1.insert(stu3);

    for(Stu stu : s1)
    {
        stu.showInfo();
    }
    return 0;
}
-------------------------------


----------------------------
如果,使用自定义类型插入到这个set容器中,


要么在自定义类型中定义<号运算符重载函数,


要么自定义一个函数对象类型,


并重写小括号运算符重载函数。
---------------------------------------

七、对组pair

对组的构造的方式:
-------------------------


-----------------------------
#include <iostream>
#include <map>
using namespace std;

int main()
{
    pair<int, string> p1 = {1001,"xialuo"};
    pair<int, string> p2(1002,"qiuya");
    pair<int, string> p3 = make_pair(1003,"yanhua");
    pair<int, string> p4 = map<int,string>::value_type(1004,"dongmei");


    //cout << p1.first << "," << p1.second;


    //把对组数据,插入到map集合中:
    map<int,string> m1;
    m1.insert(p4);
    m1.insert(p2);
    m1.insert(p3);
    m1.insert(p1);


    //map容器中的[]中括号运算符重载函数的副作用:
    m1[1005] = "dachun";
    m1[1006];
    m1[1005] = "zhangjian";
    m1.erase(1006);
    //遍历map:
    for(pair<int,string> p : m1)
    {
        cout << p.first << " ," << p.second << endl;
    }
    //有边界检查:
    cout << m1.at(1001) << endl;
    //cout << m1.at(1008) << endl;
    //无边界检查:
    cout << m1[1001] << endl;


    //find查找:
    auto it = m1.find(1001);
    if(it != m1.end())
    {
        cout << "id:" << it->first << ",姓名:" << it->second << endl;
    }
    else {
        cout << "没有找到你所斯望的元素" << endl;
    }
    return 0;
}

八、Map容器

Map容器的特性是:


所有元素都会根据元素的键的值自动排序。


Map所有的元素都是统一的pair对组,


同时拥有键值Key实值Value,

pair的第一元素被视为键值,

第二个元素被视为实值,

map不允许两个元素有相同的键。


--------------------------------------------------------
我们可以通过map迭代器改变map的键值吗?

-------------------------------------------------------------

答案是不行,

因为map的键值关系到map的元素的排列布局,

Map中的键是不可修改的,但是键对应的值是可以修改的。

所以Map的迭代器是一个双向迭代器,只支持++ ===操作。

Map是可以随时插入或删除键值对的。

Map与multimap的唯一区别是multimap中的键是可以重复的。

Map的底层实现机制是由二叉树中的红黑树进行实现的。


------------------
总结:
------------------


map容器的最小单位是pair对组,

在这个容器中,我们可以通过pair对组的Key通过[ ]中括号运算符或find方法,


找到与之对应的实值,

所以Key与Value之间成映射关系。所以map容器也被称之映射表。

  • 18
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值