1.位运算
1.1符号
& 与:
| 或:
~ 取反:~0=1;~1=0
^异或:
>>右移(所有位置上的数都往右边移动k位,移除出去的位置):a=110110,a>>1 结果:a=11011;a>>k相当于a/2^k(a除以2的k次方)
<<左移(往后补0):a=110,a<<1 结果:a=1100;a<<k相当于a*2^k
1.2常用操作:
1.求x的第k位数字 x >> k & 1
以int a=13为例,13的二进制表示为1101,要求第2位数字。先a>>2,得11;再是11 & 1,
所以得到第2位数字为1。
int main()
{
int a = 13;
cout << ( a >> 2 & 1 ) << endl;
for (int i = 5; i >= 0; i--)
{
cout << (a >> i & 1);
}
return 0;
}
运行结果:
2.lowbit(x) = x & -x,返回x的最后一位1以及后面的0
-x=~x+1,所以还可以写成:x&-x
代码验证如下:
#include <iostream>
using namespace std;
int main()
{
int a = 2310293;
int b = -a;
int c = ~a + 1;
cout << b << ' ' << c << endl;
return 0;
}
2.常用库函数 #include<algorithm>
2.1 reverse翻转
翻转一个vector:reverse(a.begin(), a.end());
翻转一个数组,元素存放在下标1 ~ n:reverse(a + 1, a + n + 1);
#include <iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
vector<int>a({ 1,2,3,4,5 });
reverse(a.begin(), a.end());
for (auto x : a) cout << x << ' ';
cout << endl;
int b[] = { 1,2,3,4,5 };
reverse(b, b + 5);//也是左闭右开,b+5表示5的下一个位置
for (auto x : b) cout << x << ' ';
cout << endl;
return 0;
}
运行结果:
2.2 unique去重
返回去重(只去掉相邻的相同元素)之后的尾迭代器(或指针),仍然为前闭后开,即这个迭代器是去重之后末尾元素的下一个位置。该函数常用于离散化,利用迭代器(或指针)的减法,可计算出去重后的元素个数。
#include <iostream>
#include<algorithm>
#include<vector>
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> b({ 1,1,2,2,3,3,4 });
int n = unique(b.begin(), b.end()) - b.begin();
cout << n << endl;
for (int i = 0; i < n; i++)
{
cout << b[i] << ' ';
}
cout << endl;
//vector另一种写法:
vector<int> c({ 1,1,2,2,3,3,4 });
c.erase(unique(c.begin(), c.end()), c.end());//unique函数是先将c中不相同的元素放在新的数组的前面
//相比原数组个数,后面缺的会随机填上。所以就用了erase,将后面的随机数删除。
for (auto x : c) cout << x << ' ';
cout << endl;
return 0;
}
运行结果:
2.3 random_shuffle随机打乱
这样写会发现多次运行的结果相同:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
vector<int> a({ 1,2,3,4,5 });
random_shuffle(a.begin(), a.end());
for (auto x : a) cout << x << ' ';
cout << endl;
return 0;
}
原因是随机种子一样,可以添加时间,使其不一样:
#include <iostream>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
int main()
{
vector<int> a({ 1,2,3,4,5 });
srand(time(0));
random_shuffle(a.begin(), a.end());
for (auto x : a) cout << x << ' ';
cout << endl;
return 0;
}
2.4 sort
对两个迭代器(或指针)指定的部分进行快速排序。可以在第三个参数传入定义大小比较的函数,或者重载“小于号”运算符。
把一个int数组(元素存放在下标1 ~ n)从大到小排序,传入比较函数
#include <iostream>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
//自己定义为从大到小排序
bool cmp(int a, int b)
{
return a > b;
}
int main()
{
vector<int> a({ 1,2,3,4,5 });
srand(time(0));
random_shuffle(a.begin(), a.end());//随机排
for (auto x : a) cout << x << ' ';
cout << endl;
sort(a.begin(), a.end());//从小到大的顺序
for (auto x : a) cout << x << ' ';
cout << endl;
sort(a.begin(), a.end(), greater<int>());//从大到小排序
for (auto x : a) cout << x << ' ';
cout << endl;
//自己定义为从大到小排序
sort(a.begin(), a.end(),cmp);
for (auto x : a) cout << x << ' ';
cout << endl;
return 0;
}
把自定义的结构体vector排序,重载“小于号”运算符:
#include <iostream>
#include<algorithm>
#include<vector>
#include<ctime>
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);//结构体要自己定义cmp
for (int i = 0; i < 5; i++)
printf("(%d,%d)", a[i].x, a[i].y);
cout << endl;
return 0;
}
结果运行:
不想另写cmp函数的话,可以直接在结构体用operater
#include <iostream>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
struct Rec
{
int x, y;
bool operator<(const Rec& t)const
{
return x < t.x;
}
}a[5];
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);
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的元素的位置的迭代器(指针)。
upper_bound的用法和lower_bound大致相同,唯一的区别是查找第一个大于x的元素。当然,两个迭代器(指针)指定的部分应该是提前排好序的。
在有序int数组(元素存放在下标1 ~ n)中查找大于等于x的最小整数的下标:
#include <iostream>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
int main()
{
int a[] = { 1,2,4,5,6 };
int* p = lower_bound(a, a + 5, 3);//返回大于等于x的第一个数
//int* p = lower_bound(a, a + 5, 7);//返回随机值,不存在
cout << *p << endl;
int t = lower_bound(a, a + 5, 3) - a;//减去数组名就返回下标
cout << t << endl;
int m = lower_bound(a, a + 5, 7) - a;//位置就是溢出数组的第一个位置
cout << m << endl;
int* q = upper_bound(a, a + 5, 4);//返回大于x的最大的数
cout << *q << endl;
return 0;
}
运行结果:
在有序vector<int>中:
#include <iostream>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
int main()
{
vector<int> a { 1,2,4,5,6 };
int t = lower_bound(a.begin (),a.end (), 3) - a.begin ();
cout << t << endl;
cout << a[t] << endl;
int m = upper_bound(a.begin(), a.end(), 5) - a.begin();
cout << m << endl;
cout << a[m] << endl;
return 0;
}
运行结果: