杨记

碎片化学习令人焦虑,系统化学习使人进步

0%

C++补充

学习C++过程中碰到的新的知识点,可能会记录在此

C++ setw() 函数用于设置字段的宽度,语法格式如下:

1
setw(n)

n 表示宽度,用数字表示。

setw() 函数只对紧接着的输出产生作用。

在头文件<iomanip>

当后面紧跟着的输出字段长度小于 n 的时候,在该字段前面用空格补齐,当输出字段长度大于 n 时,全部整体输出。

1
2
int __gcd(value, value);	//gcc编译器自带的函数,求最大公约数
int __builtin_popcount(value); //计算value的二进制形式中有多少个1,如32就是一个1
1
2
3
4
5
6
7
8
9
#include <cctype> 或 #include <ctype.h> 或 #include <locale>
int isalpha(int c); //判断是不是字母
int isupper(int c); //判断是不是大写字母
int islower(int c); //判断是不是小写字母
int isdigit(int c); //判断是不是数字
int isalnum(int c); //判断是不是字母或数字

int tolower(int c); //返回c的小写字母
int toupper(int c); //返回c的大写字母
1
2
3
4
5
min(value1, value2);
max(value1, value2);

min_element(first, last, comp);
max_element(first, last, comp);

algorithm

1
2
3
bool all_of (InputIterator first, InputIterator last, UnaryPredicate pred);	//序列中的所有元素都可以使谓词返回 true
bool none_of (InputIterator first, InputIterator last, UnaryPredicate pred); //序列中的无元素可以使谓词返回 true
bool any_of (InputIterator first, InputIterator last, UnaryPredicate pred); //序列中的任一元素可以使谓词返回 true
1
2
3
4
5
6
7
8
9
#include <iostream>     // std::cout
#include <algorithm> // std::all_of
#include <array> // std::array
int main () {
std::array<int,8> foo = {3,5,7,11,13,17,19,23};
if ( std::all_of(foo.begin(), foo.end(), [](int i){return i%2;}) )
std::cout << "All the elements are odd numbers.\n";
return 0;
}

查看类型名称 typeid(value).name(); 头文件typeinfo

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <string>
using namespace std;
int main()
{
int n = 5;
cout<<typeid(n).name()<<endl;
cout<<typeid(string).name()<<endl;
return 0;
}
1
2
3
4
5
6
const char* c_str(string); 	string 转 C风格字符串
string(const char*); c风格字符串 转 string
int atoi(const char*); c风格字符串 转 数字
string to_string(value); 数字转字符串

char* itoa(int value,char*string,int radix);//value: 要转换的整数,string: 转换后的字符串,radix: 转换进制数,如2,8,10,16 进制等。不是标准的,编译器可能不支持

数字和字符串转换

数字转字符串

int sprintf ( char * str, const char * format, ... );

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
char str[10];
int a=1234321;
sprintf(str,"%d",a);
int len=strlen(str);
cout<<"字符串"<<str<<endl;
cout<<"长度"<<len<<endl;

char str1[10];
double b=123.321;
sprintf(str1,"%.3lf",b);
int len1=strlen(str1);
cout<<"字符串"<<str1<<endl;
cout<<"长度"<<len1<<endl;
return 0;
}

stringsteam

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <string>
#include <iostream>
#include <sstream>
using namespace std;

int main(){
double a = 123.32;
string res;
stringstream ss; //定义流ss
ss << a; //将数字a转化成流ss
ss >> res; //将流ss转化成字符串
//string res = ss.str();
cout<<res<<endl;
return 0;
}

字符串转数字

1
2
3
int stoi (const string&  str, size_t* idx = 0, int base = 10); // base是进制,默认10进制
long stol (const string& str, size_t* idx = 0, int base = 10);
long long stoll (const string& str, size_t* idx = 0, int base = 10);

