avatar
文章
73
标签
209
分类
30
首页
简历
技术文章
时间图
分类
标签
关于
高晓庄 札记
首页
简历
技术文章
时间图
分类
标签
关于

高晓庄 札记

二叉树与二叉搜索树:递归遍历三板斧
发表于2026-01-15|基础
线性结构(数组、链表)的局限在于:它们只有”一维”的先后关系。 但很多现实问题天然是”层次”的——目录结构、组织架构、表达式、决策过程。这时候就需要树。 而二叉树,是所有树结构里最基础、也最重要的一种。 什么是二叉树二叉树:每个节点最多有两个子节点(左子节点和右子节点)。 几个必须记住的术语: 根节点:最顶层的节点 叶子节点:没有子节点的节点 深度:从根到该节点的边数 高度:从该节点到最远叶子的边数 递归遍历三板斧处理树的几乎所有问题,都离不开遍历。二叉树有三种经典的深度优先遍历,区别只在于访问根节点的时机: 1234567891011121314151617181920212223// 前序遍历:根 → 左 → 右void preorder(TreeNode node) { if (node == null) return; visit(node); // 先访问根 preorder(node.left); preorder(node.right);}// 中序遍历:左 → 根 → 右void inorder(T...
哈希表:为什么它能做到 O(1)
发表于2026-01-13|基础
哈希表(Hash Table)可能是日常写代码里用得最多的数据结构:Java 的 HashMap、Go 的 map、Python 的 dict,本质上都是它。 它的核心卖点是:增删查平均都是 O(1)。 但”为什么是 O(1)”,恰恰是最多人答不清楚的地方。今天把它彻底搞懂。 哈希表的本质:数组 + 哈希函数哈希表底层是一块数组。数组按下标访问是 O(1),这是它快的根本原因。 问题在于:现实中的 key 通常不是整数下标(比如”用户 ID 是字符串”),怎么把一个任意的 key 映射成数组下标? 答案是哈希函数: 1hash(key) → 数组下标 理想情况下,不同的 key 映射到不同的下标,那增删查就都是 O(1)。 但理想情况几乎不可能——因为 key 的取值空间通常远大于数组的大小,所以必然出现哈希冲突:两个不同的 key,算出了同一个下标。 冲突怎么解决解决哈希冲突有两种主流思路: 1. 链地址法(拉链法)同一个下标上挂一条链表,冲突的 key 都放在这条链表里。 查找时:先算哈希找到下标,再在链表里逐个比对 key。 Java 的 HashMap 用的就是这种方法...
数组、链表、栈、队列:最基础也最容易被问倒
发表于2026-01-11|基础
很多人在面试里栽跟头,不是栽在什么高深的算法上,而是栽在最基础的线性结构上。 比如被问一句”数组和链表的区别是什么”,能说出”数组连续、链表不连续”的人很多,但能讲清楚”为什么数组按下标访问是 O(1)、链表在中间插入是 O(1)”的人,就少多了。 这篇文章把这四种最基础的线性结构,从底层特性到复杂度一次讲透。 数组:连续内存,随机访问数组的本质是一块连续的内存。 正因为连续,所以当你知道首地址和元素下标时,可以直接算出目标元素的地址: 1目标地址 = 首地址 + 下标 × 元素大小 这个计算是常量时间的,所以数组按下标访问是 O(1),这就是”随机访问”。 但也正因为连续,数组有两个代价: 插入和删除要搬移数据:在中间插入一个元素,后面的元素都要往后挪一位,平均 O(n) 扩容成本高:数组创建时要指定大小,满了就得申请更大的新数组、整体拷贝 数组的适用场景:读多写少、大小相对固定。 链表:离散内存,靠指针连接链表的本质是每个节点存数据和下一个节点的指针,节点之间靠指针串联,不需要连续内存。 优点:插入删除快(只需改指针,O(1)),天然支持动态扩容 缺点:不能随机访问,...
策略模式与观察者模式:从 if-else 地狱里爬出来
发表于2026-01-09|基础
如果说创建型模式解决的是”怎么 new 对象”,那行为型模式解决的就是”对象之间怎么协作”。 策略模式和观察者模式,是行为型模式里最常用、也最能立刻改善你代码质量的两个。 策略模式:消灭 if-else 地狱先看一段真实的坏代码。假设你在写电商的优惠券系统,有满减、折扣、立减三种优惠: 1234567891011public double calcPrice(String type, double price) { if ("fullReduction".equals(type)) { return price - 100; } else if ("discount".equals(type)) { return price * 0.8; } else if ("directReduction".equals(type)) { return price - 30; } else ...
从单体架构迁移到微服务,我是怎么设计的
发表于2026-01-08|ArchitectureMicroservices
从单体架构迁移到微服务,我是怎么设计的 架构演进从来不是”重写”,而是一场有节奏、可回滚、能持续交付的工程。本文复盘我在一个传统单体系统上做微服务化改造的完整设计思路。 为什么不直接重写接手时,系统是一个运行多年的单体应用,业务逻辑高度耦合,编译一次要十几分钟,任何小改动都要整体发版。团队第一反应是”推倒重写”。 但重写意味着:在很长一段时间内没有新功能产出,且新旧系统切换期的数据一致性几乎无法保证。最终我们选择了绞杀者模式(Strangler Fig Pattern)——在保留老系统运转的前提下,逐步把能力”绞杀”出来。 拆分原则:先按业务域,再按变更频率拆分粒度是最容易踩坑的地方。拆太细,分布式事务和运维成本爆炸;拆太粗,等于没拆。 我们的经验是两轮拆分: 第一轮按业务域:把系统切成若干个自治的领域边界(用户、订单、设备、GIS 等),每个域对应一个团队、一个独立的交付单元。 第二轮按变更频率:把”频繁变更”和”稳定不变”的模块再次分离,让高频模块能独立发布,不用拖着稳定模块一起回归。 判断边界是否合理的标准很简单:这个服务能不能独立演进、独立部署、独立扩容? 如果三个...
工厂方法与抽象工厂:别再混为一谈
发表于2026-01-07|基础
面试里经常出现这样的对话: “讲讲工厂模式。”“工厂模式有简单工厂、工厂方法、抽象工厂……” 然后就开始背定义。但背完往往自己也是糊的,因为这三个名字实在太像了。 其实它们的演进逻辑非常清晰,理清了就永远忘不掉。 起点:到处 new 的坏味道假设你在做一个支付系统,支持微信和支付宝两种支付方式。最初你可能会这么写: 12345if ("wechat".equals(type)) { return new WeChatPay();} else if ("alipay".equals(type)) { return new AliPay();} 问题来了:如果以后要加”银联支付”、”苹果支付”,这段 if-else 就得一直改,而且这样的判断散落在代码各处,改一处漏一处。 创建对象的逻辑,不应该和业务逻辑混在一起。这就是工厂模式要解决的问题。 第一站:简单工厂把创建逻辑抽到一个”工厂”里: 123456789public class PayFactory { public...
单例模式:饿汉、懒汉、双重检查锁,到底怎么选
发表于2026-01-05|基础
单例模式大概是每个学 Java 的人第一个接触的设计模式,也是面试里被问烂、但很多人其实没真懂的一个。 它的目标很简单:保证一个类在整个系统中只有一个实例,并提供一个全局访问点。 为什么需要单例?典型场景:配置管理、线程池、数据库连接池、日志器、Spring 容器里的 Bean(默认就是单例)。这些对象如果重复创建,要么浪费资源,要么状态不一致。 难的不是”理解目标”,是在并发下正确、安全地实现它。 写法一:饿汉式123456789public class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; }} 类加载的时候就创建实例,所以叫”饿汉”——不管用不用,先造出来。 优点:简单,线程安全(由 JVM 类加载机制保证) 缺点...
设计模式入门:为什么需要它,以及三大分类
发表于2026-01-03|基础
刚学设计模式的人,最容易犯一个错:把它当成”要背下来的 23 个名词”,然后拿着锤子到处找钉子。 这完全跑偏了。 设计模式的价值,从来不在”记住”,而在理解它为什么出现。 设计模式到底解决什么问题写代码久了你会发现,很多问题会反复出现: 怎么保证一个类只有一个实例? 怎么在运行时切换不同的算法? 怎么让两个模块解耦、互不直接依赖? 怎么在不改老代码的前提下扩展新功能? 这些问题被无数工程师踩过、想过、总结过,最后沉淀成了一套”常见问题的常见解法”——这就是设计模式。 它本质上是一套经验的复用。你不需要自己重新发明轮子,前人已经替你想好了。 把设计模式当”通用语言”我真正体会到设计模式的价值,是在团队协作里。 假设你在代码评审时看到这样一段话: “这里建议用策略模式把这块 if-else 拆掉。” 如果你们团队都懂策略模式,这句话一句话就说清楚了,不用解释一大堆背景。 但如果没人懂,你就得说:”你看这里,我们有三种计费方式,现在是 if-else 判断,以后可能还会加第四种、第五种,而且每个分支的逻辑还很长……” 设计模式是工程师之间沟通问题的通用词汇表。它让”复杂的设计意...
1…8910
avatar
高晓庄
Java / Go / Python
AI / RAG / Agent
Cloud Native / Kubernetes
文章
73
标签
209
分类
30
Follow Me
最新文章
腾讯 Hy4 首发速评:770B 跑分该怎么读2026-11-04
善待自己是一剂不保证有效的药方 — 听程乐松讲2026-09-10
听《十字路口》刘震云那一期,我突然不焦虑了——一个普通人的几个共鸣2026-09-08
关于"内卷"的经济学解释——读《人月神话》和薛兆丰之后2026-09-05
不确定性是人生唯一确定的事——我不再假装掌控一切2026-09-01
分类
  • AI31
    • Agent2
    • Architecture1
    • CV1
    • Dify1
    • LLM2
    • RAG1
  • Architecture3
标签
n8n Claude Code DFS Copilot 王阳明 HashMap 注意力机制 单元测试 多线程 QLoRA MetaGPT 工程化 开发范式 TDD 人生 开篇 Prompt 架构 Function Calling 工程 智能问数 Gemini 中年 MySQL Docker BabyAGI AI工作流 向量数据库 代码审查 Tool Use 函数式编程 Flannel 检索增强 网络排障 记忆 自动化 递归 云原生 单例模式 Self-RAG
归档
  • 2026-11 1
  • 2026-09 4
  • 2026-08 16
  • 2026-07 10
  • 2026-06 7
  • 2026-05 4
  • 2026-04 5
  • 2026-03 2
网站信息
文章数目 :
73
本站总字数 :
88.5k
本站访客数 :
本站总浏览量 :
最后更新时间 :
© 2025 - 2026 By 高晓庄