比较乱,有空再整理~
C++学习笔记
命名空间的using
声明
一般用到标准输入输出流的时候,库函数属于命名空间std
,用作std::cout
、std::cin
或者在开头声明:using namespace std;
或者单独声明:using std::cin;
、using std::cout;
类型说明符auto
auto
:让编译器去分析表达式所属的类型。
1 2
| auto cnt = 0; auto pi = 3.14;
|
类型指示符decltype
decltype
是declare type
的缩写,译为声明类型。
能从表达式的类型推断出变量的类型,如:
1
| decltype(sizeof(arr)) length;
|
基于范围的for
语句(range for)
for (declaration : expression)
statement
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for (auto c : str) { cout << c << “ ”; } cout << str;
for (auto &c : str) { c = toupper(c); } cout << str;
|
cpp中类相关
静态成员变量和静态成员函数
类中定义的静态成员、函数,为整个类所有,所有对象共享。所以可以直接通过类名访问,当然也可以通过对象直接访问。
静态成员函数只能直接访问静态变量和静态函数(因为不能实例化)。
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
| #include <iostream> #include <string> using namespace std; class test { private: static int m_value; public: test() { m_value++; } static int getValue() { return m_value; } }; int test::m_value = 0; int main() { test t1; test t2; test t3; cout << "test::m_value2 = " << test::getValue() << endl; cout << "t3.getValue() = " << t3.getValue() << endl; system("pause"); }
|
|
静态成员函数 |
普通成员函数 |
所有对象共享 |
yes |
yes |
隐含this 指针 |
no |
yes |
访问普通成员变量(函数) |
no |
yes |
访问静态成员变量(函数) |
yes |
yes |
类的继承
相应的构造函数也可以继承。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Gene { public: int index; int dir; Gene(int _index, int _dir) :index(_index), dir(_dir) {}; }; class Res :public Gene { public: int station; double st; double pt; Res(int _station, int _index, int _dir, double _st, double _pt) :Gene(_index, _dir), station(_station), st(_st), pt(_pt) {}; string fout()const; };
|
读取CSV文件,表格型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ifstream inFile(filePath, ios::in); string lineStr; getline(inFile, lineStr); while (getline(inFile, lineStr)) { stringstream ss(lineStr); string str; vector<string> lineArray; while (getline(ss, str, ',')) lineArray.push_back(str); strArray.push_back(lineArray); }
|
判断字符串是否是数字
c++比较愚蠢,只能一个字符一个字符的判断
方法一:判断字符的ASCII范围
(数字的ASCII范围为48~57)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| bool AllisNum(string str) { for (int i = 0; i < str.size(); i++) { int tmp = (int)str[i]; if (tmp >= 48 && tmp <= 57) { continue; } else { return false; } } return true; }
|
方法二:使用C++提供的stringstream对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| stringstream sin(str); double d; char c; if(!(sin >> d)) {
return false; } if (sin >> c) {
return false; } return true; }
|
方法三:使用std::isdigit
来判断
有一个大坑,若字符是中文可能会报错。
1 2 3 4 5 6 7
| bool isNumber(const string& str) { for (char const &c : str) { if (std::isdigit(c) == 0) return false; } return true; }
|
数字取整取小数
程序运行时间计时⏲
clock()
有毫秒级的精度,直接上例子:
1 2 3 4 5 6 7 8 9
| #include<time.h> int main() { time_t startTime, endTime; startTime = clock(); func(); endTime = clock(); cout << "运行时间:" << (endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; }
|
cpp运算符重载
C++重载相等运算符
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
| #include <iostream>
class Person { private: int m_age; public: bool operator==(const Person& other) { std::cout << "call member function operator==" << std::endl; if (this->m_age == other.m_age) { return true; } return false; } };
int main() { Person p1(10); Person p2(10);
if (p1 == p2) { std::cout << "p1 is equal with p2." << std::endl; } }
|
C++ 输入/输出运算符重载
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
| class MyClass { public: int a = 0; MyClass(){}; friend ostream &operator<<(ostream &output, const MyClass my) { output << my.a << endl; return output; } friend istream &operator>>(istream &input, MyClass &my) { input >> my.a; return input; } };
int main() { MyClass my; cout << my.a << endl; cout << my; cin >> my; cout << my; return 0; }
|
cpp匿名函数
lambda函数的一般形式
cpp中的匿名函数用Lambda表达式实现,又称为lambda函数
可以这样来定义一个lambda函数
1 2
| auto func = []() { std::cout << "Hello world"; }; func();
|
正常情况下,只要函数体中所有return都是同一个类型的话,编译器就会自行判断函数的返回类型。也可以显示地指定lambda函数的返回类型。这个需要用到函数返回值后置的功能,比如这个例子
1
| [] () -> int { return 1; }
|
所以总的来说lambda函数的一般形式就是:
1
| [captures] (params) -> ret {Statments;}
|
lambda函数的变量截取
- [] 不截取任何变量
- [&} 截取外部作用域中所有变量,并作为引用在函数体中使用
- [=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
- [=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
- [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
- [this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
lambda函数的使用
在类似find_if
函数中需要人工定义一个cmp
函数的情况,用lambda函数就会很方便,一行代码不用另外再显示定义一个函数。示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <algorithm>
vector<Solution> resArray;
bool TALBP::cmp_fitness(Solution ind1, Solution ind2) { return ind1.fitness < ind2.fitness; } sort(resArray.begin(), resArray.end(), cmp_fitness);
sort(resArray.begin(), resArray.end(), [](const Solution& s1, const Solution& s2) {return s1.fitness < s2.fitness; });
int target_index; auto it = find_if(resArray.begin(), resArray.end(), [&](const Solution & s) {return s.op.index == target_index; });
for_each( v.begin(), v.end(), [] (int val) { cout << val; } );
|
cpp中vector相关
初始化
初始化其大小
1 2 3 4 5 6 7 8
| vector<int> v1;
vector<int> v2(2); v1.resize(2);
vector<int> v3(3, 4); v1.resize(3, 4);
|
二维数组的初始化
1
| vector<vector<int>> v6(m, vector<int>(n, 0));
|
用已有数值初始化
1 2 3 4 5 6 7
| vector<int> v4(v1); vector<int> v4 = v1;
int a[3] = {1, 2, 3}; vector<int> v5(a, a + 2); vector<int> v5(v1.begin(), v1.end() - 1);
|
插入数据
单个在最前面,即第一个位置插入
两个vector合并,也用insert
,即后一个在前一个的最后插入。
1
| resStaList.insert(resStaList.end(), temp.begin(), temp.end());
|
排序
简单排序
从小到大排序比较简单,使用sort()函数既可
1 2 3 4 5
| #include <algorithm>
sort(v.begin(),v.end()); sort(vec.rbegin(), vec.rend()); reverse(arr.begin(), arr.end());
|
自定义排序
1 2 3 4 5 6 7 8 9 10 11
| #include <algorithm>
vector<Solution> resArray;
bool TALBP::cmp_fitness(Solution ind1, Solution ind2) { return ind1.fitness < ind2.fitness; } sort(resArray.begin(), resArray.end(), cmp_fitness); 或用lambda函数(匿名函数)更方便 sort(resArray.begin(), resArray.end(),[](const Solution& s1, const Solution& s2) {return s1.fitness < s2.fitness; });
|
删除
Untitled
查找并删除
1 2 3
| auto it = find(opr_left.begin(), opr_left.end(), value); auto it = find_if(opr_left.begin(), opr_left.end(), cmp); opr_left.erase(it);
|
去重
用unique
函数来帮忙
查找相邻并且相同的,将之移到容器末尾
最后返回非重复的的迭代器处。
再将返回值到末尾的重复值用erase
删除就可以得到去重后的结果了
1 2
| auto last = std::unique(v.begin(), v.end()); v.erase(last, v.end());
|
正则表达式
符号 |
意义 |
^ |
匹配行的开头 |
$ |
匹配行的结尾 |
. |
匹配任意单个字符 |
[…] |
匹配[]中的任意一个字符 |
(…) |
设定分组 |
\ |
转义字符 |
\d |
匹配数字[0-9] |
\w |
匹配字母[a-z],数字,下划线 |
\s |
匹配空格 |
\W |
\w 取反 |
\D |
\d 取反 |
\S |
\s 取反 |
+ |
前面的元素重复1次或多次 |
* |
前面的元素重复任意次 |
? |
前面的元素重复0次或1次 |
{n} |
前面的元素重复n次 |
{n,} |
前面的元素重复至少n次 |
{n,m} |
前面的元素重复至少n次,至多m次 |
| |
逻辑或 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include<iostream> #include<regex>
using namespace std;
int main1() { regex reg("([a-zA-Z]*) ([a-zA-Z]*)$"); cmatch what; bool isit = regex_match("id admin", what, reg); for(int i = 0; i !=what.size(); ++i) { cout << what[i+1].first << "\t"; } cout << "match" << endl; }
|
有个坑,regex_match
方法需要输入const char*
,这时就需要类型转化
1 2 3 4 5 6 7 8 9
| string s = "string_To_const char* "; const char *c_s=s.c_str();
const char *c_ss = s.data();
const char* p = "const char* _To_string"; string y(p);
|
键值对,哈希表
unordered_map
容器,直译过来就是”无序 map 容器”的意思。所谓“无序”,指的是 unordered_map 容器不会像 map 容器那样对存储的数据进行排序。换句话说,unordered_map 容器和 map 容器仅有一点不同,即 map 容器中存储的数据是有序的,而 unordered_map 容器中是无序的。
具体来讲,unordered_map 容器和 map 容器一样,以键值对(pair类型)的形式存储数据,存储的各个键值对的键互不相同且不允许被修改。但由于 unordered_map 容器底层采用的是哈希表存储结构,该结构本身不具有对数据的排序功能,所以此容器内部不会自行对存储的键值对进行排序。
值得一提的是,unordered_map 容器在<unordered_map>
头文件中,并位于std
命名空间中。因此,如果想使用该容器,代码中应包含如下语句:
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
| #include <unordered_map> using namespace std;
int main() { unordered_map<int, int> umap;
umap[6] = 77; umap.emplace(3, 5);
cout << "umap size = " << umap.size() << endl; for (auto iter = umap.begin(); iter != umap.end(); ++iter) { cout << iter->first << " " << iter->second << endl; } for (auto &&it : umap) { cout << it.first << " " << it.second << endl; } for (const auto &[fir, sec] : umap) { cout << fir << " " << sec << endl; } return 0; }
|
栈
很简单,记住是先入后出的结构。操作时压入一个新成员,返回栈顶成员,或弹出栈顶成员。
基本用法
push()
: 向栈内压入一个成员;
pop()
: 从栈顶弹出一个成员;
empty()
: 如果栈为空返回true,否则返回false;
top()
: 返回栈顶,但不删除成员;
size()
: 返回栈内元素的大小;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <iostream> #include <stack> using namespace std;
int main() { stack<int> stk; for (int i = 0; i < 50; i++) { stk.push(i); } cout << "栈的大小:" << stk.size() << endl; while (!stk.empty()) { cout << stk.top() << endl; stk.pop(); } cout << "栈的大小:" << stk.size() << endl; return 0; }
|