/*
vector 变长数组 数组长度可以动态变化 基本思想是倍增思想
    size() 返回元素个数
    empty() 返回是否为空
    clear() 清空
    front() 返回vector的第一个数
    back() 返回vector的最后一个数
    push_back() 向vector最后插入一个数
    pop_back() 把vector最后一个数删掉
    vector也是有迭代器的:
    begin() vector的第0个数
    end() vector的最后一个数后面一个数
    vector支持随机寻址 跟数组一样
    
    
string 字符串, substr()可以返回子串, c_str()可以返回string对应的字符数组的头指针
    size() / length()它的作用和size()是一模一样的 都是返回字符串长度
    empty()
    clear()
    
    
queue 队列 队尾插入队头弹出
    size()
    empty()
    
    但queue是没有clear这个函数的 同样queue priorty_queue stack是没有clear这个函数的
    如何清空一个queue q = queue<int>(); 直接构造一个空的queue就可以了
    
    push() 往队尾插入
    front()返回队头元素
    back() 返回队尾元素
    pop() 把队头弹出
    
    
priorty_queue优先队列/堆, 默认是大根堆
    push() 往堆里插入一个元素
    top() 返回他的堆顶
    pop() 把堆顶弹出
    
    如何定义小根堆?
    priority_queue<int, vector<int>, greater<int>> heap; 将后面两个参数写出 一个是vector 一个是greater
    
stack 栈
    empty()
    size()
    push() 往栈顶添加一个元素
    top() 返回栈顶元素
    pop() 弹出栈顶元素
    时间复杂度都是O(1)的
    
deque 双端队列 队头队尾都可以插入弹出 而且可以支持随机访问
    size()
    empty()
    clear()
    front()
    back()
    push_back()/pop_back()
    push_front()/pop_front()
    begin()/end()
    支持随机寻址
    但效率比一般数组要慢好几倍
    
set, map, multiset, multimap 基于平衡二叉树(红黑树实现), 本质上是动态维护一个有序序列
红黑树是平衡二叉树的一种
    size() O(1)
    empty() O(1)
    clear()
    begin()/end() 迭代器 可以支持 ++ --操作 分别返回前驱和后继 时间复杂度 O(logN)
    有序序列里的前驱指的是前面一个数
    有序序列里的后继指的是后面一个数
    
    set所有操作时间复杂度是log(N)
    
    set/multiset
        insert() 插入一个数
        find() 查找一个数 如果不存在的话返回的是 end迭代器
        count() 返回某一个数的个数
        erase()
            (1)输入是一个数,删除所有x O(k + logN) k是x的个数
            (2)输入是一个迭代器,删除这个迭代器
            
        *核心操作 注意混淆 意思并不是相反
        1)lower_bound() 返回大于等于x的最小的数的迭代器
        2)upper_bound() 返回大于x的最小的数的迭代器
        如果不存在的话 返回 end迭代器



    map/multimap 东西有点多 最好去往上搜一下C++STL的详细介绍 用的时候现用现查 不用背
    map是C++里很常用的操作
        insert() 插入的数是一个pair
        erase() 输入的参数是pair或者迭代器
        find()
        [] 时间复杂度是O(logN)





下面四个C++里已经帮我们实现的哈希表
unordered_set, unordered_map,
unordered_multiset, unordered_multimap
上面四个都是基于哈希表来实现的
    操作跟上面类似 但绝大部分操作是O(1)的 即增删改查
    不支持 lower_bound()/upper_bound() 因为他内部是没有序的
    不支持 迭代器的++ --

压位实现
bitset 状态压缩 位存储
    bit<10000> s;
    ~, &, |, ^
    >>, <<
    ==, !=
    []
    
    count() 返回有多少个1
    
    any() 判断是否至少有一个1
    none() 判断是否全为0
    
    set() 把所有位置或1
    set(k, v)将第k位变成v
    reset() 把所有位变成0
    flip() 把所有位取反 等价于~
    flip(k) 把第k位取反
list用的不多不讲
*/


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>

using namespace std;

int main(){
    // vector<int> a(10, 3);//初始化vector 这个效果是 定义一个长度为10的vector它里面每个数都是3
    // //系统内某一程序分配空间时,所需时间与空间大小无关,与申请次数有关
    // // 所以变长数组要尽量减少申请空间的次数
    // //vector在优化的时候是尽量减少申请空间的次数 但是可以浪费空间 所以用的是倍增的思想
    
    
    
    
    // //这两个函数所有容器都有 时间复杂度是O(1)的
    // a.size();//返回的是a里面元素的个数
    // a.empty();//返回的是a是不是空的
    
    
    // clear();//清空这个函数不是所有容器都有 比方说队列queue就没有清空这个函数
    
    // for(auto x : a) cout << x << endl;
    
    
    // vector<int> a;
    
    // for(int i = 0; i < 10; i++) a.push_back(i);
    
    // for(int i = 0; i < a.size(); i++) cout << a[i] << ' ';
    // cout << endl;
    
    // for(vector<int>::iterator i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    // cout << endl;//用迭代器进行遍历
    
    // // for(auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';//当变量类特别长的时候 我们写auto就特别省事儿
    
    // for(auto x : a) cout << x << ' ';
    // cout << endl;
    
    /*
    pair<int, int>p;//pair可以存储一个二元组
    pair<int, pair<int, int>>p;//这样pair可以存储三个东西
    pair可以看成是帮我们实现了一个结构体 而且自带一个比较函数 比一般的结构体要省一些代码

    p.first();//取得pair的第一个元素
    p.second();//取得pair的第二个元素
    // 支持比较运算,按照字典序比较运算,以first为第一关键字,以second为第二关键字(字典序)

    p = make_pair(10, "yxc");
    p = {20, "abc"};

    vector<int> a(4, 3), b(3, 4);
    
    if(a < b) puts("a < b");//按照字典序来比较 4个3是小于3个4的 所以3333 < 444是成立的
    */
    // string a = "yxc";
    
    // a += "def";
    // a += 'c';
    
    // cout << a << endl;
    
    // cout << a.substr(1, 2) << endl;//从下标1开始返回2个字母
    //当第二个数很大的时候 即超过最大长度的时候 我们就会输出到最后一个字母为止
    //也可以把第二个数删掉 即直接返回从1开始到最后的字符串
    
    // 注意:
    // C++里的 substr 第一个值是起始位置 第二个值是子串长度
    // 很多语言里第二个数是截至位置 不用语言注意区分 只有C++是子串长度 其他语言都是截至位置
    
    
    
    
    
    
    
    
    set<int> S;
    multiset<int> MS;
    //set中是不能有重复元素的
    
    
    
    
    map<string, int> a;
    a["yxc"] = 1;
    // yxc就映射到了1
    
    
    cout << a["yxc"] << endl;
    //这是查找 可以直接查找yxc
    
    
    
    
    
    
    return 0; 
}