Linux提供了很多高级的I/O函数,在特定条件下表现出优秀的性能,大致分为三类:
用于创建文件描述符的函数:pipe、dup/dup2
读写数据的函数:readv/writev、sendfile等
用于控制I/O行为和属性的函数:fcntl
pipe函数pipe函数可以用于创建一个管道,以实现进程间通信。
12#include<unistd.h>int pipe(int fd[2]);
参数是一个包含两个int型整数的数组指针,成功时返回0,并将一对打开的文件描述符填入其参数指向的数组,如果失败返回-1并设置errno
通过pipe函数创建的两个文件描述符fd[0]和fd[1]分别构成管道两端,并且f[0]只能用于读出数据,f[1]只能用于写数据
dup和dup2dup函数创建一个新的文件描述符,该新文件描述符和原有文件描述符file_descriptor 指向相同的文件、管道或者网络连接。并且 dup返回的文件描述符总是取系统当前可用的最小整数值。dup2和 dup类似,不过它将返回第一个不小于file_descriptor_two的整数值。dup和dup2系统调用 ...
经典书籍学习
未读
这章节好像没什么特别的
经典算法
未读算法快速排序采用的是分治思想,即在一个无序的序列中选取一个任意的基准元素pivot,利用pivot将待排序的序列分成两部分,前面部分元素均小于或等于基准元素,后面部分均大于或等于基准元素,然后采用递归的方法分别对前后两部分重复上述操作,直到将无序序列排列成有序序列。
流程:
首先设定一个分界值,通过该分界值将数组分成左右两部分。
将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
实现123456789101112131415161718192021222324252627282930313233343536373839404142434445464 ...
经典书籍学习
未读到目前为止,我们编写的程序所使用的对象都有着严格定义的生存期:
全局对象在程序启动时分配,在程序结束时销毁
局部自动对象,在我们进入其定义的程序块时才被创建,在离开块时被销毁
局部static对象在第一次使用前分配,在程序结束时才销毁
除了auto和static对象外,C++还支持动态分配对象,动态分配的对象生存期不受他们创建时所在的作用域限制,只有被显式释放时才会被销毁。
除了静态内存和栈内存,每个程序还拥有一个内存池,被称为堆,程序用堆来存储动态分配的对象。
动态内存和智能指针在C++中,动态内存的管理是通过一对运算符来完成的:
new 在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化
delete 接收一个动态对象的指针,销毁该对象,并释放与之关联的内存
为了更容易地使用动态内存,C++11提供了两种智能指针来管理动态对象:
shared_ptr 允许多个指针指向同一个对象
unique_ptr 独占所指向的对象
还有一个weak_ptr,指向shared_ptr所管理的对象
具体介绍移步:CPP11特性之资源管理指针
动态数组new ...
经典书籍学习
未读从C++11开始,模板可以接收一组数量可变的参数。
变参模板可以将模板参数定义成能够接收任意多个模板参数的情况,这一类模板被称为变参模板
变参模板实例比如,可以通过调用下面代码中的 print()函数来打印一组数量和类型都不确定的参数:
12345678#include <iostream> void print () {} template<typename T, typename… Types> void print (T firstArg, Types… args) { std::cout << firstArg << ’\n’; //print first argument print(args…); // call print() for remaining arguments }
如果传入的参数是一个或者多个,就会调用这个函数模板,这里通过将第一个参数单独声明,就可以先打印第一个参数,然后再递归的调用print()来打印剩余的参数。这些被称为args的剩余参数,是一个函 ...
题目给你一个字符串数组 words ,找出并返回 length(words[i]) * length(words[j]) 的最大值,并且这两个单词不含有公共字母。如果不存在这样的两个单词,返回 0 。
示例 1:
123输入:words = ["abcw","baz","foo","bar","xtfn","abcdef"]输出:16 解释:这两个单词为 "abcw", "xtfn"。
示例 2:
123输入:words = ["a","ab","abc","d","cd","bcd","abcd"]输出:4 解释:这两个单词为 "ab", "cd"。
示例 3:
123输入:words = ["a","aa", ...
本章节主要从三个方面讨论Linux网络API:
socket地址API。socket最开始的含义是一个IP地址和端口对(ip,port)。它唯一地表示了使用TCP通信的一端。本书称其为socket地址。
socket基础API。socket的主要API都定义在sys/socket.h头文件中,包括创建socket、命名socket、监听socket、接受连接、发起连接、读写数据、获取地址信息、检测带外标记,以及读取和设置socket选项。
网络信息API。Linux提供了一套网络信息API,以实现主机名和IP地址之间的转换,以及服务名称和端口号之间的转换。这些API都定义在netdb.h头文件中,我们将讨论其中几个主要的函数。
socket地址API主机字节序和网络字节序现在CPU一次都能装载4字节(至少),那么这四个字节排列顺序将影响他被累加器装载成的整数值。
字节序分为大端字节序和小端字节序,大端序指的是一个整数的高位字节在内存的低地址处,低位字节在高地址处,小端序则相反。现代PC都用小端序,所以小端序又称主机字节序,与此同时发送端总是将发送端数据转化为大端字节序再发送,因此大 ...
经典书籍学习
未读
关联容器和顺序容器有着根本的不同,关联容器的元素是按照关键字来访问的,顺序容器的元素是按照他们在容器中的位置来顺序保存和访问的
关联容器支持高效的关键字查找和访问,两个主要的关联容器是map和set
使用关联容器提取map当从 map 中提取一个元素时,会得到一个 pair 类型的对象。简单来说, pair 是一个模板类型,保存两个名为 first 和 second 的(public)数据成员。 map 所使用的 pair 用数据成员 first 保存关键字,用 second 成员保存对应的值。
使用关键字类型的比较函数用来组织一个容器中元素的操作的类型也是该容器类型的一部分。为了指定使用自定义的操作,必须在定义关联容器类型时,提供此操作的类型。 如前所述,用尖括号指出要定义哪种类型的容器,自定义的操作类型必须在尖括号中紧跟着元素类型给出。
在尖括号中出现的每个类型,就仅仅是一个类型而已。当创建一个容器(对象)时,才会以构造函数参数的形式提供真正的比较操作(比较操作需要的类型,必须与在尖括号中指定的类型相吻合)。
例如,我们不能直接定义一个Sales_data的 multiset ...
题目DNA序列 由一系列核苷酸组成,缩写为 'A', 'C', 'G' 和 'T'.。
例如,"ACGAATTCCG" 是一个 DNA序列 。
在研究 DNA 时,识别 DNA 中的重复序列非常有用。
给定一个表示 DNA序列 的字符串 s ,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。
示例 1:
12输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT"输出:["AAAAACCCCC","CCCCCAAAAA"]
示例 2:
12输入:s = "AAAAAAAAAAAAA"输出:["AAAAAAAAAA"]
提示:
0 <= s.length <= 105
s[i]``==``'A'、'C'、'G' or 'T'
解答哈希直接可以 ...
经典算法
未读算法堆排序是比较基础的排序算法,它的流程比较多,理解起来不会像冒泡排序和选择排序那样直观。
二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)
二叉堆是一棵被完全填满的二叉树,有例外的可能是底层元素,底层元素从左到右填入,这样的树被称为完全二叉树。
仔细观察可以发现,其实一个数组可以被表示成一个二叉树:
观察上图可以发现,任意一位置i上元素,其左儿子为2i+1上,右儿子在2i+2上。
我们现在的需求是对数组元素进行从小到大排序,那么我们需要根据既定的数据构建堆,这也是堆排序必要的一步。在构建堆的时候,我们需要满足堆序性质。
堆序性质:任意一个节点小于(大于)它的后裔,这取决于你测排序方式。
这里以从小到大排序为例。我们可以建立一个大根堆,每一轮构建完成后,取出根节点(即最大节点)放在最后,所以最小节点在根上,然后重新构建大根堆。
堆排序主要分三步:
构建堆
调整堆
堆排序
每次排序结束,将根节点取出,放在最后,即每一轮可以将一个当前最大值排在正确的位置上
举一个例子:
此时9和4交换,然后4为 ...