STL 标准模板库使用参考

STL 标准模板库使用参考

C++ 的 STL 从广义上可以分为 algorithm(算法)、container(容器) 和 iterator(迭代器) 三类,包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法

STL 被组织在以下 13 个头文件中:
< algorithm >
< deque >
< functional >
< iterator >
< vector >
< list >
< map >
< memory >
< numeric >
< quee >
< set >
< stack >
< utility >

Vector 向量容器

简介
vector 是一种简单高效的容器,在尾端插入和删除元素,算法时间度为 O(1),其他元素插入和删除为 O(n). vector 可以动态调整所占用的内存空间。

头文件: < vector >

用数组方式访问 vector 元素参考代码

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

int main() {
    /// 声明方式
    vector<int> v;

    v.push_back(20);
    v.push_back(26);
    v.push_back(12);

    /// vector 可以用数组的方式访问
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
    return 0;
}

用迭代器访问 vector 的参考代码

#include <iostream>
#include <vector>

using namespace std;
int main() {
    int j;
    vector<int> v;

    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    /// 0 1 2

    /// 插入 9 在第二个后面
    v.insert(v.begin() + 2, 9);

   /// 0 1 9 2

    /// 插入 5 为首元素
    v.insert(v.begin(), 5);

   /// 5 0 1 9 2

    /// 插入 12 为末元素
    v.insert(v.end(), 12);

   /// 5 0 1 9 2 12

    /// 删除第二个元素
    v.erase(v.begin() + 1);

    /// 5 1 9 2 12

    /// 删除前三个元素
    v.erase(v.begin(), v.begin() + 2);

    /// 9 2 12

    /// 迭代器,相当于游标
    vector<int>::iterator i;
    for (i = v.begin(), j = 0; i != v.end(); i++, j++) {
        cout << "v[" << j << "] = " << *i << endl;
    }

    /// 判断是否为空 (为空返回 1, 不为空返回 0)
    cout << v.empty() << endl;
    /// 0

    /// 元素实际个数
    cout << v.size() << endl;

    /// 可容纳的最大元素个数
    cout << v.max_size() << endl;

    /// 当前可容纳的 vector 元素个数
    cout << v.capacity() << endl;

    /// 首元素引用
    cout << v.front() << endl;

    /// 末元素引用
    cout << v.back() << endl;

    /// 删除末尾的一个元素
    v.pop_back();

    /// 调整数据空间大小
    v.reserve(30);
    cout << v.capacity() << endl;

    /// 反向迭代器
    vector<int> :: reverse_iterator ri;

    /// 首尾反向
    for (ri = v.rbegin(); ri != v.rend(); ri++) {
        cout << * ri << " ";
    }
    /// 2 9



    return 0;
}

结构体容器参考代码

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

struct stu {
    int x;
    int y;
};

int main() {
    int j;
    /// 结构体容器
    vector<stu> v1;
    vector<stu> v2;

    struct stu a = {1, 2};
    struct stu b = {2, 3};
    struct stu c = {4, 5};

    v1.push_back(a);
    v1.push_back(b);
    v1.push_back(c);
    v2.push_back(c);
    v2.push_back(b);
    v2.push_back(a);

    cout << "v1:" << endl;
    for (int i = 0; i < v1.size(); i++) {
        cout << v1[i].x << " " << v1[i].y << endl;
    }
    cout << "v2:" << endl;
    for (int i = 0; i < v2.size(); i++) {
        cout << v2[i].x << " " << v2[i].y << endl;
    }

    /// 两结构体元素交换
    swap(v1, v2);

    cout << "v1:" << endl;
    for (int i = 0; i < v1.size(); i++) {
        cout << v1[i].x << " " << v1[i].y << endl;
    }
    cout << "v2:" << endl;
    for (int i = 0; i < v2.size(); i++) {
        cout << v2[i].x << " " << v2[i].y << endl;
    }


    return 0;
}

deque 双端队列容器

