C++基础课:STL、位运算、常用库函数

本文介绍了C++标准模板库(STL)中的一些重要容器,如vector、queue、stack、deque、set和map的基本使用,包括声明、函数、遍历以及常见操作,强调了它们在编程中的作用和效率特点。
摘要由CSDN通过智能技术生成

//此博客根据acwing语法基础课而做,如有侵权 ,联系作者,及时删除

STL

STL是提高c++编写效率的一个利器!

一、#include<vector>.

        vector是变长数组,支持随机访问,不支持在任意位置O(1)插入吗。为了保证效率,元素的增删一般应该在末尾进行。

1、声明

        #include <vector>   头文件

        vector<int> a;          相当于一个长度动态变化的int数组

        vector<int>b[233]    相当于第一维长233,第二位长度动态变化的int数组

        struct rec{...}

        vector<rec> c;           自定义的结构体也可以保存在vector中

2、函数     

(1)、size/empty

        size函数返回vector的实际长度(包含的元素个数),empty函数返回一个bool类型,表明vector是否为空。二者的时间复杂度都是O(1)。

         所有的STL容器都支持这两个方法,含义也相同。

(2)、clear

        clear函数是把vector清空。

(3)、迭代器

        迭代器就像STL容器的“指针“,可以用” * “操作符解除引用。

        一个保存int的vector的迭代器声明方法为:

        vector<int>::iterator it;

        vector的迭代器是”随机访问迭代器“,可以把vector的迭代器与一个整数相加减,其行为和指针的移动类似。看可以把vector 的两个迭代器相减,其结果也和指针相减类似,得到两个迭代器对应下标之间的距离。

(4)、begin/end

        begin函数返回指向vector中第一个元素的迭代器。

        所有的容器都可视作一个“前闭后开”的结构,end函数返回vector的尾部,即地n个元素往后的”边界“。*a.end()与a[n]都是越界访问,其中n=a.size()。

(5)、front/back

        front函数返回vector的第一个元素,等价于*a.begin() 和a[0]。

        back函数返回vector的最后一个元素,等价于*==a.end() 和 a[a.size()-1]。

(6)、push_back()和 pop_back()

        a.push_back(x)把元素 x 插入到vector a的尾部。

        a.pop_back()删除vector a 的最后一个元素。

        时间复杂度为O(1)。

3、遍历

(1)、常规遍历

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> a({1,2,3});

    for(int i = 0; i < a.size(); i ++ ) cout << a[i] << ' ';
    cout << endl;

    return 0;
}

  (2)、迭代器遍历

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> a({1,2,3});

    for(vector<int>::iterator i = a.begin(); i !=a.end();i ++  ) cout << *i << ' ';
    cout << endl;
    //遍历过程中的迭代器vector<int >::iterator可以替换为auto

    return 0;
}

(3)、范围遍历

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> a({1,2,3});

    for(int x : a) cout << x << ' ';
    cout << endl;

    return 0;
}

4、汇总

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int>a({1,2,3});
    vector<int> b[233];

    a.size();
    //a.empty();
    //a.clear();

    vector<int>::iterator it = a.begin();
    //a.end();

    struct Rec
    {
        int x,y;
    };
    for(int i = 0; i < a.size(); i ++ ) cout << a[i] << ' ';
    cout << endl;

    a.push_back(4);

    for(vector<int>::iterator i = a.begin(); i !=a.end();i ++  ) cout << *i << ' ';
    cout << endl;

    a.pop_back();
    a.pop_back();

    for(int x : a) cout << x << ' ';
    cout << endl;

    cout << a.front() << ' ' <<a[0] << ' ' <<*a.begin() << endl;
    cout << a.back() << ' ' << a[a.size() - 1] << endl;

    cout << *a.begin() << endl;
    cout << *a.end() << endl;
    vector<Rec> c;

    return 0;
}

二、#include <queue >

        头文件 queue 主要包括循环队列 queue 和优先队列 priority queue 两个容器。

1、声明

        queue<int>q;

        struct rec{...}; queue<rec>q;                                //结构体rec中必须定义大于号

        priority_queue<int> q;                                          //大根堆

        priority_queue<int, vector<int>,greater<int>>q;   //小根堆

        priority_queue<pair<int,int>>q;

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

int main()
{
    queue<int>q;       //队列
    priority_queue<int> a;  //大根堆
    priority_queue<int,vector<int>, greater<int>>b; //小根堆

    priority_queue<pair<int,int>> c;
    struct Rec
    {
        int a,b;
       // bool operator< (const Rec& t)const
       // {
       //     return a < t.a;
       // }//大根堆要重载小于号,小根堆要重载大于号,否则会报错
    };
    priority_queue<Rec> d;
    return 0;
}

2、循环队列 queue

