string转char*
1 char *str = const_cast <char *>(str.c_str ());
深拷贝
浅拷贝就是一个对象拷贝另一个对象的内容以后,其中一个对象的改变还会影响另一个对象的内容。
编译器默认拷贝构造函数是浅拷贝,如果在类中分配了堆内存,可能导致内存的重复释放。
为了解决浅拷贝的问题,通常需要自己实现拷贝构造函数,变为深拷贝。
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 #include <iostream> using namespace std;class Person {public : Person (int age, int height){ this ->age = age; this ->height = new int (height); } Person (const Person& p){ this ->age = p.age; this ->height = new int (*p.height); } ~Person (){ cout<<"析构" <<endl; delete height; height = nullptr ; } int age; int * height; }; int main () { Person p1 (18 ,190 ) ; Person p2 (p1) ; cout<<p2. age<<" " <<*p2. height<<endl; return 0 ; }
linux常用命令
awk 参数 脚本 文件
1 awk '{print NR NF "\t" $0, $1 }'
wc -c 字符数 -l 行数 -w 单词数
sort
1 2 sort -r coin.txt 逆序 sort -n coin.txt 数值
partition函数
快排中的partition函数在algorithm库中有实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> #include <algorithm> using namespace std ; int main () { vector <int > v{19 ,8 ,7 ,3 ,5 ,1 ,0 }; int key = 6 ; auto t = partition(v.begin(), v.end(), [key](int a){ return a < key; }) - v.begin(); cout <<t<<endl ; for (auto x: v) cout <<x<<" " ; return 0 ; }
bind函数
参数绑定。通用的函数适配器。接受一个可调用对象,生成一个新的可调用对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> #include <algorithm> #include <functional> #include <queue> using namespace std ; using std ::placeholders::_1; using std ::placeholders::_2; bool cmp ( int a, int b) { return a > b; } int main () { vector <int > v{1 ,0 ,99 ,3 ,4 ,12 ,2 }; sort(v.begin(), v.end(), bind(cmp, _1, _2)); for (auto x: v) cout <<x<<" " ; cout <<endl ; return 0 ; }
lambda表达式
未命名的内联函数。一般来说应该减少捕获的数据量,避免捕获指针和引用。捕获列表和函数体是必不可少的。
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <iostream> #include <algorithm> #include <functional> #include <queue> using namespace std ; int main () { auto f = [](const int &a){ return a*a; }; cout <<f(5 )<<endl ; return 0 ; }
function函数
函数指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> #include <algorithm> #include <functional> #include <queue> using namespace std ; int f (int a) { return a*a; } int main () { function<int (int )> ff = f; cout <<ff(55 )<<endl ; return 0 ; }
tuple函数
优势在于传输一次性的一组数据,如果要大量使用,实际上不及结构体清晰明了。
可以将tuple用在map中作为多索引值。可以用来比较两个tuple类型的字典序大小。
tuple可以存引用
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 #include <iostream> #include <algorithm> #include <functional> #include <queue> #include <tuple> #include <map> #include <string> using namespace std ; int main () { std ::tuple<int , string , char > t (32 , "Penny" , 'A' ) ; cout <<get<0 >(t)<<endl ; get<1 >(t) = "Alex" ; tuple<int , string , char > t2; t2 = tuple<int , string , char >(24 , "Alex" , 'B' ); t2 = make_tuple(17 , "Jun" , 'C' ); string st = "In for a penny" ; tupel<string &> t3 (st) ; t3 = make_tuple(ref(st)); int x; string y; char z; make_tuple(ref(x), ref(y), ref(z)) = t2; tie(x, y, z) = t2; tie(x, std ::ignore, z) = t2; auto t4 = tuple_cat(t2, t3); cout <<tuple_size<decltype(t4)>::value<<endl ; tuple_element<1 , decltype(t4)>::type d; cout <<d<<endl ; tuple<int , int , int > time1, time2; if (time1 > time2) cout <<"time1 is a later time" <<endl ; map <tuple<int , char , float >, string > mp; mp[make_tuple(18 , 'A' , 3.14 )] = "Curiosity kills the cat" ; int a, b, c; tie(c, b, a) = make_tuple(a, b, c); return 0 ; }
一致性哈希
通过是为了解决传统哈希算法上的不足而提出来的。主要是增减机器是,传统哈希算法对于数据迁移的成本很高。一致性哈希也是使用取模的思想,只不过将哈希值空间组织成一个圆环,然后每个机器顺时针负责一段数据的存储,当增加机器或者减少机器时,把对应的数据迁移到附近的机器上就行,其他机器不用发生改动。但是存在一个不足,当机器数量比较少时,无法做到在环上均匀分布。于是引入虚拟节点,每个物理机器有相同数量的虚拟节点,通过虚拟节点去寻找位置,然后映射到物理机上。
海量数据问题
小根堆+归并
生成随机数
线性同余算法
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <iostream> using namespace std;int main () { long long a = 48271 , c = 0 , x = 1 ; long long m = INT_MAX; for (long long i = 0 ; i < 10 ; i++){ x = (a*x+c) % m; cout<<x<<endl; } return 0 ; }
什么是socket
socket是linux文件的一种类型。socket通过绑定IP和端口可以实现在进程间通信。创建一个socket文件描述符指向两个缓冲区,所以可以实现全双工通信。
epoll的优势
连接的文件描述符比较多,但是活跃的文件描述符比较少时,比select和poll效率更高。
epoll三个主要的函数:
epoll_create()
epoll_ctl()
epoll_wait()
ET和LT的区别
ET称为边沿触发,在调用epoll_wait函数监听的时候,如果有满足的事件,则该函数进行返回,返回值是满足监听事件的文件描述符数量。ET模式下,只会响应一次,即使部分文件描述符的事件没有进行处理。当发送接收缓冲区状态发生改变时,触发读写事件。边沿触发模式要求一直读写,直到读写完或者返回EAGAIN
LT称为水平触发,如果epoll_wait有满足条件的事件,会一直返回。增加了epoll_wait函数的调用次数。所以通常在并发服务器上,多使用ET模式。如果系统中有大量不需要读写的就绪文件描述符,而它每次都会返回,这样会大大降低检索自己关心的就绪文件描述符的效率。接收缓冲区不为空,有数据可读,读事件一直触发。发送缓冲区不为满,有数据可写,则写事件一直触发。
ET为什么要用非阻塞而不是阻塞
阻塞模式,程序在读取数据时无法知道什么时候读完,会一直阻塞在read函数上,即使已经读完了数据。
非阻塞模式,程序使用while循环读取数据,读完以后read会返回,errno被设置为EAGAIN。
五种网络IO模型
阻塞IO
非阻塞IO
IO多路复用
信号驱动IO
异步IO
前4个都是同步IO。IO多路复用也是阻塞的,但是没有阻塞在send和recv上,而是阻塞在select,poll和epoll上。
同步:进程在数据由内核空间复制回进程缓冲区时不能干别的事。
异步:在数据准备完成,由内核缓冲区拷贝到进程缓冲区后通知进程,在等待通知的这段事件里,进程可以干别的事情。