deque 与 vector 很相似,不仅可以在尾部插入和删除元素,还可以在头部插入和删除,时间复杂度为 O(1),考虑到容器元素的内存分配策略和操作性能时,deque 比 vectot 有优势。
由于使用了 Map 管理以及块为单位进行内存分配,所以不易实现 capacity 和 reverse 函数,而且也不需要这种函数。

参考代码:

#include <iostream>
#include <deque>
using namespace std;

int main() {

    deque<string> d;

    /// 尾部插入元素
    d.push_back("1a");
    d.push_back("2");
    d.push_back("3");
    /// 高效的头部插入元素
    d.push_front("front");

    /// 删除首元素
    //d.pop_front();

    /// 删除尾元素
    //d.pop_back();

    /// 删除指定位置元素
    d.erase(d.begin() + 1);

    /// 删除所有元素
    //d.clear();

    /// 指定位置插入
    d.insert(d.end() - 1, "insert");

    /// 数组方式访问
    for (int i = 0; i < d.size(); i++) {
        cout << d[i] << " ";
    }
    cout << endl;

    /// 迭代器访问
    deque<string> :: iterator i;
    for (i = d.begin(); i != d.end(); i++) {
        cout << *i << " ";
    }
    cout << endl;

    /// 两元素交换,可交换两个 queue 的所有元素
    swap(d[1], d[2]);
    /// 反向遍历
    deque<string> :: reverse_iterator pi;
    for (pi = d.rbegin(); pi != d.rend(); pi++) {
        cout << *pi << " ";
    }
    cout << endl;

    cout << "deque 是否有元素 " << d.empty() << endl;
    cout << "deque 元素个数 " << d.size() << endl;
    cout << "deque 的首元素为 " << d.front() << endl;
    cout << "deque 的末元素 " << d.back() << endl;
    cout << "deque 的最大容量为 " << d.max_size() << endl;
    return 0;
}

list 双向链表容器

list 双向链表中任一位置的元素查找、插入和删除都具有高效的常数阶算法时间复杂度 O(1)。

set 集合容器

set 集合容器使用一种红黑树的平均二叉检索树,不会将重复键值插入,检索效率高 logn。检索使用二叉树的中序遍历,因此可将元素由小到大排列出来。

参考代码

#include <iostream>
#include <set>

using namespace std;

int main() {

    set<int> s;
    /// set<int, greater<int>> s; 在创建 set 时可以规定排序方式
    for (int i = 1; i <= 100; i++) {
        /// 此条语句判断是否插入成功
        pair<set<int>::iterator, bool> p = s.insert(i);

        if (p.second) {
            cout << "插入成功" << endl;
        } else {
            cout << "已存在该元素,不重复插入" << endl;
        }
    }

    /// 拷贝 s 生成 s2
    set<int> s2(s);

    /// 如果删除的是首尾元素可以直接使用 begin() end()
    s.erase(s.begin());

    cout << "erase 的返回值是删除成功元素的个数 " << s.erase(10) << endl;
    cout << "\n";
    s.erase(s.erase(10));

    /// 不会重复插入
    s.insert(5);
    set<int>::iterator ii;
    for (ii = s.begin(); ii != s.end(); ii++) {
        cout << *ii << " ";
    }
    cout << "\n反向遍历" << endl;
    set<int>::reverse_iterator ri;
    for (ri = s.rbegin(); ri != s.rend(); ri++) {
        cout << *ri << " ";
    }
    cout << endl;
    cout << "元素个数为 " << s.size() << endl;
    cout << "元素是否为空 " << s.empty() << endl;

    /// 查找元素值,如指标不在尾末,则找到输出
    ii = s.find(10);
    if (ii != s.end()) {
        cout << "查找 = " << *ii;
    }
    return 0;
}

multiset 多重集合容器

multiset 多重集合容器可将重复元素插入

参考代码

#include <iostream>
#include <set>

using namespace std;

