Fork me on GitHub

STL中的基本数据结构与算法

目录

所在位置

入门篇:

STL

STL(Standard Template Library)是C++的标准模板库,很多竞赛常用的数据结构、算法在STL中都有,熟练掌握能极大简化编程。

一、STL容器

STL的容器分为两类

​ ①顺序式/序列容器(底层主要采用向量和链表)
​ 常见的有:vector、list、stack、queue、deque、priority_queue等
​ vector与list优缺点正好相反

​ ②关联式/关联容器(底层主要采用平衡二叉搜索树结构)
​ 常见的有:set、map、multiset、multimap等

简要特性

  • stack
    ①先进后出
    离自己最近的符合某条件的->单调栈
  • queue
    先进先出
  • list

通用操作

//迭代器
x.begin();//返回容器首个元素的迭代器
x.end();//*返回容器尾元素的后一个位置的迭代器
//反向迭代器
x.rbegin();//返回容器尾元素的迭代器
x.rend();//返回容器首元素的前一位置的迭代器

x.size();//返回容器元素数量
x.empty;//判断容器是否为空

//非通用
x.clear();//删除所有元素,仅vector、map、set...
d[];//像数组一样,支持随机访问,仅vector、map...

接下来先具体介绍几种常见的容器。

1.1 vector——向量

STL中的vector向量是一种动态数组(可变长数组),在运行时能根据需要自动改变数组大小。

特点:可随机访问,但插入删除较慢

需要掌握

  • 定义vectorv

    #include <bits/stdc++.h>//加入相关头文件:万能头,包含<vector>
    vector <int> v;
    
  • 插入 push_back();

    v.push_back(i);//加入至尾部
    v.insert(v.begin() + i, value);//加入至v[i]
    
  • 访问

    //支持随机访问
    for(int i = 0; i < v.size(); i++)
       cout << v[i] << " ";
    //迭代器访问
    for(auto it = vi.begin(); it!=vi.end(); it++)
        cout<<*it<<' '<<endl;
    
    //查找
    v.find(value);//返回其迭代器
    
  • 删除

    v.pop_back();//弹出尾部
    v.erase(iterator it)//删除某个迭代器
    v.erase(iterator first, iterator end);//删除区间[begin,end)
    v.clear();//删除所有元素
    

1.2 stack——栈

栈是一种先进后出的容器(可以理解为泡腾片的拿入拿出)

栈顶添加,栈顶弹出

需要掌握

  • 定义stack s

    #include <bits/stdc++.h>//万能头,作用等同于#include <stack>
    stack <int> s;
    
  • 添加 push

    s.push(key);//入栈至栈顶
    
  • 访问 top

    s.top();//只能访问栈顶
    
  • 删除 pop

    s.pop()//只能弹出栈顶
    

1.3 queue——队列

queue是一种先入先出的容器。

队尾添加,队首弹出

需要掌握

  • 定义queue q

    #include <bits/stdc++.h>//万能头,等同于#include <queue>
    queue <int> q;
    
  • 添加 push

    q.push(key);//入队至队尾
    
  • 访问 front、back

    q.front();//访问队首
    q.back();//访问队尾
    
  • 删除 pop

    q.pop()//只能弹出队首
    

1.4 list——双向列表

STL的list是数据结构中的双向链表,内存空间不连续,通过指针来访问

特点:可高效率在任意地方删除与插入,但不支持随机访问(访问较慢)

需要掌握

  • 定义

    list<int> list1;
    
  • 插入

    list1.push_front(value);//头插
    list1.push_back(value);//尾插
    list1.insert(pos,num);//在pos迭代器位置插入元素num。
    list1.insert(pos,n,num)//在pos迭代器位置插入n个元素num。
    list1.insert(pos,beg,end)//在pos迭代器位置插入区间为[beg,end)的元素。
    
  • 访问

    list1.front();//返回第一个元素
    list1.back();//返回最后一个元素
    for (auto it = list1.begin(); it != list1.end(); it++)//迭代访问
        cout << *it << " ";
    
  • 删除

    list1.pop_back();//尾删
    list1.pop_front();//头删
    list1.erase(pos);//删除pos迭代器位置的元素
    list1.clear();//删除所有
    

2.1 set

set是一个自动实现无重且按一定规则排序的集合

需要掌握

  • 定义 set s;

    #include <bits/stdc++.h>//万能头,包含<queue>
    set <int> s;
    
  • 插入 insert

    s.insert(value);//插入元素进集合(自动去重)
    
  • 查找 find

    //查找值为value的迭代器find(value)
    auto it=s.find(value);
    //查找set中是否含有value
    if(s.find(value) != s.end())
    //可使用upper_bound()、lower_bound()等
    
  • 遍历输出 *it

    //迭代器访问
    for(auto it=s.begin();it!=s.end();it++){
        cout<<*it<<endl;
    }
    
  • 删除某个值 erase

    //删除某值
    s.erase(value);
    //删除某迭代器
    s.erase(iterator it);
    //删除某迭代器区间
    s.erase (iterator first, iterator end);
    

