c++

1
extern int i;          //声明i但不定义

正则表达式

知乎-正则表达式

可变数组vector

属于<vector>

常用方法

成员函数 作 用
vector() 无参构造函数,将容器初始化为空
vector(int n) 将容器初始化为有 n 个元素
vector(int n, const T & val) 假定元素的类型是 T,此构造函数将容器初始化为有 n 个元素,每 个元素的值都是 val
vector(iterator first, iterator last) first 和 last 可以是其他容器的迭代器。一般来说,本构造函数初始化的结果就是将 vector 容器的内容变成与其他容器上的区间 [first, last) —致
void clear() 删除所有元素
bool empty() 判断容器是否为空
emplace_back() 更高效的void push_back(const T & val)
void pop_back() 删除容器末尾的元素
void push_back( const T & val) 将 val 添加到容器末尾
int size() 返回容器中元素的个数
T & front() 返回容器中第一个元素的引用
T & back() 返回容器中最后一个元素的引用
iterator insert(iterator i, const T & val) 将 val 插入迭代器 i 指向的位置,返回 i
iterator insert( iterator i, iterator first, iterator last) 将其他容器上的区间 [first, last) 中的元素插入迭代器 i 指向的位置
iterator erase(iterator i) 删除迭代器 i 指向的元素,返回值是被删元素后面的元素的迭代器
iterator erase(iterator first, iterator last) 删除容器中的区间 [first, last)
void swap( vector & v) 将容器自身的内容和另一个同类型的容器 v 互换

rbegin()和rend()

队列Queue

1
#include <queue>

C++队列Queue类成员函数如下:

back()返回最后一个元素

empty()如果队列空则返回真

front()返回第一个元素

pop()删除第一个元素

push()在末尾加入一个元素

size()返回队列中元素的个数

==实例==

初始化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
std::deque<int> mydeck(3, 100);        // 双端队列里初始化3个元素,都是100
std::list<int> mylist(2, 200);         // list 容器里初始化2个元素,都是200
std::queue<int> first;                 // 初始化一个空队列
std::queue<int> second(mydeck);        // 复制 mydeck 的内容初始化队列
std::queue<int, std::list<int> > third; // 初始化空队列,底层使用 list 容器
std::queue<int, std::list<int> > fourth(mylist);    // 复制 mylist 的内容初始化队列,底层使用 list 容器
std::cout << "size of first: " << first.size() << std::endl; // 0
std::cout << "size of second: " << second.size() << std::endl; // 3
std::cout << "size of third: " << third.size() << std::endl; // 0
std::cout << "size of fourth: " << fourth.size() << std::endl; // 2

判空

1
2
3
4
std::queue<int> myqueue1;
bool empty1 = myqueue1.empty(); // true
std::queue<int> myqueue2({100,100});
bool empty2 = myqueue2.empty(); // false

获得元素个数

1
2
3
4
5
6
std::queue<int> myints;
std::cout << "0. size: " << myints.size() << std::endl; // 输出:0
for (int i = 0; i < 5; i++) myints.push(i);
std::cout << "1. size: " << myints.size() << std::endl; // 输出:5
myints.pop();
std::cout << "2. size: " << myints.size() << std::endl; // 输出:4

返回头元素引用

1
2
3
4
5
6
7
std::queue<int> myqueue3;
myqueue3.push(77);
myqueue3.push(66);
int& a1 = myqueue3.front(); // 77
int a2 = myqueue3.front(); // 77
myqueue3.front() = 88; // 给头元素77赋值为88
std::cout << "front:" << myqueue3.front() << std::endl; // 输出:88

返回末尾元素引用

1
2
3
4
5
6
7
std::queue<int> myqueue4;
myqueue4.push(77);
myqueue4.push(66);
int& b1 = myqueue4.back(); // 66
int b2 = myqueue4.back(); // 66
myqueue4.back() = 33; // 给末尾元素66赋值为33
std::cout << "front:" << myqueue4.front() << std::endl; // 输出:33

入队/出队

