- level 1:语法基础课
第 9 讲 位运算、常用库函数
- 2023-12-1 13:51:08 @
C++帮我们实现好了很多有用的函数,我们要避免重复造轮子。
-
位运算
& | ~ ^ << >>
与(AND)、或(OR)、非(NOT)、异或(XOR)、左移(* 2^k)、右移(/ 2^k)
常用操作:
1.1 求
x
的第k
位数字x >> k & 1
#include <bits/stdc++.h> using namespace std; int main() { int a = 13; for (int i = 5; i >= 0; i -- ) cout << (a >> i & 1) << endl; return 0; }
1.2
lowbit(x) = x & -x
,返回x
的最后一位1
#include <bits/stdc++.h> using namespace std; int main() { int a = 121212; int b = -a; int c = ~a + 1; cout << b << endl << c << endl; return 0; }
-
常用库函数
#include <algorithm>
2.1
reverse
翻转 O(n)翻转一个
vector
:reverse(a.begin(), a.end());
翻转一个数组,元素存放在下标
1 ~ n
:reverse(a + 1, a + n + 1);
#include <bits/stdc++.h> 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.2
unique
去重前提有序,返回去重(只去掉相邻的相同元素)之后的尾迭代器(或指针),仍然为前闭后开,即这个迭代器是去重之后末尾元素的下一个位置。该函数常用于离散化,利用迭代器(或指针)的减法,可计算出去重后的元素个数。
把一个
vector
去重:int m = unique(a.begin(), a.end()) – a.begin();
把一个数组去重,元素存放在下标
1 ~ n
:int m = unique(a + 1, a + n + 1) – (a + 1);
#include <bits/stdc++.h> using namespace std; int main() { int a[] = {1, 1, 2, 2, 3, 3, 4}; int m = unique(a, a + 7) - a; cout << m << endl; for (int i = 0; i < m; i ++ ) cout << a[i] << ' '; cout << endl; vector<int> a({1, 1, 2, 2, 3, 3, 4}); a.erase(unique(a.begin(), a.end()), a.end()); for (auto x : a) cout << x << ' '; cout << endl; return 0; }
2.3
random_shuffle
随机打乱用法与
reverse
相同。#include <bits/stdc++.h> #include <ctime> using namespace std; int main() { vector<int> a({1, 2, 3, 4, 5}); srand(time(0)); // 返回当前至1970.1.1的s random_shuffle(a.begin(), a.end()); for (int x : a) cout << x << ' '; cout << endl; return 0; }
2.4
sort
对两个迭代器(或指针)指定的部分进行快速排序。可以在第三个参数传入定义大小比较的函数,或者重载“小于号”运算符。
把一个
int
数组(元素存放在下标1 ~ n
)从大到小排序,传入比较函数:int a[MAX_SIZE]; bool cmp(int a, int b) { return a > b; } sort(a + 1, a + n + 1, cmp);
#include <bits/stdc++.h> #include <ctime> using namespace std; bool cmp(int a, int b) // a 是否应该排在 b 的前面 { return a < b; } int main() { vector<int> a({1, 2, 3, 4, 5}); srand(time(0)); // 返回当前至1970.1.1的s random_shuffle(a.begin(), a.end()); for (int x : a) cout << x << ' '; cout << endl; sort(a.begin(), a.end()); // sort(a.begin(), a.end(), greater<int>()); // 从大到小 // sort(a.begin(), a.end(), cmp); // 自定义排序函数 for (int x : a) cout << x << ' '; cout << endl; return 0; }
把自定义的结构体
vector
排序,重载“小于号”运算符:struct Rec { int id, x, y; bool operator< (const Rec &a, const Rec &b) { return a.x < b.x || a.x == b.x && a.y < b.y; } }; vector<Rec> a; sort(a.begin(), a.end());
#include <bits/stdc++.h> using namespace std; struct Rec { int x, y; }a[5]; bool cmp(Rec a, Rec b) // 写一个比较函数 { return a.x < b.x; } int main() { for (int i = 0; i < 5; i ++ ) { a[i].x = i; a[i].y = -i; } for (int i = 0; i < 5; i ++ ) printf("(%d,%d) ", a[i].x, a[i].y); cout << endl; sort(a, a + 5, cmp); for (int i = 0; i < 5; i ++ ) printf("(%d,%d) ", a[i].x, a[i].y); cout << endl; return 0; }
2.5
lower_bound/upper_bound
二分lower_bound
的第三个参数传入一个元素x
,在两个迭代器(指针)指定的部分上执行二分查找,返回指向第一个大于等于x
的元素的位置的迭代器(指针)。#include <bits/stdc++.h> using namespace std; int main() { int a[] = {1, 2, 4, 5, 6}; int *p = lower_bound(a, a + 5, 3); cout << *p << endl; return 0; }
upper_bound
的用法和lower_bound
大致相同,唯一的区别是查找第一个大于x
的元素。当然,两个迭代器(指针)指定的部分应该是提前排好序的。在有序
int
数组(元素存放在下标1 ~ n
)中查找大于等于x
的最小整数的下标:int i = lower_bound(a + 1, a + 1 + n, x) - a;
#include <bits/stdc++.h> using namespace std; int main() { int a[] = {1, 2, 4, 5, 6}; int t = upper_bound(a, a + 5, 4) - a; vector<int> a(1, 2, 3, 4, 5, 6); int t = upper_bound(a.begin(), a.end(), 4) - a.begin(); cout << a[t] << endl; return 0; }
在有序
vector<int>
中查找小于等于x
的最大整数(假设一定存在):int y = *--upper_bound(a.begin(), a.end(), x);