q.push(1) //从队尾插入

q.pop()   //从队头弹出

q.front() //返回对头元素

cout << q.back() << endl; //返回队尾元素        

3、优先队列 priority_queue

a.push(1); //插入一个数
a.top();   //取最大值
a.pop();   //删除最大值

注意

除了 队列、优先队列、栈之外其余所有的STL容器都有clear函数。

重新初始化一次队列即可清空队列

4、汇总

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

int main()
{
    queue<int>q;       //队列

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

    priority_queue<int> a;  //大根堆
    
    a.push(1); //插入一个数
    a.top();   //取最大值
    a.pop();   //删除最大值
    
    priority_queue<int,vector<int>, greater<int>>b; //小根堆

    priority_queue<pair<int,int>> c;
    struct Rec
    {
        int a,b;
       // bool operator< (const Rec& t)const
       // {
       //     return a < t.a;
       // }//大根堆要重载小于号,小根堆要重载大于号,否则会报错
    };
    priority_queue<Rec> d;
    return 0;
}

三、#include <stack>

头文件stack包含栈。

1、声明

声明和前面的容器类似。

2、函数

stk.push(1);//从栈顶插入
stk.top();  //栈中最大值
stk.pop();  //弹出栈顶元素
    

3、汇总

#include <iostream>
#include <vector>
#include <queue>
#include <stack>

using namespace std;

int main()
{
    stack<int> stk;
    stk.push(1);
    stk.top();
    stk.pop();
    
    return 0;
}

四、#include <deque>

        双端队列 deque 是一个支持在两端高效插入或删除元素的连续线性存储空间。它就像vector和queue的结合。与vector相比,deque在头部增删元素仅需要O(1)的时间;与queue相比,deque像数组一样支持随机访问。

1、声明

        声明和前面的容器类似。

2、函数

a.begin();     //返回deque的头迭代器   
a.end();       //返回deque的尾迭代器 
a.front();     //队头元素
a.back();      //队尾元素
a.push_back(); //从队尾入队
a.push_front();//从队头入队
a.pop_back();  //从队尾出队
a.pop_front(); //从队头出队
a.clear();     //清空队列   

3、汇总

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <deque>

using namespace std;

int main()
{
   deque<int> a;
   a.begin(),a.end();
   a.front(),a.back();
   
   a.push_back(1),a.push_front(2);
   a[0];
   a.pop_back(),a.pop_front();
   
   a.clear();

    return 0;
}

五、#include <set>

        头文件set主要包括set和multiset两个容器,分别为“有序集合”和“有序多重集合”,即前者的元素不能重复,而后者可以包含若干个相等的元素。set和multiset的内部实现是一颗红黑树,它们支持的函数基本相同。

1、声明

        

set<int> a;         //元素不能重复
multiset<int> b;    //元素可以重复
struct Rec{...};
set<Rec> c;

2、函数

(1)、size/empty/clear

        和vector类似。

(2)、迭代器

        set和multiset的迭代器称为“双向访问迭代器”, 不支持“随机访问”, 支持星号(*)解除引用,仅支持“++”和“--”两个与算术相关的操作。

        设it是个迭代器,例如set<int>::iterator it;

        若把it++,则it会指向“下一个”元素。这里的“下一个”元素是指在元素从小到大排序的结果中,排在 it 下一名的元素。同理,若把 it--,则 it 将会指向排在“上一个”的元素。

(3)、begin/end

        返回集合的首、尾迭代器,时间复杂度均为O(1)。

        s.begin()是指向集合中最小元素的迭代器。

        s.end()是指向集合中最大元素的下一个位置的迭代器。换言之,就像vector 一样,是一个“前闭后开”的形式。因此--s.end()是指向集合中最大元素的迭代器。

(4)、insert

        s.insert(x)把一个元素x插入到集合s中,时间复杂度为O(logn)。

        在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。

(5)、find

        s.find(x)在集合s中查找等于x的元素,并返回指向该元素的迭代器。若不存在,则返回s.end()。时间复杂度为O(logn)。

(6)、lower_bound/upper_bound

        这两个函数的用法与find类似,但查找的条件略有不同,时间复杂度为O(logn)。

        s.lower_bound(x)查找大于等于x的元素中最小的一个,并且返回指向该元素的迭代器。

        s.upper_bound(x)查找大于x的元素中最小的一个,并返回指向该元素的迭代器。

(7)、erase

        设 it 是一个迭代器,s.erase(it)从 s 中删除迭代器 it 指向的元素,时间复杂度为O(logn)

        设x是一个元素,s.erase(x)从s中删除所有等于x的元素,时间复杂度为O(k+logn),k表示被删除的元素个数。

(8)、count

        s.count(x)返回集合s中等于x的元素个数,时间复杂度为O(k+logn),其中k为元素x的个数。