1
2
3
4
5
std::queue<int> myqueue5;
myqueue5.push(55); // 无返回值,入队了一个55,size()==1
myqueue5.push(45); // size()==2
myqueue5.pop(); // 无返回值,出队了一个55,size()==1
myqueue5.emplace(45);//另一种入队,其底层容器调用了emplace_back方法

交换

1
2
3
4
5
6
7
std::queue<int> teeth;
teeth.emplace(4); teeth.emplace(7);
std::queue<int> bags;
bags.emplace(4); bags.emplace(7); bags.emplace(7);
bags.swap(teeth);
std::cout << teeth.size() << std::endl; //输出:3
std::cout << bags.size() << std::endl; //输出:2

运算符 = != > >= < <=

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// [==]当两个队列front()内容一致,返回true
std::queue<int> q1, q2;
bool ret = q1 == q2; // ret为true

// [!=]当两个队列元素front()不相等,返回true
std::queue<int> q3, q4;
q3.push(1);
bool ret2 = q3 != q4; // ret2为true

// [>]左边队列的front()的元素大于右边队列pop的元素,则返回true.
std::queue<int> q5, q6;
q5.push(1); q5.push(2); q5.push(2);
q6.push(0); q6.push(2);
bool ret3 = q5 >= q6; // ret3为true,因为1大于0

头文件

algorithm(算法库)

==sort()==:

1
2
3
4
5
6
7
8
bool cmp(int a,int b){//此处为从大到小排序
  return a>b;
}

