C/C++语法:(五)STL

1.vector

如果想要开一个int二维数组,两个维度均为\(10^5\),则总大小为\(10^{10}\)个int,总容量为40G,显然没有那么大的空间给你使用,这时vector的作用就体现出来了:vector是变长数组,用多少开多少,可以保证大小为\(10^5\)的整数倍.

#include <vector>
int main(){
    vector <int> a;
    vector <int> b[233]; //第一维长233,第二维动态变化的int数组
    
    struct Rec{
        int x, y;
    };
    vetor <Rec> c;
    
    a.size();
    a.empty();//所有容器都支持以上两种方法
    a.clear(); //清空
}

迭代器:可类比为STL容器中的指针,虽然在算法题中基本用不到迭代器:

vector<int>::iterator it = a.begin(); //begin()返回指向第一个元素的迭代器
a.front(); //等价于*a.begin();
vector<int>::iterator it = a.end(); //end()返回的是最后一个元素的后一个位置,*a.end()为越界访问)
a.back(); //返回最后一个元素 等价于a[a.size() - 1]

遍历vector:

//1.
vector<int>a({1,2,3});
for (int i = 0; i < a.size(); i ++) cout << a[i];

//2.
for (vector<int>::iterator i = a.begin(); i != a.end(); i ++)
    cout << *i;
//注意vector<int>::iterator可以用auto代替,auto写迭代器真是太愉快了

//3.
for (int x : a) cout << x;

增加、删除:

a.push_back(4); //在最后加一个元素 复杂度为O(1)
a.pop_back(); //删除最后一个元素 复杂度为O(1)

2.队列queue

小学二年级学的数据结构告诉我们,队列是一种先进先出的结构.

#include <queue>
int main(){
    queue <int> q;
}

优先队列定义:

//默认优先弹出队列里的最大值
priority_queue <int> q;

//弹出最小值
priority_queue<int, vector<int>, greater<int>> b;

//如果是自定义的结构体的循环队列,一定要重载<符号,因为是大根堆,不能重载>
struct Rec{
    int a, b;
    bool operator< (const Rect& t) const{
        return a < t.a;
	}
};

//如果是优先队列,则重载>符号 背过就完事

循环队列常用操作:

q.push(4); //插入队尾
q.pop(); //弹出队头元素
cout << q.front() << endl;
a.back() //返回队尾元素

优先队列常用操作:

q.push(); //优先队列就不一定是插到队尾了 因为它是堆的结构
q.pop(); //删除堆顶元素(最大值)
q.top(); //查询堆顶元素(最大值)

循环队列、优先队列都没有clear()函数. 栈也没有clear()函数,这两个是关系户.你要清空你就重新初始化一遍呗.

3.栈stack

和队列相反,先进后出:

#include <stack>
int main(){
	stack<int> stk;
    stk.push(4);
    stk.pop(); //删除栈顶元素
    stk.top(); //返回栈顶元素
}

4.deque

又称双端队列,因为两端都是可进可出的,故得名,但是速度慢的令人发指,所以比赛中其实也不咋用得到.

#include <deque>
int main(){
    deque <int> a;
	a.begin(), a.end();
	a.front(), a.back();
	a.push_back(1), a.push_front(2);
	a.clear();
}

双端队列有clear()函数.

5.set

该容器的实现基于红黑树,不过你知道了也没啥用,顶多能用来猜测"删除"这类的函数时间复杂度为\(O(logn)\).

#include <set>
int main(){
    //1.定义
    set<int> a; //元素不能重复 否则会被忽略
    multiset<int> m; //元素可以重复
    
    //2.size empty clear与上述几个容器相同
    
    //3.结构体
    struct Rec{
        int a, b;
        bool operator< (const Rec& t) const{
			return x < t.x;
        }
    };
    set<Rec> s;
    
    //4.迭代器
    set<int>::iterator it = a.begin();
    it ++; it --;
    a.end();
    
    //5.插入与查找
    a.insert(x);
    a.find(x); //返回迭代器 如果没找到的话返回a.end() 故有以下应用:
    if (a.find(x) == a.end()) //判断x在set中   
        
    //6.erase 删除迭代器it所指向的元素 也可以直接删元素x 如果x不存在也不会报错 复杂度为O(logn) 
    a.erase(it);
    a.erase(x);
    
    //7.count(x) 由于set的特性 所以这个计数函数反而是用来判断元素存不存在
    //存在返回1 不存在就是0了
    a.count(x);
}

由于set是一个有序序列,所以很自然的,我们想起了幼儿园时支配我们的二分算法:

a.lower_bound(x); //大于等于x的最小的元素的迭代器
a.upper_bound(x); //大于x的最小的元素的迭代器

6.unordered_set

低层实现为哈希表,和set的区别就在于它是无序的,因此是O(1)的,所以就没有什么lower_bound了.

#include <unordered_set>
int main(){
    unordered_set<int> a;
    unordered_multiset<int> a; //不能存储重复元素
}

7.pair

int main(){
    pair<int, string>a;
    //1.定义
    a = {3, "yxc"}; //c++ 11
    a = make_pair(4, "abc"); //c++ 99
    cout << a.first << ' ' << a.second << endl;
    
   //2.比较 双端比较 按维度先后进行
    a==b; a>=b; a<=b; 
}

8.map

非常有用,低层仍然是红黑树

#include <map>
#include <unordered_map>
int main(){
    map <string, int> a;
    
    //1.插入 O(logn)
    a["Wx"] = 1;
    a.insert({"asd", 1});
    
    //2.查找 key为x
    a,find(x);
    
    //
    unordered_map<int, int> c;
}

9.bitset

常用于处理位运算:

#include <bitset>
int main(){
    bitset<1000> a; //长度是1000位的串
    a[0] = 1
    cout << a[0] << endl;
    
    a.set(3); //把第3位设成1
    a.reset(3); //把第3位设成0
}

本文算法思想源于Acwing,特此注明。

posted @ 2020-09-23 21:36  AIchemistar  阅读(210)  评论(0)    收藏  举报