在数学中,集合是最基本的概念之一。编程时,我们不可避免地会涉及到集合及其相关操作。在 C++ 中,标准模板库(STL)提供了 std::set/std::unordered_set 两种传统意义上的集合(除此之外,还有 std::multisetstd::unordered_multiset)。其中,std::set(和 std::multiset)定义在头文件 set 当中,从 C++98 起就有支持;而 std::unordered_set(和 std::unordered_multiset)则定义在头文件 unordered_set 当中,从 C++11 开始支持。

此篇我们讨论如何在 C++ 中进行集合的交集和并集操作。

阅读全文 »

这是一篇简短的记录。

某台服务器某账号的 crontab 任务被清空,原因不明。同时,该服务器上的 crontab 任务备份未开启。故思考如何恢复 crontab 任务。

经查,CentOS 系统的 crontab 任务的日志,打印在 /var/log/cron 之中。考虑过滤日志:

1
cat /var/log/cron* | grep CMD | awk -F'CMD' '{print $2}' | awk -F'[(|)]' '{print $2}' | sort -u

由此得到系统记录过的 crontab 执行命令,过滤其他账号的命令后即可追回目标账号的 crontab 任务。

此外,考虑备份 crontab;脚本如下:

backup_crontab.sh
1
2
3
4
5
6
7
8
9
#!/usr/bin/env bash

BACKUP_DIRECTORY="${HOME}/crontab_backup"

if [ ! -e "${BACKUP_DIRECTORY}" ]; then
mkdir -p ${BACKUP_DIRECTORY}
fi

crontab -l > ${BACKUP_DIRECTORY}/$(date '+%Y%m%d').txt

本文以 C++ 为示例语言,但实际其中思想适用范围远大于 C++ 这一编程语言的范畴。

我们知道,C++ 标准模板类库提供了一系列的容器。诸如 std::vector<ElementType> 的容器需要在声明时指定容器中所储存的元素的类型。例如,我们可以使用 std::vector<int> 声明一个包含整型数字的变长数组;而 std::vector<std::string> 则可以用来声明一个包含 std::string 的变长数组。

显而易见,由于容器在声明时就已指定了其包含的元素的类型,容器内只能包含相同类型的元素。这与面向对象编程(Object-Oriented Programming, OOP, 使用继承和运行时动态绑定的编程方式)的思想似乎是矛盾的。因为 OOP 使用继承和动态绑定,允许程序员将相关但有不同的类的共性部分抽象成基类而将这些不同的部分分别作为子类独有的成员;若是容器内只能包含相同类型的元素,我们就无法直接在一个容器中包含同一个基类不同派生类的对象了——而在实际应用中,这种场景是存在的。

前作中最后的示例(动物园的例子)中,我们通过保存基类指针(而不是对象本身)部分解决了这个问题。然而,在前例中,我们不可避免地还是需要使用 newdelete 来动态分配内存。此篇我们通过构建「代理类」来避免手工动态分配内存。

阅读全文 »

看似高大上的人工智能、机器学习,实际上都脱不开数学的支持。在这些数学内容中,最重要的无疑是两个部分:代数和概率论。我无法在博客中完整地介绍代数(特别是矩阵论)和概率论,但是将其中部分有趣又重要的内容提出来讲解,还是可行的。

此篇,我们谈谈矩阵的 SVD 分解。

阅读全文 »