std::sort(arr.begin(),arr.end());
std::sort(arr.begin(),arr.begin()+arr.size());
std::sort(arr.begin(),arr.begin()+arr.size(),cmp;
std::sort(arr.rbegin(),arr.rend());//反向迭代器,这样写也可以做到由大到小排

==__gcd(int,int)==:最大公约数 注意是两个’_’ 用go写就是这个

1
2
3
4
5
6
func gcd(a, b int) int {
    for a != 0 {
        a, b = b%a, a
    }
    return b
}

function

std::function是一个函数包装器,该函数包装器模板能包装任何类型的可调用实体,如普通函数,函数对象,lamda表达式等。包装器可拷贝,移动等,并且包装器类型仅仅依赖于调用特征,而不依赖于可调用元素自身的类型。std::function是C++11的新特性,包含在头文件中。

1
2
3
4
5
6
7
//定义void dfs(int,int,int){}
function<void (int,int,int)> dfs=[&](int x,int y,int gold){}

//function<int(int)> dfs =[&](int x)int{return x;} 省略"->"是不规范的lambda表达式,在很多编译器以及蓝桥上可通过,但力扣会报错
function<int(int)> dfs =[&](int x)->int{return x;};

[&,a,b]()->int{}//以只读的方式读入a,b,->后面表示返回

unordered_set

1
#include<unordered_set>

不能含有重复元素的容器

成员方法 功能
begin() 返回指向容器中第一个元素的正向迭代器。
end(); 返回指向容器中最后一个元素之后位置的正向迭代器。
cbegin() 和 begin() 功能相同,只不过其返回的是 const 类型的正向迭代器。
cend() 和 end() 功能相同,只不过其返回的是 const 类型的正向迭代器。
empty() 若容器为空,则返回 true;否则 false。
size() 返回当前容器中存有元素的个数。
max_size() 返回容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同。
find(key) 查找以值为 key 的元素,如果找到,则返回一个指向该元素的正向迭代器;反之,则返回一个指向容器中最后一个元素之后位置的迭代器(如果 end() 方法返回的迭代器)。
count(key) 在容器中查找值为 key 的元素的个数。
equal_range(key) 返回一个 pair 对象,其包含 2 个迭代器,用于表明当前容器中值为 key 的元素所在的范围。
emplace() 向容器中添加新元素,效率比 insert() 方法高。
emplace_hint() 向容器中添加新元素,效率比 insert() 方法高。
insert() 向容器中添加新元素。
erase() 删除指定元素。
clear() 清空容器,即删除容器中存储的所有元素。
swap() 交换 2 个 unordered_map 容器存储的元素,前提是必须保证这 2 个容器的类型完全相等。
bucket_count() 返回当前容器底层存储元素时,使用桶(一个线性链表代表一个桶)的数量。
max_bucket_count() 返回当前系统中,unordered_map 容器底层最多可以使用多少桶。
bucket_size(n) 返回第 n 个桶中存储元素的数量。
bucket(key) 返回值为 key 的元素所在桶的编号。
load_factor() 返回 unordered_map 容器中当前的负载因子。负载因子,指的是的当前容器中存储元素的数量(size())和使用桶数(bucket_count())的比值,即 load_factor() = size() / bucket_count()。
max_load_factor() 返回或者设置当前 unordered_map 容器的负载因子。
rehash(n) 将当前容器底层使用桶的数量设置为 n。
reserve() 将存储桶的数量(也就是 bucket_count() 方法的返回值)设置为至少容纳count个元(不超过最大负载因子)所需的数量,并重新整理容器。
hash_function() 返回当前容器使用的哈希函数对象。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;
int main()
{
    //创建一个空的unordered_set容器
    std::unordered_set<std::string> uset;
    //给 uset 容器添加数据
    uset.emplace("http://c.biancheng.net/java/");
    uset.emplace("http://c.biancheng.net/c/");
    uset.emplace("http://c.biancheng.net/python/");
    //查看当前 uset 容器存储元素的个数
    cout << "uset size = " << uset.size() << endl;
    //遍历输出 uset 容器存储的所有元素
    for (auto iter = uset.begin(); iter != uset.end(); ++iter) {
        cout << *iter << endl;
    }
    return 0;
}

位、进制、原补反码

打印对应进制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <iostream>
#include <bitset> //输出二进制的头文件
using namespace std;
 
int main(){
	int a = 2149580819;
	cout << "八进制: " << oct << a << endl;
	cout << "十进制: " << dec << a << endl;
	cout << "十六进制: " << hex << a << endl;
	cout << "二进制: " << bitset<sizeof(a)*8>(a) << endl;
	return 0;
}

原码:

​ 正数:对应的二进制码

​ 负数:最高位符号位为1,其余是对应的二进制码

反码:

​ 对原码按位取反,在c++中使用’~‘作为取反符号

补码:

​ 反码加一,在程序中负数以补码形式存储

#include<bits/stdc++.h> using namespace std; int main(){ int a=-1,b=100; cout«bitset<sizeof(a)*8>(a)«" -1"«endl«bitset<sizeof(~a)*8>(~a)«" ~(-1)"«endl«endl«bitset<sizeof(b)*8>(b)«" 100"«endl«bitset<sizeof(~b)*8>(~b)«" ~(100)"; return 0; }

c++基础

namespace(命名空间)

为了避免不同编译者定义不同变量的情况,使用命名空间独立开了各自的变量

使用命名空间可以使用using namespace全局引用,也可以使用::局部引用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
namespace a{
    class peo{
    public:
        int v;
        void say(){
            printf("%d",v);
        }
    };
}

using namespace a;

int main()
{
    peo p;
    p.v=1;
    p.say();
  return 0;
}

std命名空间

c++演变中,经历了一次巨大更新,为了避免老版本的东西无法使用,他们就把所有更新内容整到std内容空间中了,即不使用std的c++就是老版本c++,该改动中去掉了.h后缀,并给所有c的库加上了前缀’c’,如"math.h"被重命名为"cmath",std命名空间中添加了我们所熟知的cin>>,cout<<

1
2
3
4
5
6
7
8
#include<iostream>
using namespace std;
int main(){
    int x;
    cin>>x;
    cout<<x<<endl;
    return 0;
}

using namespace std;写在全局并不规范,会增加命名冲突的风险,但是方便

输入输出

使用输入输出时,需要包含头文件iostream,它包含了用于输入输出的对象,例如常见的cin表示标准输入、cout表示标准输出、cerr表示标准错误

bool

c++支持bool,但是默认以1和0输出,如果要输出true or false则需要使用boolalpha

1
2
3
4
bool ok=true;
cout<<ok<<endl;//1
cout<<boolalpha<<ok<<endl;//true
cout<<noboolalpha<<ok<<endl;//1

new 和 delete

申请、释放内存

1
2
3
4
5
int *p = new int;//分配1个int型的内存空间
delete p;//释放内存

int *p = new int[10];//分配10个int型的内存空间
delete[] p;//释放内存

inline(内联函数)

即编译时,不是以调用的形式把函数放在外面调用,而是直接替换掉每一次调用

在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。

栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <stdio.h>
inline const char *num_check(int v)
{
    return (v % 2 > 0) ? "奇" : "偶";
}
 
int main(void)
{
    int i;
    for (i = 0; i < 100; i++)
        printf("%02d   %s\n", i, num_check(i));
    return 0;
}

inline使用限制

inline 的使用是有所限制的,inline 只适合涵数体内代码简单的涵数使用,不能包含复杂的结构控制语句例如 while、switch,并且不能内联函数本身不能是直接递归函数(即,自己内部还调用自己的函数)。

inline仅是一个对编译器的建议

inline 函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。

建议 inline 函数的定义放在头文件中

其次,因为内联函数要在调用点展开,所以编译器必须随处可见内联函数的定义,要不然就成了非内联函数的调用了。所以,这要求每个调用了内联函数的文件都出现了该内联函数的定义

因此,将内联函数的定义放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦。

声明跟定义要一致:如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为。如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定。所以,最好将内联函数定义放在头文件中。

类中的成员函数与inline

定义在类中的成员函数默认都是内联的,如果在类定义时就在类内给出函数定义,那当然最好。如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上 inline,否则就认为不是内联的。

1
2
3
4
5
6
7
8
// 头文件
class A
{
    public:
    void Foo(int x, int y);
}
// 定义文件,声明内联
inline void A::Foo(int x, int y){}

static(静态成员变量)

静态成员变量是一种特殊的成员变量,它被关键字static修饰,它不占用额外内存,它是相同class的所有变量(如:stu li,stu wang)共用

string

属于<string>

==转char[]==

c_str(),将string转为对应的const char[]

1
2
string s="hello";
const char * arr=s.c_str()

string的增删改查

==插入==

insert()

1
2
string s="012345";
s=s.insert(2,"hello");

s最终为:01hello2345

==删除==

erase()

1
2
3
4
5
6
7
string s1, s2, s3;
s1 = s2 = s3 = "1234567890";
s2.erase(5);
s3.erase(5, 3);
cout<< s1 <<endl;//1234567890
cout<< s2 <<endl;//12345
cout<< s3 <<endl;//1234590

==提取==

substr(),类似切片

1
2
3
string s="012345";
s=s.substr(2,3);
cout<<s;//234

==查找==

(1) find(string str,int n)

从第n个位置开始查找是否存在字符串str,若存在返回char[]下标,若不存在返回一个极大值(不一定是18446744073709551615)

1
2
3
  string s="1234567890";
  cout<<s.find("123",3)<<endl;//18446744073709551615
  cout<<s.find("789",3);//6

(2) rfind(string str,int n)

直到下标n为止,查找字符串str

1
2
3
string s="1234567890";
cout<<s.find("123",3)<<endl;//0
cout<<s.find("789",3);//18446744073709551615

(3) find_first_of(string str)

查找str的某个字符,不需要整个字符串存在首次出现的位置

1
2
3
string s="1234567890";
cout<<s.find_first_of("879")<<endl;//6,7在第6个
cout<<s.find_first_of("012")<<endl;//0,1在第0个

switch…case…

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main ()
{
   char grade = 'D';
   switch(grade)
   {
   case 'A' :
      cout << "很棒!" << endl; 
      break;
   case 'B' :
   case 'C' :
      cout << "做得好" << endl;
      break;
   case 'D' :
      cout << "您通过了" << endl;
      break;
   case 'F' :
      cout << "最好再试一下" << endl;
      break;
   default :
      cout << "无效的成绩" << endl;
   }
   return 0;
}
updatedupdated2023-02-072023-02-07