vim从入门到入土
首先声明我的vscode坚定拥护者身份,奈何十年老古董实在带不动,不得不重新捡起vim开始朴素(装逼)生活。 1. 什么是 Vim?Vim 是一个强大的文本编辑器,基于经典的 vi 编辑器。它的核心设计理念是高效编辑文本,特别适合程序员和技术用户 (高逼格用户)。 与大多数文本编辑器不同,Vim 的操作基于模式切换,它拥有多个操作模式,使你能够在插入、编辑、命令等操作之间快速切换。 Vim vs Vi:Vim 是 vi 的增强版,提供了更多的功能,如多级撤销、语法高亮、扩展的脚本支持等。 2. Vim 的主要模式Vim 的操作基于不同的模式,主要有以下几种模式:1.普通模式 (Normal Mode):12345678910默认进入的模式,用于导航和操作文本。进入方式:启动 Vim 后默认进入,或按 Esc 回到普通模式。常用命令:h:向左移动光标。j:向下移动光标。k:向上移动光标。l:向右移动光标。dd:删除当前行。yy:复制当前行。p:在光标之后粘贴。2.插入模式 (Insert Mode):123用于编辑文本,类似于普通文本编辑器的输入状态。进入方式:按 i 或 a 进入。退出 ...
nth_element函数深入
nth_element 是 C++ 标准模板库 (STL) 中的一个非常有用的算法,它的功能是对范围内的元素进行部分排序,使得第 n 小的元素排到指定位置,其前面的元素都小于等于它,后面的元素都大于等于它,但前后的元素不一定是完全排序的。 nth_element 算法基于快速排序,时间复杂度在平均情况下是 O(n),最坏情况是 O(n^2),但通过随机化选取枢轴可以避免最坏情况的频繁发生。 函数原型12345template<class RandomIt>void nth_element(RandomIt first, RandomIt nth, RandomIt last);template<class RandomIt, class Compare>void nth_element(RandomIt first, RandomIt nth, RandomIt last, Compare comp); first: 范围的起始迭代器。 nth: 指定要找到的第 n 小元素的迭代器。 last: 范围的结束迭代器(不包括 last 指向的元素)。 comp: ...
快排
快速排序(Quick Sort)的C++实现1. 算法简介快速排序是一种基于 分治法 的高效排序算法。通过选择一个“基准”(pivot),快速排序将序列分成两个子序列,分别递归地进行排序。在平均情况下,时间复杂度为 ( O(n \log n) ),且具有较小的常数因子,在实际中通常比其他排序算法更快。 2. 算法步骤 选择基准值(Pivot): 通常选择序列中的第一个元素或中间元素作为基准值。 分区(Partitioning): 将序列中的元素按照基准值划分成两部分:左侧部分小于基准值,右侧部分大于基准值。 递归调用: 对左侧和右侧的子序列分别进行快速排序。 结束条件: 当子序列的长度为1或0时,不再递归。 3. 代码实现标准的递归实现:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849#include <iostream>#include <vector>// 交换两个元素void swap(int& a, int& ...
数据结构的深度思考和总结
1.数据结构的本质数据结构的本质其实就是链表和数组,其他复杂的数据结构不过是这些基本结构的高级抽象。无论是树、栈、队列,还是更高级的图结构,归根结底都是基于数组或链表构建的。它们通过底层的实现细节和不同的逻辑组织方式,提供了更易用的API接口。 比如,树这种数据结构,既可以用数组来实现,也可以用链表构建。数组的优势在于可以通过索引快速访问,节省空间,而链表的优势则在于高效的插入和删除操作。但链表由于使用指针,会占用更多的空间。 我们可以从Redis的实现上看到这一点,它内部有字符串、集合等数据结构,每一种数据类型都有不同的实现方式。其实,我们自己也可以根据具体的业务场景,设计并实现出个性化的数据结构,并定义一些适合当前业务需求的API接口。 语言层面也为我们提供了丰富的数据结构工具。比如在Python中,除了常用的字典和列表外,还可以通过collections模块找到一些更灵活和高效的数据类型,如defaultdict、双端队列deque、计数器Counter等。Java的java.util包中也包含了大量用于扩展基础数据结构的工具类。 综上所述,数据结构的底层其实就是数组和链表。 ...
Transformer架构初步
从 RNN 爬到 Transformer 山顶第一次听到 Transformer 的时候,我脑子里闪过三个画面: 物理书里的“变压器” 变形金刚 导师嘴里那句:“现在大部分大模型都是这个架构……” 然后我去翻论文《Attention is All You Need》,翻开第一眼:公式一堆、结构图一堆,我当场关掉 PDF,默默记住一个结论: 这个东西以后肯定逃不过,但今天先不学。 直到后面真的要用到它,我才开始系统地啃。下面的内容可以看作是我这个初学者把 Transformer 从“听过名字”到“勉强理解”的过程整理。 一、先说结论:Transformer 到底干了件什么事?如果只能用一句话来概括 Transformer,我现在会这样说: 以前我们处理一句话,是按时间步从左到右递推;Transformer 改成了:整句一起看,通过自注意力让每个位置和所有位置建立联系。 更具体一点: RNN:依次处理 (x_1, x_2, \dots, x_T) 每一步依赖前一步的隐状态$(h_{t-1})$; Transformer:把整段序列表示成矩阵,一次性送进若干层自注意力和前馈网 ...
KMP
1. 算法简介KMP 算法用于 字符串匹配,通过预处理模式串,避免重复的字符比较,从而实现高效匹配。它的时间复杂度是 O(n + m),其中 n 是主串长度,m 是模式串长度。 2. 主要思想当模式串中的某个字符匹配失败时,利用已知的部分匹配结果,跳过不必要的比较。这是通过 部分匹配表(也称为 前缀表)实现的。 3. 术语解释 前缀:从字符串的第一个字符开始,不包含最后一个字符的子串。 后缀:从字符串的最后一个字符开始,不包含第一个字符的子串。 部分匹配表:记录每个字符位置前的部分字符串的最长相同前缀和后缀的长度。 4. 部分匹配表的构建部分匹配表记录模式串在匹配失败时,可以跳过的字符数量。假设模式串为 pattern,前缀表 prefix[i] 的值表示在 pattern[0...i] 中,最长相同前缀和后缀的长度。 构建步骤: 初始时,prefix[0] = 0,表示第一个字符没有前缀和后缀。 使用双指针法遍历模式串,一个指针指向当前字符,一个指向最长前缀的下一个字符。 若当前字符匹配,前缀长度加 1;否则,回退到前一个匹配的前缀位置。 5. KMP 主算法步骤 预处理模式串 ...
堆栈
C++ 堆栈笔记1. 什么是堆栈?堆栈(Stack)是一种基础的数据结构,遵循后进先出(LIFO, Last In First Out)原则,意味着最后插入堆栈的元素最先被弹出。堆栈的使用场景非常广泛,如处理递归、括号匹配、表达式求值、回溯算法等。它通常用于管理程序的运行状态。 2. 堆栈的特点与应用场景2.1 特点 线性数据结构:堆栈通过一个线性方式组织元素,只有栈顶(顶部)元素可以被访问。 操作受限:仅允许在栈的顶部进行插入(push)和删除(pop)操作,无法直接访问或修改栈中的其他元素。 动态增长:堆栈可以动态调整大小,尤其是在使用标准库的实现时(如 C++ 中的 std::stack)。 2.2 典型应用场景 递归调用管理:函数递归时,每次函数调用都会在堆栈中保存局部变量和返回地址,直到递归结束,再从堆栈中逐步恢复状态。 表达式求值:在表达式求值过程中,特别是中缀转后缀表达式和逆波兰表达式的计算,堆栈是核心工具。 括号匹配:用于检查表达式中括号是否配对,堆栈可以方便地追踪最近遇到的左括号,并在遇到右括号时进行匹配。 浏览器前进/后退操作:用户在浏览网页时,前进和后退操作是典 ...
顺序表(SQList)的理解与实现
1. 什么是顺序表(SQList) ß顺序表是一种常见的线性数据结构,其特点是通过一组连续的内存空间来存储数据元素。在顺序表中,每个元素都有一个直接的前驱和后继(除了第一个元素没有前驱,最后一个元素没有后继)。顺序表的操作主要包括插入、删除、查找等。 2. 顺序表的特点优点 访问速度快:由于元素在内存中是连续存储的,因此可以通过索引直接访问,时间复杂度为 O(1)。 易于实现:使用数组或容器如 std::vector 可以轻松实现顺序表。 缺点 插入和删除效率低:当在表中间插入或删除元素时,需要移动后续的所有元素,最坏情况下的时间复杂度为 O(n)。 空间预分配:需要提前知道表的最大容量,否则可能会导致内存不足。 3. 顺序表的实现123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263#include <iostream>#include <vector>class SQList ...
screen命令应用
screen 是一个非常强大的终端会话管理工具,它可以让你在多个终端窗口中运行任务,并在会话断开后继续保持任务的执行状态。特别适合长时间运行的任务或远程连接的任务管理。对于远程服务器player简直是屠龙宝刀。 常见用法:以下是一些常见的 screen 命令和用法: 1. 启动新的 screen 会话1screen 启动一个新的 screen 会话。在新窗口中,你可以运行任何命令。 默认情况下,screen 会自动分配一个会话 ID。 2. 启动带名称的 screen 会话1screen -S session_name 通过 -S 选项为会话指定名称 session_name,便于管理多个会话。 3. 分离(Detach)会话1Ctrl + A + D 使用快捷键 Ctrl + A + D,可以将当前会话暂时分离(detach),但命令仍会继续在后台执行。 4. 恢复(Reattach)已分离的会话1screen -r 恢复上一个分离的 screen 会话。 5. 查看现有 screen 会话1screen -ls 列出当前所有的 screen 会话,包括那些分离的会 ...