2.2 map

map是一个无重有序的不同类型之间映射的集合

是一组键值对的组合,按键排序,键和值可以是任意的类型。

需要掌握

  • 定义 map<typename1,typename2> mp;

    map<string, int> mp;
    
  • 设置键值对

    mp.insert(make_pair("haha",1));//先输入给一个pair
    mp("haha") = 1;//或者直接赋值
    
  • 迭代访问输出键值

    for(auto it=mp.begin();it!=mp.end();it++)
        cout<<it->first<<" "<<it->second<<endl;
    
  • 查找

    //查找键为key的迭代器
    auto it = mp.find('a');
    //可使用upper_bound()、lower_bound()等
    
  • 删除

    //删除某个迭代器
    mp.erase(iterator it);
    //删除所有
    mp.clear()
    

二、常用算法

1. lower_bound()、upper_bound()

lower_bound()、upper_bound()可以分别求出以数组中或容器中当前元素为下界/上界的下一个元素

但是前提是数组或容器本身已经是有序的!!【已排序的数组 或map以及set】

lower_bound(first, end, val)//找到有序容器或数组中第一个大于等于val的位置
upper_bound(first, end, val)//找到有序容器或数组中第一个小于等于val的位置
//first、end可以是容器的迭代器,或者数组的地址

2. next_permulation()

next_permulation()——生成比当前数组/字符串排列大的下一个排列

next_permulation(a,a+n);//根据数组a的排列找出下一个比它排列大的数组,并更新a

next_permulation(s.begin(),s.end());//根据字符串s的排列找出下一个比它排列大的字符串,并更新s

3.sort()

sort()——可以实现对数、字符串、二元组pair、结构体甚至STL容器的排序

默认升序排序,可自定义排序规则cmp

此处先简要介绍对基本类型以及字符串的排序

/* 整型数组的排序 */
bool cmp(int a, int b)//自定义整型的降序cmp
    return a > b;
int a[N];
for(int i = 0; i < n; i++) 
    cin << a[i];
sort(a, a + n);//对数组a[0]-a[n-1]的元素升序排序![)
sort(a, a + n, cmp);//默认升序,我们可以写个降序的cmp


/* 字符串对字符的排序 */
string a;
//scanf("%s", &a[0]);//用scanf()输入只需要a[0]首地址
cin >> a;
sort(a.begin(), a.end());
printf("%s",a.c_str());//不能用cout输出字符串

以上都是sort(a, b)的形式,默认以升序排序

自定义排序规则,需要在使用sort时添加自定义的比较函数cmp()

/* 对整型 */
sort(a, a+n, cmp);
//默认升序
bool cmp(int a,int b)
  return a<b;
//降序
bool cmp(int a,int b)
  return a>b;


/* 对字符串 */
sort(a.begin(), a.end(), cmp)
//默认升序
bool cmp(char a,char b)
    return a<b;
//降序
bool cmp(char a,char b)
    return a>b;

4.bitset()位操作

bitset可以理解为一个存放二进制的数组,我们可以将整型、字符串存入bitset中。

    //初始化与各类型的输出
    bitset<5> b;//初始化5位的二进制位数组,默认均为0
    cout << b << endl;;

    int u1 = 1;
    bitset<5> b1(u1);//将整型初始化为5位二进制,不足左边补0
    cout << b1 << endl;//u1 = 1,则被初始化为00001

    string s2 = "1101";
    bitset<5> b2(s2);//将字符串初始化为5位二进制,不足左边补0
    cout << b2 << endl;;//s2=”1101“,则被初始化为”01101“

    string s3 = "110100";
    bitset<5> b3(s3);//当字符串足够时,则取左边5个
    cout << b3 << endl ;//s3为”1101“,则被初始化为”11010“

    //bitset<5> b(s, pos, n); //取字符串的s[pos]开始,n位长度
    bitset<5> b4(s3, 1, 2); //“10”—>00010
    cout << b4 << endl;

    cout << (b4 >> 1) << endl;//右移一位


    //注意是逆序存储进下标的,下标低的表示低位
    for(int i = 0; i< 5; i++)
        cout<< b4[i];
    cout << endl;

    //其它操作
    cout << endl << b.any();//b中是否存在1的二进制位?
    cout << endl << b.none();//b中不存在1吗?
    cout << endl << b.count();//b中1的二进制位的个数
    cout << endl << b.size();//b中二进制位的个数
    cout << endl << b.test(2);//测试b下标为2处是否二进制位为1
    cout << endl << b4.test(1);//测试b4下标为2处是否二进制位为1

    b.set(4);//下标4变为1
    b.reset();//所有位归零
    b.reset(3);//下标3处归零
    b.flip();//b的所有二进制位逐位取反
posted @ 2020-10-15 08:58  解尼  阅读(820)  评论(0编辑  收藏  举报