int sscanf ( const char * s, const char * format, ...);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int main()
{
char str[]="1234321";
int a;
sscanf(str,"%d",&a);
cout<<a<<endl;

char str1[]="123.321";
double b;
sscanf(str1,"%lf",&b);
cout<<b<<endl;
return 0;
}

stringstream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <string>
#include <sstream>
#include <iostream>
using namespace std;

int main(){
double a ;
string res= "123.32";
stringstream ss;
ss << res;
ss >> a;
cout<<a<<endl;
return 0;
}

清除键盘缓冲区

C:fflush(stdin);

C++:

  • cin.clear(); 将错误标识置为0;
  • cin.sync();
  • cin.ignore(100, '\n'); 丢弃字符直到遇到 ‘\n’ (包含 ‘\n’ ),如果丢去了100个字符还没遇到 ‘\n’ ,也停止,100是丢弃的最大字符数。

C/C++还可以使用while(getchar() != '\n'); 推荐这个,前面的几个感觉有问题。

注意

数组作为形参传递到被调函数中,是以指针的形式指向数组的首地址,无法使用sizeof计算数组大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

void test(char t[])
{
cout << sizeof(t) << endl; // 4
}

int main()
{
cout << sizeof(char*) << endl; // 4
char t[] = "abcdfjie";
cout << sizeof(t) << endl; // 9
test(t);
return 0;
}

数组批量赋值

memset函数,一般是用于对字符数组操作,头文件<cstring><string.h>

void * memset ( void * ptr, int value, size_t num );

ptr数组的起始地址,num是有多长的字节设置为value,value是对num长度的字节都设置为value,范围0~255

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <cstring>
using namespace std;
int main ()
{
char str[] = "almost every programmer should know memset!";
memset (str,'-',6);
cout<<str<<endl; // ------ every programmer should know memset!
int a[5];
memset(a, 0, 5*sizeof(int)); // 没问题
memset(a, 1, 5*sizeof(int)); // 结果不是{1,1,1,1,1} 因为一个int是4个字节,memset是对接下来20个字节每个字节都设为1,如果初始化为0就没问题
return 0;
}

fill函数,头文件<algorithm>

void fill (ForwardIterator first, ForwardIterator last, const T& val);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main()
{
int a[5];
fill(a, a+5, 1); //a: 1,1,1,1,1

vector<int> myvector (8); // myvector: 0 0 0 0 0 0 0 0
fill (myvector.begin(),myvector.begin()+4,5); // myvector: 5 5 5 5 0 0 0 0
fill (myvector.begin()+3,myvector.end()-2,8); // myvector: 5 5 5 8 8 8 0 0
return 0;
}

强制类型转换

C强制转换与C++强制转换

1
2
3
(type-id)expression 	//转换格式1

type-id(expression) //转换格式2

c++除了能使用c语言的强制类型转换外,还新增了四种强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast,主要运用于继承关系类间的强制转化,语法为:

1
2
3
4
static_cast<new_type>      (expression)
dynamic_cast<new_type> (expression)
const_cast<new_type> (expression)
reinterpret_cast<new_type> (expression)

new_type为目标数据类型,expression为原始数据类型变量或者表达式

C++强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast - SpartacusIn21 - 博客园 (cnblogs.com)

priority_queue

优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的

和队列基本操作相同:

  • top 访问队头元素
  • empty 队列是否为空
  • size 返回队列内元素个数
  • push 插入元素到队尾 (并排序)
  • emplace 原地构造一个元素并插入队列
  • pop 弹出队头元素
  • swap 交换内容

定义:

1
2
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
  • T——数据类型
  • Container——容器类型(必须是数组实现的容器如:vector,deque等,不能是list)
  • Compare——比较方式,自定义数据类型必要;基本数据类型默认是大顶堆
