Linux 网络编程 | 多连接 TCP 文件传输程序
这篇博客介绍在 Linux 下使用 epoll 和 Socket API 编写一个使用多条 TCP 连接来传输文件的 C/S 模式程序。 程序框架对于这个程序,分为服务端和客户端。服务端负责发送文件,客户端负责接收文件。客户端首先向服务端请求文件元信息,如文件名、大小等,然后根据文件大小,同时建立多条的 TCP 连接进行分块下载,达到加速文件传输的目的。 完整的项目代码可以到 https://github.com/howardlau1999/tcp-file-transfer 获取。 Socket API 的使用对于服务端而言,其最主要的功能是监听端口,因此封装一个 liste...
循环神经网络小项目 | 七绝作诗
数据集做深度的第一步就是要收集炼丹原料准备数据集,这里我选择了 GitHub 上的这个项目 chinese-poetry 然后取其中的唐诗部分,并去除含有现在字库缺少的字的唐诗,将诗中一些注解删除(比如一字多解),再利用正则匹配提取出七绝唐诗,将每个汉字拆成单独的词,在唐诗开头和结尾添加 <SOP> 和 <EOP> 符号标志开始和结束,一共准备了 10922 首七绝唐诗作为训练数据。 数据集长这样: 12345<SOP> 中 管 五 弦 初 半 曲 , 遙 教 合 上 隔 簾 聽 。 一 聲 聲 向 天 頭 落 , 效 得 仙 人 夜 唱 經 。 &l...
Linux C/C++ 实现热更新
有时候在服务器程序中,需要不停止运行程序但是又要更新一些程序代码,这时候可以借助动态加载库来实现功能的热更新,不过不是在编译的时候链接动态链接库,而是在程序中手动控制加载和卸载。 动态链接库的手动使用很简单,主要有四个 API:dlopen() 用于打开 .so 文件,dlsym() 用于加载符号,dlclose() 用来卸载链接库以及 dlerror() 用来输出错误信息。 这里我简单写了一个主程序,通过输入函数名,获取动态链接库中的符号,然后调用函数: 123456789101112131415161718192021222324252627282930313233343536373...
LeetCode | 173 二叉搜索树迭代器
实现一个二叉搜索树迭代器。你将使用二叉搜索树的根节点初始化迭代器。 调用 next() 将返回二叉搜索树中的下一个最小的数。 注意: next() 和hasNext() 操作的时间复杂度是O(1),并使用 O(h) 内存,其中 h 是树的高度。 其实就是二叉树的中序遍历,手动模拟函数递归调用时候的出入栈即可。 12345678910111213141516171819202122232425262728class BSTIterator { stack<TreeNode*> s;public: BSTIterator(TreeNode *root) ...
平衡二叉树 | 红黑树
注:下面这个版本基于《算法(第四版)》实现。这个红黑树是简化版本的。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105enum Color { RED, BLACK };template <class ...
平衡二叉树 | AVL 树
四种不平衡的情况 参考代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113template <typename K, typename V>struct AVL...
C++11 字面量操作符
在 C++ 11 中,引入了字面量操作符(literal operator),使用的方法就像下面这样: 123456789long double operator "" _w(long double);std::string operator "" _w(const char16_t*, size_t);unsigned operator "" _w(const char*);int main() { 1.2_w; // calls operator "" _w(1.2L) u"...
C++ 模板元编程 | 快速排序
有了之前插入排序的基础,实现快速排序不是一件难事,快排的算法用 Haskell 描述就像是下面这样的: 12QuickSort [] = []QuickSort (x:xs) = QuickSort [a | a <- xs, a < x] ++ [x] ++ QuickSort [a | a <- xs, a >= x] 可以看出来,我们还需要补充的列表操作是 Concat,把两个表连接起来,还有 Filter,过滤一个表的元素,实现思路很简单: 123456789101112131415161718192021222324252627282930313233...
C++ 模板元编程 | 插入排序
实现快速排序:https://howardlau.me/programming/cpp-templates-metaprogramming-quick-sort.html 辅助模板类下面这些类利用了 C++ 的模板,实现了一些基本的逻辑功能: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include <iostream>// 布尔常量类型struct TrueType { co...
Python 导入时和运行时代码运行的时机
在 Python 中,import 语句会执行一个文件中的顶层代码,然后将各种函数定义体预先编译成字节码(Python 中字节码可以通过 dis 反编译模块看到)缓存起来,以后重新导入相同的模块就使用缓存,只做名称绑定。对于函数来说,Python 解释器会将 def 定义的函数体编译成字节码,并且将函数对象绑定到对应的全局名称上,但是这时候显然不会执行定义体,解释器只会在运行时调用函数的时候才会执行定义体。 但是对于类来说,导入的时候,解释器会执行类的定义体,类中嵌套的类定义体也会被执行。 下面通过代码来理解导入时和运行时的差别,建议先不要执行代码,先通过纸笔模拟一遍执行过程: 假设 e...