(知识点笔记)C++算法竞赛语法基础:位运算与常用库函数

本文详细介绍了C++中的位运算符(如与、或、异或、左右移等),并展示了如何使用这些运算符实现特定功能,如获取数字的位、位操作、数组/向量的常见操作如翻转、去重、随机打乱和排序,以及lower_bound和upper_bound的二分查找。
摘要由CSDN通过智能技术生成

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;
}

运行结果: 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值