Libra的C++学习笔记

C++学习笔记

1.参数

给函数设置参数时可以的话最好把参数设置为要修改的值的引用,而不是设置为返回值,这样可以避免不必要的复制。(当然前提是你希望该值被修改,如果不应该被修改就不要用引用参数)

//例如
void fill_random_int(vector<int>& v,int cnt){
    v.clear();
    for(int i = 0; i < cnt;i++)
        v.push_back(rand());
}
//和
vector<int> fill_random_int(int cnt){
    vector<int> v;;
    for(int i = 0; i < cnt;i++){
        v.push_back(rand());
    }
    return v;
}
//下面的函数在返回vector变量时,实际上是把函数体里面的v的所有值都复制给调用者,浪费时间。

2.find函数用法

用途:查找数组或vector中首次出现的元素的下标

#include <algorithm>//find函数所在头文件
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;

int main(int argc, const char* argv[]) {
    vector<int> a = {1, 2, 3};
    int b[7] = {1, 2, 3, 4, 3, 4, 5};
    string s = "abcdefghijklmnopqrst";
    set<int> c = {1, 2, 3, 4, 5};

    vector<int>::iterator p1; //注意在对vector使用find函数时的返回类型
    p1 = find(a.begin(), a.end(), 3);

    int* p2; //注意对数组使用find函数时的返回类型
    p2 = find(b + 7, b + 10, 3);

    size_t p3 = s.find('a'); //注意string类型有单独的find函数及其返回类型

    set<int>::iterator p4; //注意set类型有单独的find函数及其返回类型(无法查位置)
    p4 = c.find(3);

    cout << find(a.begin(), a.end(), 3) - a.begin() << endl; //注意上面写的返回值一般不用来输出,下面两个将输出long long类型的下标(均从0开始)
    cout << find(b + 7, b + 10, 3) - b << endl;
    cout << p3 << endl;
    return 0;
}

3. 寻找最大值/max_element

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

int main(int argc, const char* argv[]) {

    vector<int> a = {1, 2, 3, 4}; //可应用于多种数据类型
    int b[5] = {3, 55, 7, 5, 2};
    set<int> c = {1, 2, 4, 8};
    vector<string> d = {"saf", "afsdf", "werqio", "aaaaaaa", "z"}; //注意string类型的比较方法,挨个元素比较,"z"最大

    cout << *max_element(d.begin(), d.end()) << endl; //输出最大值
    cout << *max_element(c.begin(), c.end()) << endl;
    cout << *max_element(b, b + 5) << endl;
    cout << *max_element(a.begin(), a.end()) << endl;

    cout << max_element(d.begin(), d.end()) - d.begin() << endl; //输出最大值下标
    // cout << max_element(c.begin(), c.end()) - c.begin() << endl;对set来说还是不行,因为set无序
    cout << max_element(b, b + 5) - b << endl;
    cout << max_element(a.begin(), a.end()) - a.begin() << endl;

    return 0;
}

输出

2
10
0

4. 求交并集

set_union与set_intersection用法

#include <algorithm>
#include <iostream>
#include <iterator>
#include <set>
#include <vector>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x.begin())
using namespace std;

vector<int> intersection1(vector<int>& nums1, vector<int>& nums2) {
    vector<int> res1, res2;
    set<int> s1(ALL(nums1)), s2(ALL(nums2));
    set_intersection(ALL(s1), ALL(s2), INS(res1)); //求交集
    set_union(ALL(s1), ALL(s2), ALL(res2));        //求并集
    return res1, res2;
}

vector<int> intersection2(vector<int>& nums1, vector<int>& nums2) {
    vector<int> res1, res2;
    sort(ALL(nums1));//set_union()和set_intersection()并不是set的专用方法,而是std里面,故也可以直接对vector使用
    sort(ALL(nums2));//传递的容器必须是排序的,set 容器中元素默认是排序的,而 vector 需要调用 sort 函数进行排序
    set_intersection(ALL(nums1), ALL(nums2), INS(res1)); //求交集
    set_union(ALL(nums1), ALL(nums2), ALL(res2));        //求并集
    return res1, res2;
}

5. compare函数

注意string1.compare(string2)函数的返回值,当二者相等时返回0,不等时返回-1

6. 优先队列自定义类型的优先级问题

对于自定义类型(一般指结构体),要么在结构体内部重载运算符,要么在结构体外面定义仿函数【struct cmp内部重载"()"运算符】,样例如下:

注意:
如果用less的话,需要重载"<",并且在返回值中用">“才能实现从小到大排列,
如果用greater的话,需要重载”>",在返回值中依然是用">"才能实现从小到大排列。

typedef struct STRUCT {
    int dis;
    int index;
    friend bool operator<(const STRUCT& a, const STRUCT& b) {
        return a.dis > b.dis;
    }
} node;
priority_queue<node, vector<node>, less<node>> q;//实现了按dis从小到大排列

实现"个位数越大优先级越小"

typedef struct STRUCT {
    int num;
    int index;
} node;
struct cmp { //仿函数
    bool operator()(const node& a, const node& b) const {
        if(a.num == b.num) {
            return a.index > b.index;
        }
        return a.num < b.num;//"<"为从大到小排列,">"为从小到大排列
    }
};
struct node{
    int x;
    int y;
    friend bool operator < (node a,node b)
    {
        if(a.x==b.x)
            return a.y<b.y;
        return a.x>b.x;
    }
};

7.map排序问题

注意map中默认是按Key从小到大排列的(即在定义map时,第三个参数默认是less),也可通过定义仿函数作为第三个参数传给map定义的方式对Key进行其他方式的排序(如原本Key为string类型,则其默认为字典序从小到大排序,可通过写仿函数然后传参的方式使其按字符串长度排序)。注意map无法使用sort函数(map为非线性容器),若要按Value进行排序,只能把将数据从map中取出,具体操作在这里

8. 位运算判断一个整数是否为2的幂

先放结论:

bool is_power_of_two(int n) {
    return (n != 0) && ((n & -n) == n);
}

证明:对于以补码形式存储的整数来说,- n = ~ n + 1,该运算的一个重要性质为:n 与 - n 的二进制形式中最后一个1及之后的所有0相同,而之前的所有位均为相反数,如:

对于12来说,他的二进制表示为01100,-12的二进制表示为10100,计算过程为:12=10011,可以看到,12中最后的一连串的0在反转后全部变为1,12+1=10100,那么在加完1之后,这些反转后的1又都会变成0,而前一位优惠变成1,而更前面的则相当于只进行了翻转运算,而2的幂的二进制表示的最重要的特点即为整个1-0串中只有一个1,故成立。

而要注意的是,0也满足上述变换,故需单独考虑

9.关于快速排序

快速排序首先确定一个基准值(一般选择首或尾),希望能使得小于该基准值的都在前面,大于该基准值的都在后面,这样再把基准值放到两区域交界处,基准值就归位(处于正确位置)了,过程则是利用双指针从两头向中间扫描,右边遇到小于基准值的停一停,左边遇到大于基准值的停一停,然后二者交换,一直到两指针相遇,由于我们选择让右指针先移动,故最后左指针所在位置的值arr[i]为小于基准值的最右面的一个位置,记其为mid,将其与基准值所在位置进行值交换,第一轮就结束了。之后便可以用递归的方式来对左半边和右半边分别快排。

问题1:若数据有序性很高,或者极端情况下数据完全有序,那么就会导致每轮结束后,下一轮的两边长度分别为1和n-1,最终形成与冒泡排序一样的局面,时间复杂度为O(N^2)

int quick_sort(int* arr, int l, int r) {
    int i = l, j = r, temp = arr[l];
    while(i < j) {
        while(i < j && arr[j] > temp) {
            j--;
        }
        while(i < j && arr[i] <= temp) {
            i++;
        }
        if(i < j) {
            swap(arr[i], arr[j]);
        }
    }
    swap(arr[l], arr[i]);
    return i;
}

void Quick(int* arr, int l, int r) {
    int mid;
    if(l < r) {
        mid = quick_sort(arr, l, r);
        Quick(arr, l, mid - 1);
        Quick(arr, mid + 1, r);
    }
}

解决方法1:每次随机从 l ~ r 之间随机选择一个下标,以其代表的值为基准值,可以有效防止每次都得到最差结果。

void Quick(int* arr, int l, int r) {
    if(l < r) {
        int i = l, j = r, temp = rand() % (r - l + 1) + l;
        swap(arr[l], arr[temp]);
        while(i < j) {
            while(i < j && arr[j] > arr[l]) {
                j--;
            }
            while(i < j && arr[i] <= arr[l]) {
                i++;
            }

            if(i < j) {
                swap(arr[i], arr[j]);
            }
        }
        swap(arr[l], arr[i]);
        Quick(arr, l, i - 1);
        Quick(arr, i + 1, r);
    }
}

解决方法2:每次都选中间为基准,因为设计的数据要么有序(以首尾为基准的基本凉凉),要么无序,而无序且数据很大且能使每次以中间为基准的选法达到最差的情况,这种可能就很小了。

void Quick(int* arr, int l, int r) {
    int i = l, j = r, temp = arr[(l + r) >> 1];
    while(i <= j) {
        while(arr[i] < temp) {
            i++;
        }
        while(arr[j] > temp) {
            j--;
        }
        if(i < j) {
            int t = arr[i];
            arr[i++] = arr[j];
            arr[j--] = t;
        }
    }
    if(l < j) {
        Quick(arr, l, j);
    }
    if(r > i) {
        Quick(arr, i, r);
    }
}0

10.树状数组

本质:是数组而不是树

用途:单点修改与区间求和,区间修改与单点取值(线段树都可以实现,不过显得大材小用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eyBp9IZZ-1595066141487)(./assets/树状数组.png)]

树状数组利用二进制的思想,以上图为例,红色代表树状数组bit[],黑色代表原生数组arr[],则可直观看出

bit[1]=arr[1];

bit[2]=arr[1]+arr[2];

bit[6]=arr[5]+arr[6];

bit[12]=arr[9]+arr[10]+arr[11]+arr[12];

bit[14]=arr[13]+arr[14]

简单找规律(查资料)后发现,C[i] = A[i - 2k+1] + A[i - 2k+2] + … + A[i]; //k为i的二进制中从最低位到高位连续零的长度,即i的二进制表示中最后一位1及后面所有的0组成的数。

那么2k该怎么求呢?

参考本文第八个小知识点,可知2k即为i中最小的2的幂,而该知识点中判断的方法正好可以用来获得i的二进制表示中最后一位1及后面所有的0组成的数,即(i&(-i)).

//需要先构造lowbit函数或宏
//宏
#define lowbit(x) (x&(-x))
//函数
int lowbit(int x){
    return (x&(-x));
}
单点修改与区间求和

构造树状数组:

arr[i] 包含于 bit[i + 2k]、bit[(i + 2k) + 2k]…

​ 所需空间为线性,bit[max_num]即可(构造全局变量)

​ 随数据的输入直接构造即可(相当于原数据均为0,然后每次单点增加arr[i]大小的数据,因此,单点修改有着与之一样的操作):

void update(int index,int delta,int num){
    while(index<=num){
        bit[index]+=delta;
        index+=lowbit(index);
    }
}
...
for(int i=1;i<=num;i++){
    cin>>arr[i];
    update(i,arr[i],num);
}

区间求和:

int query(int index,int num){
    int ans=0;
    while(index>0){
        ans+=bit[index];
        index-=lowbit(index);
    }
    return ans;
}

上述代码求解的是 $ \sum_{i=1}^{index} $(arr[i]),要想求解区间x~y范围内的数据和,只需query(y)-query(x-1).

区间修改与单点取值

与单点修改不同,在区间修改的过程中,若是按上述过程对区间中的数据分别修改,则完全体现不出树状数组的优势,因此这里引入差分的概念。

核心:差分!!!

对于序列a1,a2,a3…an,对它进行差分就变成了a1 ,a2-a1 ,a3-a2…,an-an-1,差分后的序列的前i项和
sum=a1+(a2-a1)+(a3-a2)+…+(ai-1-ai-2)+(ai-ai-1)=ai

即从1到 i - 1 项都被消掉了,最后只剩下了ai,得出结论:差分后序列的前 i 项和等于差分前第 i 个元素的值,利用此性质再结合上面的query()函数,则可以快速进行单点取值。

那么差分在区间修改过程中有什么奇妙的应用呢?

由上述结论可以推出当原数组的连续区间[L,R]被统一修改时,其差分数组只需要修改index=L和index=R+1的两个数据,原因如下:

原因如下

  • 区间[L,R]内每个元素都加上了相同的值,所以相对差距并没有改变,所以[L+1,R]的差分值并没有改变,但是这个区间的两头却会发生改变;

  • 第L个元素加上了x,但第L-1个元素没有加x,所以第L个元素的差分结果就会从原来的(aL-aL-1)变成了现在的(aL-aL-1+x),增加了x;

  • 同理尾部第R个元素加上了x,但是第R+1个元素没有加x,所以第R+1个元素的查分结果就从原来的(aR+1-aR)变成了现在的(aR-aR-1-x),减少了x.

    void update(int index,int delta,int num){
        while(index<=num){
            bit[index]+=delta;
            index+=lowbit(index);
        }
    }
    
    int last=0,cur;
    for(int i = 1; i <= num; i++) {
    	cin>>cur;
        update(i, cur - last, n);
    	last = cur;
    }
    

11. 快速读入(整型)

因为getchar()最快,所以:

int read() {
    int f = 1, ans = 0;//f为正负号标记,ans一定要初始化为0,因为后面要累加
    char c = getchar();
    while(c < '0' || c > '9') {
        if('-' == c) {
            f = -1;
        }
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        ans = ans * 10 + c - '0';
        c = getchar();
    }
    return ans * f;
}

12. 单调队列

顾名思义单调队列就是单调递增或单调递减的队列,可通过STL里面的deque实现,也可以通过数组加左右指针实现,前者较慢,后者较快。通常用来计算固定大小窗口里面的最大值、最小值。

Eg.1

链接:滑动窗口 /【模板】单调队列

题面:有一个长为 nn 的序列 aa,以及一个大小为 kk 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。输入格式

输入一共有两行,第一行有两个正整数 n, k, 第二行 n 个整数,表示序列 arr

输出共两行,第一行为每次窗口滑动的最小值, 第二行为每次窗口滑动的最大值.

1 <= k <= n <= 106, arr[i] ∈ \in [2-31,231).

例如:

The array is arr = [1,3,−1,−3,5,3,6,7], and k = 3img

输入:

8 3
1 3 -1 -3 5 3 6 7

输出:

-1 -3 -3 -3 3 3
3 3 5 5 6 7

解析:典型的求滑动固定窗口最大、最小值的问题,直接套单调队列模板,注意单调队列一般存的都是下标

deque实现
#include <cstdio>
#include <iostream>
#include <queue> //deque所在头文件
using namespace std;

const int max_num = 1e6 + 10;
int arr[max_num];
deque<int> q;

int read(); //快速读入

int main() {
    int n, k;
    n = read();
    k = read();
    for(int i = 0; i < n; i++) {
        arr[i] = read();
    }

    long long ans = 0;
    for(int i = 0; i < n; i++) { //先算最小值,用单增队列
        while(!q.empty() && arr[q.back()] > arr[i]) {
            q.pop_back();
        }
        q.push_back(i);
        if(i >= k) { //完全形成一个窗口,接下来开始滑动
            while(q.front() <= i - k) {
                q.pop_front();
            }
            printf("%d ", arr[q.front()]);
        }
    }

    printf("\n");
    q.clear(); //清空队列

    for(int i = 0; i < n; i++) { //再算最大值
        while(!q.empty() && arr[q.back()] < arr[i]) {
            q.pop_back();
        }
        q.push_back(i);
        if(i >= k) { //完全形成一个窗口,接下来开始滑动
            while(q.front() <= i - k) {
                q.pop_front();
            }
            printf("%d ", arr[q.front()]);
        }
    }

    return 0;
}

int read() {
    int f = 1, ans = 0;
    char c = getchar();
    while(c < '0' || c > '9') {
        if('-' == c) {
            f = -1;
        }
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        ans = ans * 10 + c - '0';
        c = getchar();
    }
    return ans * f;
}
数组实现
#include <cstdio>
#include <iostream>
using namespace std;

const int max_num = 1e6 + 10;
int arr[max_num], deq[max_num], l = 1, r = 0; //注意左右指针的实现

int main() {
    //这里不再写数据的输入了

    for(int i = 0; i < n; i++) {
        while(l <= r && arr[deq[r]] > arr[i]) {//要求最大值只需要把'>'换成'<'(加不加'='都无所谓)
            //要把刚滑进窗口的数据插入到单调队列里来,先把不合要求的数据删掉,这里用指针移动来代替
            r--; 
        }
        deq[++r] = i;
        if(i >= k - 1) {
            while(deq[l] <= i - k) {
                l++;
            }
            printf("%d", arr[deq[l]]);
        }
    }
    return 0;
}
Eg.2