int main() {
    multiset<int> ms;

    /// 插入元素
    ms.insert(10);
    ms.insert(13);
    ms.insert(11);
    ms.insert(13);
    ms.insert(12);
    ms.insert(13);

    /// 查找元素
    int v = 121;
    multiset<int>::iterator ii = ms.find(v);
    // auto ii = ms.find(v);
    if (ii != ms.end()) {
        cout << *ii << endl;
    }
    auto i = ms.begin();
    while (i != ms.end()) {
        cout << *i << " ";
        i++;
    }
    cout << endl;
    cout << "等于13的个数:" << ms.count(13);
    return 0;
}

map 映照容器

map 映照容器的元素数据是一个键值和一个映照数据组成的,键值与映照数据之间有一一映照的关系。

参考代码

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

int main() {
    map<const char*, float> m;
    m["apple"] = 3.4;
    m["orange"] = 1.2;
    m["pear"] = 3.5;
    cout << m["apple"] << endl;
    cout << m["orange"] << endl;
    cout << m["pear"] << endl;
    
    return 0;
}
#include <iostream>
#include <map>

using namespace std;

int main() {
    map<int, string> m;
    m[1] = "s1";
    m[1] = "s2";
    m[2] = "s3";

    map<int, string>::iterator i;
    for (i = m.begin(); i != m.end(); i++) {
        cout << i->first << " " << i->second << endl;
    }

    return 0;
}

multimap 多重映照容器

multimap 与 map 基本相同,唯独不同的是,multimap 允许插入重复键值的元素,由于重复键值的存在,所以,multimap 的元素的插入、删除、查找都与 map 不相同。

参考代码

#include <iostream>
#include <map>

using namespace std;

int main() {
    /// 定义 map 对象,当前没有任何元素
    multimap<string, double> mp;

    mp.insert(pair<string, double>("Jack", 300.5));
    mp.insert(pair<string, double>("Kity", 200));
    mp.insert(pair<string, double>("Memi", 500));
    mp.insert(pair<string, double>("Jack", 306));

    /// 使用前向迭代器中序遍历 multimap
    multimap<string, double>::iterator it;

    /// 删除键值等于 “Jack” 的元素
    mp.erase("Jack");
    for (it = mp.begin(); it != mp.end(); it++) {
        cout << (*it).first << " " << (*it).second << endl;
    }

    /// 元素查找
    it = mp.find("Nacy");
    if (it != mp.end()) {
        cout << (*it).first << " " << (*it).second << endl;
    } else {
        cout << "Not find if!" << endl;
    }

    return 0;
}

stack 堆栈容器

堆栈是一个线性表,插入和删除只在表的一端进行。一端称为栈顶(Stack Top);另一端则为栈底(Stack Bottom)。堆栈的元素插入称为入栈,元素的删除称为出栈。由于元素的入栈和出栈总在栈顶进行,因此,堆栈是一个后进先出(Last In First Out)表,即 LIFO 表。
C++ STL 的 stack 堆栈容器不设最大容量,提供入栈、出栈、栈顶元素访问和判断是否为空的基本操作。

参考代码

//
// Created by 10940 on 2020/8/4.
//

#include <iostream>
#include <stack>

using namespace std;

#define STACK_SIZE 100

int main() {
    /// 创建
    stack<string> s;

    /// 插入元素
    s.push("aaa");
    s.push("bbb");
    s.push("ccc");

    /// 可限制大小
    if (s.size() < STACK_SIZE) {
        s.push("68");
    }

    /// empty 判断栈是否为空  为空返回 true 否则返回 false
    while (!s.empty()) {
        /// top 取栈顶元素(但不删除)
        cout << s.top() << endl;
        /// pop 删除栈顶元素
        s.pop();
    }
    return 0;
}

queue 队列容器

queue 队列是一个线性存储器,与后进先出的堆栈不同,元素数据的插入在表的一端进行,在另一端删除,从而构成了一个先进先出(First In First Out)表。插入一端称为队尾,删除一端称为队首。

参考代码

#include <iostream>
#include <queue>

using namespace std;