1
2
3
4
5
6
7
8
//升序队列,小顶堆
priority_queue <int,vector<int>,greater<int>> q;
//降序队列,大顶堆
priority_queue <int,vector<int>,less<int>> q;
//greater和less是std实现的两个仿函数
//greater是将大的元素放在前面:5 4 3 2 1 降序序列
//less相反:1 2 3 4 5 升序序列
//priority_queue对greater和less好像反了一样

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
priority_queue<int> pq; //默认情况
priority_queue<int, vector<int>, less<int>> pql; //降序
priority_queue<int, vector<int>, greater<int>> pqg; //升序
for(int i : {3,5,2,8,50,34}) {
pq.push(i);
pql.push(i);
pqg.push(i);
}

cout<<"a greater:";
int a[] = {3,5,2,8,50,34};
sort(a, a + 6, greater<int>()); //按降序排序 greater
for(int i : a) {
cout<<i<<" ";
}
cout<<endl;

cout<<"pq 默认:";
while(!pq.empty()) { //输出队列pq的元素 默认less
cout<<pq.top()<<" "; //队首元素
pq.pop(); //出队
}
cout<<endl;

cout<<"pql less:";
while(!pql.empty()) { //输出队列pql的元素 less
cout<<pql.top()<<" "; //队首元素
pql.pop(); //出队
}
cout<<endl;

cout<<"pqg greater:";
while(!pqg.empty()) { //输出队列pqg的元素 greater
cout<<pqg.top()<<" "; //队首元素
pqg.pop(); //出队
}
cout<<endl;

return 0;
}
1
2
3
4
a greater:50 34 8 5 3 2 
pq 默认:50 34 8 5 3 2
pql less:50 34 8 5 3 2
pqg greater:2 3 5 8 34 50

pair的比较,先比较第一个元素,第一个相等比较第二个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
priority_queue<pair<int, int> > a;
pair<int, int> b(1, 2);
pair<int, int> c(1, 3);
pair<int, int> d(2, 5);
a.push(d);
a.push(c);
a.push(b);
while (!a.empty())
{
cout << a.top().first << ' ' << a.top().second << '\n';
a.pop();
}
}
1
2
3
2 5
1 3
1 2

对自定义数据类型,可以重载运算符<,或写仿函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <queue>
using namespace std;

//方法1
struct tmp1 //运算符重载<
{
int x;
tmp1(int a) {x = a;}
bool operator<(const tmp1& a) const
{
return x < a.x; //大顶堆
}
};

//方法2
struct tmp2 //重写仿函数,也可以是类
{
bool operator() (tmp1 a, tmp1 b)
{
return a.x < b.x; //大顶堆
}
};

int main()
{
tmp1 a(1);
tmp1 b(2);
tmp1 c(3);
priority_queue<tmp1> d;
d.push(b);
d.push(c);
d.push(a);
while (!d.empty())
{
cout << d.top().x << '\n';
d.pop();
}
cout << endl;

priority_queue<tmp1, vector<tmp1>, tmp2> f;
f.push(c);
f.push(b);
f.push(a);
while (!f.empty())
{
cout << f.top().x << '\n';
f.pop();
}
}

原文链接:https://blog.csdn.net/weixin_36888577/article/details/79937886

bitset

1
2
3
4
5
6
7
8
9
10
#include <bitset>
std::bitset<8> bs;

// 模板参数是一个size_t类型的数值(value),而非一个类型
// numeric_limits<size_t>::min() == 0
// std::bitset<8> 表示的二进制位为8位,
// 默认的构造函数将其初始为全0

cout << bs.to_ulong() << endl; // 0
cout << bs.to_string() << endl; // 00000000

bs[0]表示的是将该数值转换为二进制时的最末尾元素,而非首位(其意义和数组并不相同)

1
2
3
std::bitset<8> bs;
//bs[0] = 1; // 0000 0001
//bs[7] = 1; // 1000 0000

使用string对象

1
2
std::bitset<8> bs("00000111");
bs.to_ulong(); // 7

bitset的操作