3、汇总

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <d2d1_1helper.h>

using namespace std;

int main()
{
    set<int> a;         //元素不能重复
    multiset<int> b;    //元素可以重复

    set<int>::iterator  it = a.begin();
    it ++; it--;
    ++ it;  --it;
    a.end();

    a.insert(x);
    if(a.find(x) == a.end())// 判断x在a中是否存在

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

    a.erase(it);

    a.count(x);

    struct Rec
    {
        int x,y;
        bool operator < (const Rec& t) const
        {
            return x < t.x;
        }
    };
    set<Rec> c;

    return 0;
}

六、#include <map>

        map容器是一个键值对 key-valua的映射,其内部实现是一颗已key为关键码的红黑树。Map的key和value 可以是任意类型,其中 key 必须定义小于号运算符。

1、声明

map<key type,key,type> name;

2、函数

(1)、size/empty/clear/begin/end

        以上 集中函数均与set类似。

(2)、insert/erase

        与set类似,但是其参数均为pair<key,type,value type>。

(3)、find

        h.find(x)在变量名为h的map中查找key为x的二元组。

(4)、[ ]操作符

        h[key]返回key映射的value的引用,时间复杂度为O(logn)。

        [ ]操作符是map最吸引人的地方。我们可以很方便的通过h[key]来得到 key 对应的value。还恶意对h[key]进项赋值操作,改变key对应的value。

位运算

& 与

| 或

~ 非

异或

>> 右移

<< 左移

常用操作

        (1)求x的第k位数字  x>>k & 1

        (2) lowbit(x)= x & -x,返回 x 的最后一位1.

常用库函数


(1)reverse 翻转

        翻转一个vector:

        reverse(a.begin(),a.end());

        翻转一个数组 ,元素存放在下标1~n:

        reverse(a+1,a+1+n);

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

int main()
{
    /*vector<int> a ({1,2,3,4,5});
    reverse(a.begin(),a.end());*/
    
    int a[] = {1,2,3,4,5};
    reverse(a,a+5);

    for(int x : a) cout << x << ' ';
    cout << endl;

    return 0;
}

(2)unique 去重

        返回去重之后的尾迭代器(或指针),仍然为前闭后开,即这个迭代器是去重之后末尾元素的下一个位置。该函数常用于离散化,利用迭代器(或指针)的减法,可计算出去重后的元素个数。

        把一个vector去重:

        int m = unique(a.begin(),a.end()-a.begin());

        把一个数组去重,元素存放在下标1~n:

        int m = unique(a + 1,a + 1 + n) - (a + 1);

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

int main()
{
    //int a[] = {1,1,2,2,3,3,4};
    vector<int> a ({1,1,2,2,3,3,4});

    int m = unique(a.begin(), a.end()) - a.begin();

    cout << m << endl;

    for(int i = 0; i < m; i ++) cout << a[i] << ' ';
    cout << endl;

    return 0;
}

(3) rardom_shuffle随机打乱

        用法与reverse相同。

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

using namespace std;

int main()
{
    vector<int> a ({1,2,3,4,5});
    //int a[] = {1,2,3,4,5};

    srand(time(0));

    random_shuffle(a.begin(),a.end());

    for(int x : a) cout << x << ' ';
    cout << endl;

    return 0;
}

(4)sort

        对两个迭代器(或指针)指定的部分进行快速排序。恶意在第三个参数传入定义大小比较的函数,或者重载“小于号”运算符。

        把一个int 数组(元素存放在下标1~n)从大到小排序,传入比较函数:

        int a[MAX_SIZE];

        bool cmp(int a,int b){return a>b;}

        sort(a + 1,a + 1 +n,cmp);

        把自定义的结构体vec排序,重载“小于号”运算符:

         struct rec{int id,x,y; }

        vector<rec> a;

        bool operator<(const rec&a,const rec &b){

                return a.x < b.x || a.x == b.x && a.y< b.y;

        }

        sortt(a.begin(),a.end());

(5) lower_bound/upper_bound 二分

        lower_bound 的第三个参数传入一个元素x,在两个迭代器(指针)指定的部分上执行二分查找,返回指向第一个大于等于x的元素的位置的迭代器(指针)。

         upper_bound 的用法和lower_bound 大致相同,唯一的区别是查找第一个大于 x 的元素。当然,两个迭代器(指针)指定的部分应该是提前排好序的。

          在有序 int 数组(元素存放在下标1~n)中查找大于等于x的最小整数的下标:

        int l = lower_bound(a+1,a+1+n,.x )-a;

        在有序vector<int> 中查找小于等于 x 的最大整数(假设一定存在):

        int y = *--upper_bound(a.begin(),a.end(),x);

        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值