递归遍历回顾

1 | public void dfs(treenode root){ |
利用栈模拟递归过程
先中序
1 | class Solution { |
后序
- 后序遍历需要用到一个记录状态的指针memo
- 如果memo指针指向右子树说明右子树处理完了直接返回,栈弹出
1 | public List<Integer> postorderTraversal(TreeNode root) { |

1 | public void dfs(treenode root){ |
1 | class Solution { |
1 | public List<Integer> postorderTraversal(TreeNode root) { |
[TOC]

在软件开发的世界里,Library(库)和 Framework(框架)是两个高频词汇,它们都旨在提升开发效率、促进代码复用。然而,尽管两者常被同时提及,其本质和在开发流程中的角色却大相径庭。理解它们的区别,对于开发者选择合适的工具、构建健壮的应用程序至关重要。
一个经典的概括,也是理解两者核心差异的关键:“你调用库的功能,而框架则调用你的代码。” 这句话精辟地指明了两者的控制流方向。
定义与目的:
Library,顾名思义,是一系列预先编写好的函数、类或模块的集合。它的主要目的是代码复用,让开发者无需从零开始实现某些通用或特定领域的功能。例如,一个数学库可能包含了各种复杂的数学运算函数(如计算三角函数、矩阵运算),一个图像处理库则提供了图片编辑、滤镜等功能。
控制权:
在使用 Library 时,控制权始终在开发者手中。你决定何时、何地、如何调用库中的功能。库更像是一个工具箱,里面装满了各种专业的工具,你需要用到哪个,就取出哪个来使用。你编写自己的主程序逻辑,然后在需要特定功能时,主动调用库中相应的方法。
特点:
定义与目的:
与 Library 不同,Framework 更像是一个应用程序的骨架或蓝图。它已经预设了程序的整体结构、控制流程和设计模式。框架定义了一套应用程序的构建规范和生命周期,并在其中留下了许多“空白区域”(即扩展点或回调函数),等待开发者用自己的代码去填充和实现。
控制权:
在 Framework 中,控制权从开发者转向了框架。当你使用一个框架时,你不再是主导者。框架掌握了应用程序的整体控制流,并在其预设的生命周期或事件发生时,回调你所实现的功能。例如,Web 开发中常见的框架(如 Spring、Django、React、Angular)都提供了一个完整的应用结构,包括路由、数据绑定、请求处理等机制。开发者无需从头设计这些底层架构,只需遵循框架的约定,将业务逻辑代码写入框架预留的位置。当应用程序运行时,是框架在主导整个流程,并在适当的时候调用你的代码(如处理某个HTTP请求、渲染某个组件)。
特点:
Library 和 Framework 最根本的区别在于“控制反转”(Inversion of Control, IoC)。
IoC 的好处在于,开发者可以将精力集中在业务逻辑的实现上,而无需关心底层架构、线程管理、生命周期管理等复杂问题,这些都由框架统一处理。这大大降低了开发的复杂度,并促进了代码的标准化和可维护性。
我们可以将 Library 比作一个专业的工具箱,里面有螺丝刀、扳手、锤子等各种工具,你需要用时就拿出来用。而 Framework 更像是一个已经搭建好主体的毛坯房,它决定了房间的布局、水电线路等基础结构,你只需要在其中添置家具、装修墙面(即填充你的业务代码)。
两者并非互斥,而是相辅相成。一个典型的开发流程通常是:开发者首先选择一个合适的 Framework 作为应用程序的骨架,然后根据业务需求,在 Framework 的结构内,通过调用各种 Library 来实现具体的功能。例如,在一个 Web 框架中,你可能会使用一个日期处理库、一个加密库或一个图表库来完成特定的数据操作和展示。
无论是 Library 还是 Framework,它们都通过 API (Application Programming Interface) 来向外部提供功能接口。API 是开发者与它们进行交互的“连接器”或“合同”,定义了如何调用它们的功能。
综上所述,Library 和 Framework 在软件开发中扮演着不同的角色。Library 提供的是可复用的功能集合,开发者拥有完全的控制权;而 Framework 则提供了一个完整的应用结构和控制流,开发者需按照其规范填充业务逻辑,控制权则由框架掌握(即控制反转)。
理解这一核心区别,不仅能帮助开发者更好地选择和使用工具,更能深入理解现代软件架构设计的思想,从而构建出更高效、更易维护的应用程序。
好的,我们来深入探讨 Framework 如何通过“钩子”设计模式来实现其“调用你的代码”这一核心机制。
在前面关于 Framework 的讨论中,我们强调了其核心特征是“控制反转”(IoC),即“框架调用你的代码”。那么,Framework 是如何做到这一点的呢?答案在于它广泛应用了各种**“钩子”(Hook)设计模式**。
在软件设计中,“钩子”可以理解为:
“钩子”本身并非一个单一的设计模式,而是一类思想或机制的统称,它可以通过多种具体的设计模式来实现,例如:
Framework 的设计者预见到了应用的通用流程和可能的定制点。他们将这些定制点设计成“钩子”,并规定了这些钩子的调用时机和参数。
形象比喻:
如果说 Framework 是一个已经设计好线路和插座的房子,那么“钩子”就是那些预留好的插座。你只需要把你的电器(你的代码)插上去,当房子里的电源系统(框架的控制流)运行时,你的电器就会被供电并工作。你不需要去改动房子的线路,只需要利用好它提供的插座。
before_request (请求前处理), after_request (请求后处理), init (应用初始化), destroy (应用销毁) 等。created, mounted, updated, componentDidMount, useEffect 等,允许开发者在组件的不同生命阶段执行代码。onClick (按钮点击), onDraw (绘制界面), onKeyPress (键盘事件) 等,当用户进行交互时,框架回调开发者定义的处理函数。before_save (保存前验证), after_delete (删除后清理) 等,在数据库操作前后执行特定逻辑。简而言之,“钩子”设计模式是 Framework 实现“控制反转”的基石和具体手段。 它使得 Framework 能够像一个精密的指挥家,在应用程序的生命周期中,在适当的时机,精准地调用开发者所提供的定制化代码,从而构建出强大而灵活的应用程序。
1 | graph LR |
zap快速启动
1 | var logger *zap.Logger |
通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.Example()创建一个Logger。
上面的每一个函数都将创建一个logger。唯一的区别在于它将记录的信息不同。例如production logger默认记录调用函数信息、日期和时间等。
通过Logger调用Info/Error等。
默认情况下日志都会打印到应用程序的console界面。
1 | package main |
在上面的代码中,我们首先创建了一个Logger,然后使用Info/ Error等Logger方法记录消息。
日志记录器方法的语法是这样的:
1 | func (log *Logger) MethodXXX(msg string, fields ...Field) |
其中MethodXXX是一个可变参数函数,可以是Info / Error/ Debug / Panic等。每个方法都接受一个消息字符串和任意数量的zapcore.Field场参数。
每个zapcore.Field其实就是一组键值对参数。
我们执行上面的代码会得到如下输出结果:
1 | {"level":"error","ts":1573180648.858149,"caller":"ce2/main.go:25","msg":"Error fetching url..","url":"www.5lmh.com","error":"Get www.5lmh.com: unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\te:/goproject/src/github.com/student/log/ce2/main.go:25\nmain.main\n\te:/goproject/src/github.com/student/log/ce2/main.go:14\nruntime.main\n\tE:/go/src/runtime/proc.go:200"} |
1 | var logger *zap.Logger |
1 | package main |
本文将详细指导您如何从零开始,使用 Hexo 框架和 GitHub Pages 搭建一个个人独立博客。请按照步骤操作,勿跳过任何环节。
以管理员身份运行命令提示符 (CMD) 或 Git Bash,依次输入以下命令并检查版本信息:
1 | node -v |
打开命令提示符 (CMD) 或 Git Bash,执行以下命令全局安装 Hexo 命令行工具:
1 | npm install -g hexo-cli |
GitHub Pages 将用于托管您的博客静态页面。
your_github_username.github.io (例如:octocat.github.io)。SSH Keys 用于本地 Git 和 GitHub 之间的安全通信。
在任意文件夹内右键,选择 Git Bash Here,输入以下命令生成 SSH Key:
1 | ssh-keygen -t rsa -C "your_email@example.com" |
过程中会提示输入密码,直接按 4 次 Enter 键跳过即可(不设置密码)。
找到生成的公钥:
默认路径在 C:\Users\YourUsername\.ssh\,找到 id_rsa.pub 文件。
用记事本或其他文本编辑器打开 id_rsa.pub,复制其中所有内容。
将公钥添加到 GitHub:
登录 GitHub,点击右上角用户头像 -> Settings (设置)。
在左侧导航栏找到 SSH and GPG keys。
点击 New SSH key (新建 SSH Key)。
Title (标题) 随意填写,将复制的公钥内容粘贴到 Key (密钥) 文本框中。
点击 Add SSH key (添加 SSH Key)。
测试 SSH 连接:
在 Git Bash 中输入:
1 | ssh -T git@github.com |
首次连接会提示确认,输入 yes 并回车。如果看到 “Hi your_username! You’ve successfully authenticated…” 的信息,则表示配置成功。
在您喜欢的位置新建一个文件夹,例如 MyBlog (或 Blog),进入该文件夹。
在该文件夹内右键,选择 Git Bash Here,执行以下命令初始化 Hexo 博客:
1 | hexo init |
注意:如果遇到
hexo命令未找到的错误,尝试在命令前加上npx,例如npx hexo init。
安装 Hexo 依赖:
1 | npm install |
生成并启动本地服务器:
依次执行以下命令:
1 | hexo generate # 简写为 hexo g |
提示:如果
hexo s启动失败,可以尝试重复执行,有时是网络连接不稳定导致。
在浏览器中打开提示的链接 (通常是 http://localhost:4000),您应该能看到默认的 Hexo 博客页面。
回到 Git Bash 窗口,按 Ctrl + C 关闭本地服务器。
在您的博客根目录 (即 MyBlog 文件夹) 下打开 Git Bash,执行:
1 | npm install hexo-deployer-git --save |
配置 _config.yml 文件:
在您的博客根目录 (MyBlog 文件夹) 下,用文本编辑器 (如记事本、VS Code) 打开 _config.yml 文件。
滚动到文件最底部,找到 deploy: 部分。如果存在,删除其下的所有内容。
将以下配置粘贴到 deploy: 下方,并注意缩进:
1 | deploy: |
重要:
- 确保
type、repository、branch前面各有 两个空格。- 每个冒号
:后面都有一个空格。
获取仓库 HTTPS URL:
回到您的 GitHub 仓库页面 (your_github_username.github.io)。
点击绿色的 Code 按钮,选择 HTTPS 选项卡,然后复制显示的 URL (例如:https://github.com/your_username/your_username.github.io.git)。
粘贴 URL 并保存:
将复制的 HTTPS URL 粘贴到 _config.yml 文件中 repository: 后面的位置。
保存 _config.yml 文件。
生成并部署博客:
在博客根目录的 Git Bash 中,依次执行以下命令:
1 | hexo generate # 生成静态文件 |
注意:首次部署可能需要您输入 GitHub 用户名和密码。
如果您使用代理工具 (如 Clash Verge),且遇到 hexo d 部署失败,可能需要为 Git 配置代理。假设您的代理端口为 7897:
清除现有代理设置 (可选,避免冲突):
1 | git config --global --unset http.proxy |
设置 HTTP/HTTPS 代理:
1 | git config --global http.proxy http://127.0.0.1:7897 |
验证代理设置:
1 | git config --global --get http.proxy |
配置完成后,再次尝试 hexo deploy。
如果您是首次在当前设备上使用 Git,需要配置您的全局用户信息:
1 | git config --global user.email "your_email@example.com" |
配置完成后,再次执行 hexo deploy。
部署成功后,您的博客即可通过 https://your_github_username.github.io 访问。
打开博客根目录下的 _config.yml 文件,找到 Site 部分,根据您的需求修改以下内容:
1 | # Site |
保存文件后,重新执行 hexo generate 和 hexo deploy 使更改生效。
创建新文章:
在博客根目录的 Git Bash 中,执行以下命令创建新的 Markdown (.md) 文章文件:
1 | hexo new "您的文章标题" |
新文章文件将生成在 source/_posts/ 目录下。
编辑文章:
您可以使用任何 Markdown 编辑器打开 .md 文件进行编辑。推荐使用 Typora (请支持正版)。
生成并部署:
文章编辑完成后,保存文件,然后在 Git Bash 中执行:
1 | hexo generate |
您的新文章将发布到博客中。
Butterfly、Anzhiyu)。安装和配置主题通常有详细的文档。至此,您的个人独立博客已基本搭建完成!
太棒了!这是一个非常实用的 AutoHotkey 脚本,能极大地提升键盘操作效率。以下是为你准备的博客推文内容,包含了博客文章和推文版本:
你是否也曾因为频繁地从主键盘区(Home Row)移动手掌去触碰方向键、Home、End 等导航键而感到不便?尤其是在长时间编码、写作或浏览文档时,这种重复性的手部移动不仅降低效率,还可能增加手部疲劳甚至重复性劳损 (RSI) 的风险。
好消息是,有了 AutoHotkey,我们可以彻底改变这种低效的习惯!今天,我将分享一个巧妙的脚本,它能将你几乎不用的 CapsLock 键变成一个功能强大的导航中心,让你在不离开主键盘区的情况下,轻松实现光标的精准控制。
CapsLock 键在日常使用中,除了偶尔需要输入全大写字母外,其利用率极低。将其重新映射为修饰键,不仅不会影响现有工作流,反而能:
IJKL 的布局,非常符合人体工程学和许多 Vim/Emacs 用户的习惯。Shift 和 Ctrl 等修饰键,这意味着你可以轻松实现 Ctrl+Left (跳词)、Shift+End (选择到行尾) 等高级操作!下面是实现这一功能的 AutoHotkey 脚本。如果你还没有安装 AutoHotkey,可以在 AutoHotkey 官网 下载并安装。
脚本代码:
1 | ; 禁用 CapsLock 原功能 |
如何使用:
.ahk 文件(例如 CapsLockNav.ahk)。.ahk 文件放入 Windows 启动文件夹,让它开机自启动。现在,你可以尝试以下操作:
CapsLock + J: 光标向左移动CapsLock + L: 光标向右移动CapsLock + I: 光标向上移动CapsLock + K: 光标向下移动CapsLock + U: 光标移动到行首CapsLock + O: 光标移动到行尾CapsLock + H: 向上翻页CapsLock + N: 向下翻页更强大的组合:
Ctrl + CapsLock + J: 向左跳过一个单词 (相当于 Ctrl+Left)Shift + CapsLock + L: 向右选择一个字符 (相当于 Shift+Right)Ctrl + Shift + CapsLock + O: 从当前位置选择到行尾 (相当于 Ctrl+Shift+End)是不是非常方便?这种方式不仅能让你在编程时保持双手在键盘中心,也能在日常文档编辑、浏览网页时提供流畅无缝的体验。
一个小小的 AutoHotkey 脚本,就能将一个利用率不高的 CapsLock 键,变成你提升键盘效率的强大工具。告别频繁的手部移动,拥抱更舒适、更高效的打字体验吧!
如果你也尝试了这个脚本,欢迎在评论区分享你的使用感受!
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
1 | $ hexo new "My New Post" |
More info: Writing
1 | $ hexo server |
More info: Server
1 | $ hexo generate |
More info: Generating
1 | $ hexo deploy |
More info: Deployment