成员函数 函数功能
bs.any() 是否存在值为1的二进制位
bs.none() 是否不存在值为1的二进制位 或者说是否全部位为0
bs.size() 位长,也即是非模板参数值
bs.count() 值为1的个数
bs.test(pos) 测试pos处的二进制位是否为1 与0做或运算
bs.set() 全部位置1
bs.set(pos) pos位处的二进制位置1 与1做或运算
bs.reset() 全部位置0
bs.reset(pos) pos位处的二进制位置0 与0做或运算
bs.flip() 全部位逐位取反
bs.flip(pos) pos处的二进制位取反
bs.to_ulong() 将二进制转换为unsigned long输出
bs.to_string() 将二进制转换为字符串输出
~bs 按位取反 效果等效为bs.flip()
os << b 将二进制位输出到os流 小值在右,大值在左

原文链接: C++基础——简单而强大的bitset_五道口纳什的博客-CSDN博客_c++bitset

行列式计算

代数余子式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <vector>
using namespace std;

long long determinant(vector<vector<long long>> &D);
static int divisor = 0x1f1f1f1f;

int main( )
{
int T;
cin >> T;
vector<int> result;
while(T--)
{
int n;
cin >> n;
vector<vector<long long>> nums(n, vector<long long>(n));
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
cin >> nums[i][j];
}
}
int tmp = determinant(nums) % divisor;
if(tmp < 0) tmp += divisor;
result.emplace_back(tmp);
}
for(int i : result)
{
cout << i << endl;
}
return 0;
}

//输入代表矩阵的二维数组、矩阵阶数,返回矩阵的行列式
long long determinant(vector<vector<long long>> &D)
{
int n = D.size();
long long d = 0;
// 一阶二阶直接计算
if(n == 1) d = D[0][0];
if(n == 2) d = (D[0][0] * D[1][1] - D[0][1] * D[1][0]) % divisor;
else
{
//余子式
vector<vector<long long>> M(n - 1, vector<long long>(n - 1));
for(int k = 0; k < n; ++k)
{
for(int i = 0; i < n-1; ++i)
{
for(int j = 0; j < n-1; ++j)
{
M[i][j] = D[i + 1][j < k ? j : j + 1];
}
}
// 按第一行展开,递归计算行列式,注意元素0则不展开可以加快计算速度
if(D[0][k])
{
d += D[0][k] * determinant(M) * (((2 + k) % 2) ? -1 : 1) % divisor;
}
}
}
return d;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
3
3
1 -2 -1
0 3 2
3 1 -1
3
0 3 2
1 -2 -1
3 1 -1
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <vector>
using namespace std;

int inverseNumber(vector<int> &p);
int determinant(vector<vector<int>> &p);

int main( )
{
int divisor = 0x1f1f1f1f;
int T;
cin >> T;
vector<int> result;
while(T--)
{
int n;
cin >> n;
vector<vector<int>> nums(n, vector<int>(n));
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
cin >> nums[i][j];
}
}
int tmp = determinant(nums) % divisor;
if(tmp < 0) tmp += divisor;
result.emplace_back(tmp);
}
for(int i : result)
{
cout << i << endl;
}
return 0;
}

//求逆序数
int inverseNumber(vector<int> &p)
{
int count = 0;
int len = p.size();
for (int i = 0; i < len; ++i)
{
for (int j = i + 1; j < len; ++j)
{
if (p[i] > p[j])
{
++count;
}
}
}
if (count % 2 == 0)
{
return 1;
}
else
{
return -1;
}
}

//求和函数
int determinant(vector<vector<int>> &p)
{
int n = p.size();
vector<int> a(n);
int count = 1; //结果
int r = 0;
//初始化系数
for(int i = 0; i < n; i++)
{
a[i] = i + 1;
}

do{
for (int i = 0; i < n; i++)
{
count *= p[i][a[i]-1];
}
r += inverseNumber(a) * count;
count = 1;

}while(next_permutation(a.begin(), a.end()));
return r;
}

欢迎关注我的其它发布渠道