int main() {
    /// 创建一个队列
    queue<int> q;

    /// 插入数据
    q.push(3);
    q.push(5);
    q.push(2);

    cout << "元素个数为: " << q.size() << endl;
    /// back 队末元素
    cout << q.back() << endl;

    while (!q.empty()) {
        /// 打印队首元素
        cout << q.front() << endl;
        q.pop();
    }
    return 0;
}

priority_queue优先队列容器

优先队列是一种容器适配器,它的第一个元素(位于头部 top )总是队列中最大的元素,这里的“最大”是指队列元素的严格弱序中的“最大”。严格弱序是一系列数或事物按照一定的比较关系"<“排列得到的序列,”<"可以是数学中进行数值比较的大于,也可以是小于,还可以是其他含义。
priority_queue 优先队列容器使用堆排序算法,每次将最大值或最小值出列。时间复杂度为 O(nlogn)。
创建一个优先队列的格式为 priority_queue<T, Container, Comper>, 可以看出,创建一个优先队列默认需要三个参数(实际应用上有些参数可以省去)。
T : 队列中元素的数据类型
Container : 用于存储和访问队列元素的底层容器类型。
Compare : 比较关系,默认是数值上的小于关系,比如 1 < 2, 6 < 7,此时队列中元素由队头到队尾由大到小排列,采用默认 compare 时此参数可以省去。当需要采用其他标准进行比较时需要额外定义这一比较方式。当满足比较关系 “ < " 时,返回 true ,否则返回 false。

参考代码

#include <iostream>
#include <queue>

using namespace std;

int main() {
    
    /// 创建优先队列,默认降序
    priority_queue<int> q;
    /// 完整格式
    /// 末尾两个 > > 之间一定要有空格
    ///           数据类型   容器    比较方式  这里一定要有空格
    // priority_queue< T, Container, Compare> > a;
    /// 升序队列
    // priority_queue< int, vector<int>, greater<int> > a;
    /// 降序队列
    // priority_queue< int, vector<int>, less<int> > a;

    /// 插入数据
    q.push(93);
    q.push(5);
    q.push(2);
    q.push(33);
    q.push(52);
    q.push(12);

    cout << "元素个数为: " << q.size() << endl;
    while (!q.empty()) {
        /// 去队首元素
        cout << q.top() << endl;
        /// 出队列要先判断是否为空
        q.pop();
    }
    return 0;
}
#include <iostream>
#include <queue>

using namespace std;

/*class cmp {
    public:
    bool operator() (const int a, const int b) {
        return a > b;
    }
};*/

/// 自定义比较方式
struct cmp {
    bool operator() (const int a, const int b) {
        return a > b;
    }
};

int main() {
    priority_queue<int, vector<int>, cmp >  q1;
    priority_queue<int, vector<int> > q2;

    int a[] = {1, 3, 4, 2, 5, 0, 6};
    for (int i = 0; i < 7; i++) {
        q1.push(a[i]);
        q2.push(a[i]);
    }
    cout << "q1: ";
    while (!q1.empty()) {
        cout << q1.top() << " ";
        q1.pop();
    }
    cout << "q2: ";
    while (!q2.empty()) {
        cout << q2.top() << " ";
        q2.pop();
    }

    return 0;
}

Unique 去重

"unique"是C++语言中的STL函数,包含于头文件中。功能是将数组中相邻的重复元素去除。然而其本质是将重复的元素移动到数组的末尾,
最后再将迭代器末尾指向最后不重复的下标。

注意:想要实现完全去重功能,需要在执行unique函数之前先对数组进行排序。
参考代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int a[maxn];
int main() {
    int N;
    while(scanf("%d", &N) != EOF) {
        for (int i = 0; i < N; ++i) scanf("%d", &a[i]);
        sort( a, a + N);
        ///去重
        /// m 是去重后剩余的个数
        int m = unique(a, a + N) - a;
        printf("%d", m);
        for (int i = m - 1; i >= 0; --i) printf(" %d", a[i]);
        printf("\n");
    }
    return 0;
}

本文内容摘自《算法竞赛宝典 基础算法艺术》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值