链接:Fake Maxpooling

题目:给定一个n*m的矩阵mat[n][m],对于矩阵中任意的一个位置(i,j),其值为lcm(i,j)***(lcm为i和j的最小公倍数)**,再给定一个k,求该nm的数组中所有k*k的小矩阵中最大值的和。

例如:输入n=3,m=4,k=2

则得到的3*4的矩阵为

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5h1p12rQ-1595066141492)(D:%5CTools%5CType%5CMarkDown%5Cassets%5Cimage-20200718001948042.png)]

然后从[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RpChu8of-1595066141494)(D:%5CTools%5CType%5CMarkDown%5Cassets%5Cimage-20200718002035906.png)]开始,获取所有的2*2的小矩阵中的最大值,然后求和,得到的结果就是2+6+6+6+6+12=38.\

要求: 1 <= n, m <= 5000, 1 <= k <= min⁡{n,m},time<3s

题解:该题可以用滑动窗口或者单调队列来解,不过前者慢且难写,后者快且便于书写,后者还可以分别用deque和数组实现,deque会很慢,数组就很快。不过该题其实容易TLE在创建该数组上,如果使用每一个位置都暴力计算gcd再i*j/gcd(i,j)***【O(n*m*log(n))】***的话,是绝对TLE的,这里使用O(n*m)的方法:

for(inti = 1; i <= n; i++)
    for(intj = 1; j <= m; j++)
        if(!Gcd[i][j])
            for(intk = 1; k * i <= n && k * j <= m; k++)
                Gcd[k * i][k * j] = k, A[k * i][k * j] = i * j * k;//这里用了两个数组,一个存gcd,																另一个才是mat数组。

之后便是二维数组上的单调队列。

deque实现(TLE)
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
typedef struct {
    int x;
    int y;
} node;
const int max_num = 5010;
int mat[max_num][max_num];
deque<node> q;

int read();

int main(int argc, const char* argv[]) {
    int n, m, k;
    n = read();
    m = read();
    k = read();

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(!mat[i][j])
                for(int k = 1; k * i <= n && k * j <= m; k++)
                    mat[k * i][k * j] = k;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            mat[i][j] = i * j / mat[i][j];

    long long ans = 0;
    for(int i = 1; i <= n - k + 1; i++) {
        q.clear();
        for(int j = 1; j <= m; j++) {
            for(int row = i; row <= i + k - 1; row++) {
                while(!q.empty() && mat[q.back().x][q.back().y] < mat[row][j]) {
                    q.pop_back();
                }
                q.push_back({row, j});
            }
            if(j >= k) {
                while(q.front().y <= j - k) {
                    q.pop_front();
                }
                ans += mat[q.front().x][q.front().y];
            }
        }
    }
    printf("%lld", ans);

    return 0;
}

int read() {
    int f = 1, ans = 0;
    char c = getchar();
    while(c > '9' || c < '0') {
        if('-' == c) {
            f = -1;
        }
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        ans = ans * 10 + c - '0';
        c = getchar();
    }
    return f * ans;
}
数组实现
#include <algorithm>
#include <cstdio>
#include <time.h>
using namespace std;
typedef long long LL;
#define N 1000010

int n, m, k, A[N][N], B[N][N];
LL ans;

void Handle(int n, int m) {
    static int q[N];
    for(int i = 1; i <= n; i++) {
        int l = 1, r = 0;
        for(int j = 1; j < k; j++) {
            while(l <= r && A[i][q[r]] <= A[i][j]) {
                r--;
            }
            q[++r] = j;
        }
        for(int j = k; j <= m; j++) {
            while(l <= r && q[l] + k <= j) {
                l++;
            }
            while(l <= r && A[i][q[r]] <= A[i][j]) {
                r--;
            }
            q[++r] = j;
            B[j - k + 1][i] = A[i][q[l]]; //转置操作
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(!A[i][j])
                for(int k = 1; k * i <= n && k * j <= m; k++)
                    A[k * i][k * j] = k;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            A[i][j] = i * j / A[i][j]; //懂了

    Handle(n, m); //先把每一行看成一维数组,以1*k的窗口滑动,记录每个窗口的最大值,并将其转置之后放到B数组里面(即本来应该是竖着的,转成横着的了)
    for(int i = 1; i <= m - k + 1; i++)
        for(int j = 1; j <= n; j++)
            A[i][j] = B[i][j]; //把B数组复制到A数组里面
    Handle(m - k + 1, n);      //再在A数组里面再来一次单调队列,依然是横着,因为转置过了
    for(int i = 1; i <= n - k + 1; i++)
        for(int j = 1; j <= m - k + 1; j++)
            ans += B[i][j]; //最后加起来就行了
    printf("%lld\n", ans);

    return 0;
}

13.bitset<template T>

构造函数

    bitset<4> bitset1;  //无参构造,长度为4,默认每一位为0

    bitset<8> bitset2(12);  //长度为8,二进制保存,前面用0补充

    string s = "100101";
    bitset<10> bitset3(s);  //长度为10,前面用0补充
    
    char s2[] = "10101";
    bitset<13> bitset4(s2);  //长度为13,前面用0补充

    cout << bitset1 << endl;  //0000
    cout << bitset2 << endl;  //00001100
    cout << bitset3 << endl;  //0000100101
    cout << bitset4 << endl;  //0000000010101

注意:

  • 构造时,需在<>中表明bitset 的大小(即size)。

  • 在进行有参构造时,若参数的二进制表示比bitset的size小,则在前面用0补充(如上);若比bitsize大,参数为整数时取后面部分,参数为字符串时取前面部分(如下)

 bitset<2> bitset1(12);  //12的二进制为1100(长度为4),但bitset1的size=2,只取后面部分,即00

    string s = "100101";  
    bitset<4> bitset2(s);  //s的size=6,而bitset的size=4,只取前面部分,即1001

    char s2[] = "11101";
    bitset<4> bitset3(s2);  //与bitset2同理,只取前面部分,即1110

    cout << bitset1 << endl;  //00
    cout << bitset2 << endl;  //1001
    cout << bitset3 << endl;  //1110

操作符

&(按位与),|(按位或),^(按位异或),~(按位取反),>>(右移若干位,左边补0),<<(左移若干位,右边补0),[](按下标取值)

注意:bitset起始位为0,且为最右端

常用函数

 bitset<8> foo ("10011011");

    cout << foo.count() << endl;  //5     (count函数用来求bitset中1的位数,foo中共有5个1
    cout << foo.size() << endl;   //8     (size函数用来求bitset的大小,一共有8位

    cout << foo.test(0) << endl;  //true   (test函数用来查下标处的元素是0还是1,并返回false或										    true,此处foo[0]为1,返回true
    cout << foo.test(2) << endl;  //false  (同理,foo[2]为0,返回false

    cout << foo.any() << endl;  //true    (any函数检查bitset中是否有1
    cout << foo.none() << endl;  //false  (none函数检查bitset中是否没有1
    cout << foo.all() << endl;  //false   (all函数检查bitset中是全部为1

注意:test函数会对下标越界作出检查,而通过 [] 访问元素却不会经过下标检查,所以,在两种方式通用的情况下,选择test函数更安全一些

 	cout << foo.flip(2) << endl;  //10011111   (flip函数传参数时,将参数所指下标位取反
    cout << foo.flip() << endl;   //01100000   (flip函数不指定参数时,将bitset每一位全部取反

    cout << foo.set() << endl;    //11111111  (set函数不指定参数时,将bitset的每一位都置为1
  	cout << foo.set(3) << endl;    //11111111  (set函数只有一个参数时,将参数下标处置为1
    cout << foo.set(3,0) << endl;  //11110111  (set函数指定两位参数时,将第一参数位的元素置为												第二参数的值,本行对foo的操作相当于foo[3]=0
    cout << foo.reset(4) << endl;  //11101111  (reset函数传一个参数时将参数下标处置为0
    cout << foo.reset() << endl;   //00000000  (reset函数不传参数时将bitset的每一位全部置为0

上面的函数也都会检查下标是否越界,如果越界就会抛出异常

类型转换函数

    bitset<8> foo ("10011011");

    string s = foo.to_string();  //将bitset转换成string类型
    unsigned long a = foo.to_ulong();  //将bitset转换成unsigned long类型
    unsigned long long b = foo.to_ullong();  //将bitset转换成unsigned long long类型

    cout << s << endl;  //10011011
    cout << a << endl;  //155
    cout << b << endl;  //155

例题

题目链接:Greater and Greater

题解链接:Libra的blog

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值