表的创建和基础的增删改查

创建表

  • 通过create table实现
1
2
3
4
create table 表名(
表中每列元素名+数据类型+(主键)+是否可以为空
--主键唯一,且主键内容不能重复
)

增加/插入

  • 通过insert into实现
    1
    2
    3
    insert into [表名(对应每列元素名)]
    value[(每行对应元素的实际值)]
    --insert()中的顺序要和表本身的顺序相同

删除

  • 通过delete from … where实现
1
2
3
delete from [表名]
where [要删除对象的查询列元素]
--绝对禁止无WHERE的DELETE(会清空全表)

##修改

  • 通过update…set…where实现
1
2
3
4
update 表名
set [修改后的内容(完整)]
where [修改对象的查询列元素]
--set后的修改内容中间用‘,’间隔

##查找

  • 通过select.. from实现
    1
    2
    3
    SELECT [列名或表达式]
    FROM [表名或视图名]
    order by [排序的根据]

Java 核心机制深度解析:包、类与访问控制的艺术

📖 引言

在 Java 开发中,我们每天都在写 packageimportpublic class。但你是否思考过:为什么 Java 要制定这些看似繁琐的规则?

  • 为什么一个 .java 文件里只能有一个 public 类?
  • 为什么外部类不能用 privateprotected 修饰?
  • import 到底引入了什么?

这些规则并非随意设定,而是 Java 编译器为了实现高效查找明确命名空间严格封装而做出的核心设计。今天,我们就来拆解这些机制背后的逻辑。


1. 包(Package):Java 的命名空间与文件系统映射

1.1 什么是包?

在 Java 中,包(Package) 本质上是一个命名空间(Namespace),同时也对应着文件系统中的目录结构

它主要解决两个核心问题:

  1. 命名冲突:避免不同开发者定义的相同类名发生冲突(例如:你定义的 User 和我定义的 User)。
  2. 访问控制:提供“包级私有(package-private)”的访问权限,隐藏内部实现细节。

1.2 包与文件系统的强绑定

Java 强制要求:包名必须与文件目录结构完全一致

如果你声明:

1
package com.example.service;

那么该文件必须位于项目源码目录下的 com/example/service/ 文件夹中。

💡** 核心逻辑**:这种强绑定关系让 JVM 和编译器可以通过类的全限定名(Fully Qualified Name),直接计算出该类在磁盘上的物理路径,无需遍历搜索,极大提升了编译和加载效率。


2. Import 机制:引入的是“类”而非“文件”

很多初学者误以为 import 是引入一个文件,这是一个常见的误区。

2.1 Import 的真实含义

当你写下:

1
import com.example.service.UserService;

你实际上是在告诉编译器:

“我在代码中要用到 UserService 这个,请去 com.example.service 这个包下找到它的定义。”

2.2 为什么需要“单 Public 类”规则?

这正是 Java 规定 “一个 .java 文件中至多只能有一个 public 类,且文件名必须与该 public 类同名” 的根本原因。

场景推演:
假设允许一个文件 Utils.java 中包含两个 public 类:

1
2
3
// 文件名:Utils.java
public class A { ... }
public class B { ... }

当你在另一个文件中写 import A; 时,编译器会陷入困惑:

  • A 类是在 A.java 中吗?
  • 还是在 Utils.java 中?
  • 甚至可能在 Other.java 中?

如果没有“类名=文件名”的约定,编译器为了找到一个类,可能需要扫描项目中所有的 .java 文件,这将导致编译速度极慢,且容易产生歧义。

结论

**import**** 引入的是类。为了保证编译器能通过类名快速、唯一地定位到源文件,Java 强制建立了 **类名 <-> 文件名 <-> 包路径** 的一一映射关系。**


3. 外部类的访问修饰符:为什么只有 public 和 default?

在 Java 中,类分为**外部类(Top-level Class)内部类(Inner Class)**。它们的访问修饰符规则截然不同。

3.1 外部类的限制

对于直接定义在 .java 文件中的外部类,只能使用以下两种修饰符:

  1. **public**:公开的,可以被任何包中的类访问。
  2. **default**(不写修饰符):包级私有的,只能被同一个包内的类访问。

** 禁止使用 **private** 和 ****protected**

3.2 深度解析:为什么不能用 private/protected?

语义冲突分析

  • **private**** 的含义**:私有,仅对“宿主”可见。
    • 内部类可以有 private,因为它隶属于某个外部类,对外部类的其他成员私有是合理的。
    • 外部类没有宿主。如果一个外部类是 private,它对谁私有?对 JVM?对包?这在语义上是不成立的。如果它对外不可见,那它永远无法被实例化,失去了存在的意义。
  • **protected**** 的含义**:对子类可见 + 同包可见。
    • protected 的核心场景是继承
    • 虽然外部类可以被继承,但访问控制的第一道门槛是“能否看到该类”。如果一个类连被“看到”(import)的资格都受限于子类关系,会导致循环依赖和复杂的编译检查逻辑。
    • Java 设计者认为:类要么完全公开(public),要么只在这个模块(包)内内部使用(default)。如果需要限制继承,可以在类内部通过构造函数或 final 关键字控制,而不是在类定义级别使用 protected

3.3 对比表

特性 外部类 (Top-level) 内部类 (Inner)
可用修饰符 public
, default
public
, protected
, private
, default
文件对应 文件名必须与 public 类名一致 无独立文件,依附于外部类
访问范围 全局 或 包内 可精确控制到外部类的实例或静态上下文
设计目的 构建模块的对外接口或内部实现 封装逻辑,回调,事件监听

4. 最佳实践:构建清晰的 Java 项目结构

基于上述原理,我们在实际开发中应遵循以下规范:

4.1 目录结构规范

严格遵守包名与目录一致的原则。

1
2
3
4
5
6
7
8
9
10
src/main/java
└── com
└── example
├── Application.java // public class Application
├── controller
│ └── UserController.java // public class UserController
└── service
├── UserService.java // public class UserService
└── impl // 存放实现细节
└── UserServiceImpl.java

4.2 类的设计原则

  1. 单一职责:一个文件只专注于一个 public 类的定义。如果有辅助类,可以考虑:
    • 定义为单独的 .java 文件(使用 default 访问权限,仅限包内使用)。
    • 定义为 static 内部类(如果它紧密依赖于外部类)。
  2. 最小暴露原则
    • 对外提供的 API、DTO、Service 接口使用 public
    • 内部工具类、实现细节、数据传输对象(如果不跨包)尽量使用 default,减少 public 类的数量,降低耦合。

4.3 避免通配符导入

虽然 import java.util.*; 很方便,但在大型项目中,显式导入(import java.util.List;)更优:

  • 清晰性:明确知道使用了哪些类。
  • 避免冲突:防止不同包中存在同名类时产生编译错误。

5. 总结

Java 的这些“硬性规定”,初看是束缚,实则是为了保护开发者:

理解这些底层逻辑,不仅能帮你避开编译错误,更能让你在设计系统架构时,自然地遵循高内聚、低耦合的原则。


本文基于 Java SE 17+ 规范编写,适用于 Spring Boot 及各类企业级 Java 应用开发场景。


算术逻辑单元(ALU)与加法器设计

🎯 学习目标

  • 理解 ALU 的功能与基本结构
  • 掌握多位加法器的两种实现方式:行波进位 vs 超前进位
  • 了解 ALU 如何支持加法、减法、逻辑运算及自增/自减
  • 认识 ALU 在 CPU 中的核心地位

一、什么是 ALU?

ALU(Arithmetic Logic Unit) 是 CPU 中执行基本运算的数字电路模块。

✅ 主要功能:

类型 操作示例
算术运算 加(ADD)、减(SUB)、自增(INC)、自减(DEC)
逻辑运算 AND、OR、XOR、NOT
比较/标志 判断结果是否为零(Zero)、是否溢出(Overflow)

📌 现代 ALU 通常不直接实现乘除,但一定包含加法器和逻辑门阵列。


二、多位加法器设计

1. 行波进位加法器(Ripple Carry Adder)

  • 将 N 个全加器(Full Adder)级联
  • 第 i 位的进位输出(Cout)作为第 i+1 位的进位输入(Cin)
  • 最低位 Cin = 0

✅ 优点:结构简单,硬件成本低
❌ 缺点:进位逐级传递,延迟大(32 位 ≈ 32 级延迟)


2. 超前进位加法器(Carry Lookahead Adder, CLA)

  • 提前并行计算每一位的进位,不依赖前一级 Cout
  • 引入两个关键信号:
    • 生成(Generate): ( G_i = A_i \cdot B_i ) → 本位必然产生进位
    • 传播(Propagate): ( P_i = A_i \oplus B_i ) → 本位会传递进位

进位公式示例:
[
\begin{aligned}
C_1 &= G_0 \
C_2 &= G_1 + P_1 G_0 \
C_3 &= G_2 + P_2 G_1 + P_2 P_1 G_0 \
\end{aligned}
]

✅ 优点:延迟显著降低(接近常数)
⚠️ 代价:电路复杂度高,通常用于 4~8 位小组,再分组级联

🌐 现代 CPU 广泛采用多级超前进位结构以平衡速度与面积。


三、ALU 如何支持多种操作?

核心设计:功能单元 + 多路选择器(MUX)

1
2
3
4
5
6
7
8
9
10
        A ────────────────┐
├──[AND]──┐
B ────────────────┤ │
├──[OR]───┤
├──[XOR]──┼── MUX ──→ Result
├──[ADD]──┤
Control Signal ──→[SEL]─────┘
控制信号(如 ALUOp) 决定 MUX 选择哪一路输出
减法通过补码实现:
A - B = A + (-B) = A + (\sim B + 1)

四、自增(INC)与自减(DEC)的实现

方法 1:复用加法器(通用方式)

  • 自增:A + 1
  • 自减:A + (-1)(-1 的补码 = 全 1,如 111…111)
  • 通过 MUX 将 B 输入替换为常数 1 或 -1

方法 2:专用递增器(高性能场景)

  • 用于程序计数器(PC)、循环计数器等关键路径
  • 利用 +1 的进位规律(连续 1 变 0,首个 0 变 1)并行生成结果
  • 延迟远低于通用加法器
    💡 即使指令集无 INC 指令(如 MIPS),编译器也会用 addi $reg, $reg, 1 实现。

五、ALU 的典型接口(以教学级 MIPS 为例)

输入信号

信号名 位宽 说明
A[31:0] 32 位 第一个操作数
B[31:0] 32 位 第二个操作数
ALUOp[2:0] 3 位 控制信号:
010 = ADD
110 = SUB
• 其他值对应 AND/OR/XOR 等

输出信号

信号名 位宽 说明
Result[31:0] 32 位 运算结果
Zero 1 位 Result == 0,则置 1;否则为 0
→ 用于 beq 等条件跳转指令
Overflow 1 位 加法溢出标志:
符号位进位 ≠ 最高数值位进位 时置 1

🔍 Zero 信号生成方法
Result[31:0] 的所有位进行 OR 运算,然后取反:
[
\text{Zero} = \overline{R_{31} + R_{30} + \cdots + R_0}
]
→ 只有当所有位都是 0 时,OR 结果为 0,取反后 Zero = 1。🔍 Zero 信号生成:将 Result 所有位 OR 后取反。

📝 小结

ALU 是 CPU 的运算核心,支持算术与逻辑操作
行波进位 简单但慢,超前进位 快但复杂
减法 = 加负数(补码),无需独立减法器
自增/自减 通常通过加法器 + 常数实现
控制信号 + MUX 实现操作选择
ALU 输出的 Zero / Overflow 标志对程序控制流至关重要

基本逻辑门与组合逻辑电路

🎯 学习目标

  • 掌握 7 种基本逻辑门(AND、OR、NOT、NAND、NOR、XOR、XNOR)
  • 理解布尔代数如何描述和简化逻辑关系
  • 能用逻辑门搭建简单组合电路(如半加器、全加器)
  • 区分组合逻辑与时序逻辑

一、什么是逻辑门?

逻辑门 是实现布尔函数的电子器件,输入/输出只有 0(低电平)或 1(高电平)。


二、7 种基本逻辑门

符号 布尔表达式 功能
NOT ⦁→○ ( Y = \overline{A} ) 取反
AND & ( Y = A \cdot B ) 全1才1
OR ≥1 ( Y = A + B ) 有1就1
NAND &+○ ( Y = \overline{A \cdot B} ) 全1才0
NOR ≥1+○ ( Y = \overline{A + B} ) 全0才1
XOR =1 ( Y = A \oplus B ) 不同为1
XNOR =1+○ ( Y = \overline{A \oplus B} ) 相同为1

重点

  • NAND 和 NOR 是“通用门”:仅用它们可构建任何逻辑电路。
  • XOR 用于加法、奇偶校验

三、布尔代数基础

常用定律包括交换律、结合律、分配律、德·摩根律吸收律等。

德·摩根律(De Morgan’s Laws)

[
\begin{aligned}
\overline{A + B} &= \overline{A} \cdot \overline{B} \
\overline{A \cdot B} &= \overline{A} + \overline{B}
\end{aligned}
]

【Q&A】(\overline{A}) 是什么?德·摩根怎么理解?

  • (\overline{A}) 表示 A 的逻辑非(NOT A),不是数学负号。
    • 若 (A = 0),则 (\overline{A} = 1);若 (A = 1),则 (\overline{A} = 0)。
  • 德·摩根的核心思想:
    • “A 或 B 不成立” ⇔ “A 不成立 且 B 也不成立”
    • “A 与 B 不成立” ⇔ “A 不成立 或 B 不成立”
  • 电路意义:可用 NOT + AND 实现 NOR,体现门电路的等价性。

吸收律(Absorption Law)

[
\begin{aligned}
A + A \cdot B &= A \
A \cdot (A + B) &= A
\end{aligned}
]

【Q&A】吸收律为什么成立?怎么推导?
1. 真值表验证:无论 B 取何值,(A + AB) 的结果始终等于 A。
2. 代数推导
[
A + AB = A \cdot 1 + A \cdot B = A(1 + B) = A \cdot 1 = A
]
(因为 (1 + B = 1) 在布尔代数中恒成立)
3. 电路意义:当 A 已确定输出时,额外的 (AB) 路径不影响结果,被“吸收”。
→ 这是逻辑简化的重要工具!


四、组合逻辑电路

组合逻辑电路:输出仅取决于当前输入,无记忆、无反馈。

特点:

  • 输入变化 → 输出立即响应(忽略延迟)
  • 由逻辑门直接连接构成
  • 例子:加法器、译码器、多路选择器

五、实战:加法器设计

1. 半加器(Half Adder)

  • 输入:A, B
  • 输出:
    • Sum = (A \oplus B)
    • Carry = (A \cdot B)

2. 全加器(Full Adder)

  • 输入:A, B, Cin
  • 可用 2 个半加器 + 1 个 OR 门 构成
  • 是构建多位加法器(如32位ALU)的基本单元

六、组合逻辑 vs 时序逻辑(预览)

组合逻辑 时序逻辑
输出依赖 仅当前输入 当前输入 + 历史状态
有无记忆 ❌ 无 ✅ 有(靠寄存器)
例子 加法器、译码器 寄存器、计数器、CPU

📝 小结

  • 逻辑门是数字电路的“原子”
  • 布尔代数是设计与优化的数学工具
  • 半加器 = XOR + AND;全加器 = 2×半加器 + OR
  • 德·摩根律吸收律 是化简的关键
  • 组合逻辑 = 无记忆,纯门电路

定点数与浮点数表示(IEEE 754 标准)

定点数与浮点数表示(IEEE 754 标准)

🎯 学习目标

  • 理解定点数的基本思想(为浮点做铺垫)
  • 掌握 IEEE 754 单精度(32位)浮点数的结构
  • 能手动将十进制小数转换为 IEEE 754 格式
  • 理解 为什么 0.1 + 0.2 != 0.3
  • 了解特殊值:无穷大(∞)、NaN、非规格化数

一、为什么需要浮点数?

整数可用补码完美表示,但现实中有大量小数

  • 科学计算:3.1415926
  • 金融:99.99
  • 图形:坐标 (1.5, -2.3)

如果用固定小数点位置(比如始终保留2位小数),叫 定点数(Fixed-Point)

  • 优点:硬件简单,运算快
  • 缺点:范围小、精度固定(无法同时表示 0.0000011000000.0

【Q&A】为什么定点数无法同时表示极小数和极大数?
因为定点数的小数点位置在硬件中是固定的。例如,若用32位表示,你必须预先分配多少位给整数部分、多少位给小数部分。

  • 表示 1000000.0 需要约20位整数部分;
  • 表示 0.000001 需要约20位小数部分;
    但总共只有32位,无法兼顾。
    浮点数通过“阶码”动态调整尺度,用同一格式覆盖极大范围和高精度。

→ 所以需要 浮点数(Floating-Point)小数点位置可以“浮动”,类似科学计数法!


二、科学计数法 → 浮点数思想

十进制科学计数法:
123.45 = 1.2345 × 10²

二进制科学计数法:
5.75₁₀ = 101.11₂ = 1.0111 × 2²

浮点数就是把一个数拆成三部分:
数值 = (-1)^S × (1.M) × 2^(E - Bias)

  • S:符号位(0正,1负)
  • M:尾数(Mantissa / Fraction),表示有效数字
  • E:阶码(Exponent),表示指数(带偏移)

✅ 这就是 IEEE 754 标准的核心!


三、IEEE 754 单精度(32位)格式

位段 长度 含义
S(符号) 1 位 0 = 正,1 = 负
E(阶码) 8 位 存储 指数 + 偏移量(Bias)
M(尾数) 23 位 存储小数部分(隐含前导1

💡 偏移量(Bias):单精度用 127,所以实际指数 = E - 127

🌟 关键技巧:隐含前导1(Hidden Bit)

  • 规格化数(Normalized)的二进制形式总是 1.xxxxx
  • 所以 IEEE 754 不存这个“1”,只存小数部分 xxxxx,省1位,提高精度!

【Q&A】单精度是否等于“1位整数 + 多位小数 + 偏移”?
是的!更准确地说:
单精度将实数表示为 二进制科学计数法 (-1)^S × 1.M × 2^E,然后:

  • 符号 S 存 1 位;
  • 尾数只存 M(23位小数部分),前导 1. 是隐含的;
  • 阶码存 E + 127(8位无符号整数)
    这三部分组成32位,实现高效、统一的浮点表示。

四、动手:十进制 → IEEE 754(单精度)

例:+5.75

  1. 转二进制:101.11
  2. 规格化:1.0111 × 2² → M = 0111..., E真实 = 2
  3. 阶码存储:2 + 127 = 129 → 1000 0001
  4. 组合: 0 10000001 01110000000000000000000

五、为什么 0.1 + 0.2 != 0.3

  • 0.1₁₀ = 0.0001100110011...₂(无限循环)
  • IEEE 754 只能存 23位尾数 → 必须截断/舍入
  • 内存中存的是 近似值 ≈ 0.10000000149…
  • 两个近似值相加 ≠ 0.3 的近似值

✅ 在 Python 中:

1
2
3
4
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False

💡 启示:永远不要用 == 比较浮点数!应使用 abs(a - b) < epsilon


六、IEEE 754 单精度(32位)

部分 位数 说明
S 1 符号位(0 = 正,1 = 负)
E 8 阶码(Exponent),偏置值 Bias = 127
M 23 尾数(Mantissa/Fraction),隐含前导 1

💡 小知识:实际数值计算公式为
$
(-1)^S \times (1.M) \times 2^{E - 127}
$
其中 1.M 表示二进制小数(如 1.101)。

示例:将十进制数 5.0 转换为 IEEE 754 单精度

  1. 转二进制:
    $ 5.0_{10} = 101.0_2 = 1.01_2 \times 2^2 $

  2. 确定各字段:

    • S = 0(正数)
    • E = 2 + 127 = 129 → 二进制 10000001
    • M = 01 后补零至 23 位 → 01000000000000000000000
  3. 最终 32 位表示:

1
2
3
0 10000001 01000000000000000000000
↑ ↑ ↑
S E(8位) M(23位)

七、双精度(64位)简介

部分 位数 说明
S 1 符号
E 11 阶码(Bias = 1023)
M 52 尾数(隐含前导1)

精度:≈15 ~ 17 位十进制
范围:≈ ±10³⁰⁸
编程语言中 double 类型即为此格式

计算机系统概述 & 冯·诺依曼体系结构

1.什么是计算机组成原理?

计算机组成原理研究的是:
计算机内部各功能部件如何协同工作,以执行程序指令。

2.冯.诺依曼体系结构

这是现代几乎所有通用计算机的基础架构,由数学家冯.诺伊曼在1945年提出。

核心思想(五大部件+存储程序):

|部件|功能|
|运算器(ALU)|执行算数和逻辑运算(如加法、与或非)|
|控制器(CU)|指挥协调各部件工作,取指令、译码、执行)|
|存储器(Memory)|存放程序和数据(统一编址[^1])|
|输入设备|如鼠标、键盘,将外部信息送入计算机|
|输出设备 |如显示器、打印机,将结果输出|
[^1]: 统一编码:程序指令(代码)和数据共享一个线性地址空间,由CPU使用相同的地址总线进行访问。

工业流程(简化版):

1.程序(如a=b+c)被编译成机器指令,存入内存;
2.CPU的控制器从内存逐条取出指令(取指)。
3.对指令译码,知道要做什么操作。
4.控制ALU(运算器)从内存读取bc,计算b+c
5.将结果写回内存(或寄存器)。
6.重复,直至程序结束。

💡 这个“取指 → 译码 → 执行”的循环,称为 指令周期(Instruction Cycle),是CPU工作的核心节奏。

3.现代计算机的层次结构(补充视角)

虽然底层是冯·诺依曼模型,但现代计算机更复杂,通常分为多层:

1
2
3
4
5
6
7
8
9
10
11
应用程序(Python/Java)

操作系统(管理硬件资源)

指令集架构(ISA,如x86、ARM、RISC-V)

微体系结构(CPU内部设计:流水线、多核等)

数字逻辑电路(门电路、触发器)

半导体器件(晶体管、电容)

计算机组成原理主要聚焦在 ISA 层到微体系结构层,即“程序员可见的硬件行为”和“CPU如何实现这些行为”。

⚠️ 注意:哈佛结构 vs 冯·诺依曼结构
冯·诺依曼:程序和数据共用一个存储空间和总线(通用计算机主流)。
哈佛结构:程序存储器和数据存储器分开(常用于嵌入式系统,如单片机),可并行取指和取数,速度更快。
现代CPU内部其实混合使用:L1 Cache 分为指令Cache和数据Cache(类似哈佛),但主存仍是统一的(冯·诺依曼)。

无名杀安装

零基础 10 分钟搭建网页版「无名杀」

只要会开机、会打字就能搞定!全程中文界面,浏览器直接玩。


✅ 准备清单

项目 要求
电脑 Windows 10/11(Win7 不行)
网络 能打开网页(最好有代理,下载更快)
技能 会复制粘贴,认识字母

📥 第1步:装两个“小帮手”

  1. Node.js(自动下载工具)
    • 打开 https://nodejs.org → 点 LTS → 下载 → 一路 Next
    • 安装完按 Win+R → 输入 cmd → 回车 → 输入
      1
      2
      3
      4
      5
      6
      7
           node -v
      ```
      出现版本号就 OK,关窗口。

      2. **Git**(可选,但推荐)
      - https://git-scm.com → 下载 → 全部默认安装
      - 同样在黑窗口输入
      git –version
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
           出现版本号就 OK。

      ---

      ## 📥 第2步:把游戏“搬”到电脑
      1. 在 **D盘** 新建文件夹 `noname`(路径不要有空格/中文)
      2. 打开 **cmd**(Win+R → 输入 `cmd` → 回车)
      3. 一行行复制(每行回车):

      ```cmd
      cd /d D:\noname
      git clone https://github.com/libnoname/noname.git
      cd noname
      git checkout v1.11.1

第3步:一键安装依赖

还在黑窗口,复制:

1
npm install

等 3-10 分钟,出现大量 added xxx packages 即可。
如果卡住 99% → 再复制下面两行换国内镜像:

1
2
npm config set registry https://registry.npmmirror.com
npm install

🏗️ 第4步:生成游戏资源(更新代码后做一次)

同窗口输入:

1
npm run build:full

30s后出现done即可。
这一步把武将、皮肤、音频整理到dist\文件夹。


🚀 第5步:启动网页服务器

继续输入:

1
2
cmd
npm run dev

看到:

1
2
应用正在使用8089端口以提供无名杀本地服务器功能!
Server running at http://localhost:8089

不要关这个窗口,最小化即可。


🎮 第6步:浏览器开玩

1.打开Edge/chrome/Firefox
2.地址栏输入:

1
localhost:8089

3.
回车 → 出现登录界面 → 右下角版本号 v1.11.1 → 开始游戏

注1:有的电脑在执行完上一步会自动跳转;
注2:玩完记得在’cmd’中’ctrl+c’结束服务;


推荐操作:

在桌面上新建一个bat文件,里面:

1
2
3
4
5
bat
@echo off
cd /d D:\noname\noname(存放位置)
npm run dev
start http://localhost:8089

这样便于打开使用

'贪心算法'

贪心算法

一、概述

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取当前状态下最优(即最有利)的选择,从而希望导致结果是全局最优的算法策略。它是一种简单而有效的算法思想,在许多问题中能够快速得到近似最优解。

二、基本原理

贪心算法的基本思想是通过局部最优的选择来逐步构建全局最优解。其核心步骤如下:

  1. 分解问题:将问题分解为多个子问题,每个子问题都有一个最优解。
  2. 局部最优选择:在每个子问题中,选择当前状态下最优的解。
  3. 构建全局解:通过局部最优解逐步构建全局最优解。

三、贪心算法的特点

  • 优点
    • 简单高效:贪心算法通常具有较低的时间复杂度,能够在较短时间内得到解。
    • 易于实现:贪心算法的逻辑相对简单,容易理解和实现。
  • 缺点
    • 无法保证全局最优:贪心算法只能保证局部最优,不能保证最终结果是全局最优解。
    • 适用范围有限:并非所有问题都适合使用贪心算法,需要根据具体问题进行判断。

四、适用场景

贪心算法适用于以下几种情况:

  • 具有贪心选择性质:问题的全局最优解可以通过局部最优解来构建。
  • 具有最优子结构:问题的最优解包含其子问题的最优解。

五、经典案例

(一)活动选择问题

问题描述:给定一系列活动,每个活动都有一个开始时间和结束时间,选择尽可能多的不重叠活动。

贪心策略:每次选择结束时间最早的活动,并排除与其冲突的活动。

算法步骤

  1. 按活动的结束时间对活动进行排序。
  2. 选择第一个活动。
  3. 对于后续的每个活动,如果它的开始时间不早于当前活动的结束时间,则选择该活动,并更新当前活动。

代码示例(Python):

def activity_selection(start, finish):
    activities = sorted(zip(start, finish), key=lambda x: x[1])  # 按结束时间排序
    selected = [activities[0]]  # 选择第一个活动
    for i in range(1, len(activities)):
        if activities[i][0] >= selected[-1][1]:  # 当前活动开始时间不早于上一个活动结束时间
            selected.append(activities[i])
    return selected

Day1'

本文基于 菜鸟教程 PyTorch 神经网络基础 整理,并补充了实战建议与易踩坑提示,适合刚入门的同学快速上手。


1. 神经网络到底在做什么?

一句话:把输入数据通过层层加权+激活映射到目标空间,让模型自己学会“特征提取器”。

核心三件套:

组件 作用
神经元 线性加权 + 非线性激活
把神经元按功能分组(输入/隐藏/输出)
连接权重 网络唯一可学习的参数

2. PyTorch 中的“骨架”:nn.Module

所有网络都继承自 nn.Module,必须实现两个方法:

class SimpleNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(2, 2)  # 输入 2 维 → 隐藏 2 维
        self.fc2 = nn.Linear(2, 1)  # 隐藏 2 维 → 输出 1 维

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        return self.fc2(x)

打印模型即可看到网络结构:

SimpleNN(
  (fc1): Linear(in_features=2, out_features=2, bias=True)
  (fc2): Linear(in_features=2, out_features=1, bias=True)
)

3. 激活函数怎么选?
表格
激活函数
适用场景
PyTorch 写法
ReLU
隐藏层默认首选
 torch.relu(x) 
Sigmoid
二分类输出层
 torch.sigmoid(x) 
Softmax
多分类输出层
 F.softmax(x, dim=1) 
Tanh
早期网络,现在较少
 torch.tanh(x) 
小技巧:隐藏层一律 ReLU,输出层看任务类型,基本不会错。
4. 损失函数 & 优化器速查表
表格
任务类型
损失函数
优化器推荐
回归
 nn.MSELoss() 
 Adam 
二分类
 nn.BCEWithLogitsLoss() 
 Adam 
多分类
 nn.CrossEntropyLoss() 
 Adam  /  SGD+momentum 
5. 训练循环 6 步曲
python
for epoch in range(100):
    model.train()                # 1. 训练模式
    optimizer.zero_grad()        # 2. 清零梯度
    output = model(X)            # 3. 前向传播
    loss = criterion(output, Y)  # 4. 计算损失
    loss.backward()              # 5. 反向传播
    optimizer.step()             # 6. 更新权重

每 10 个 epoch 打印一次损失,肉眼观察是否下降即可。
6. 评估 & 预测
python
model.eval()                    # 关键:切换评估模式
with torch.no_grad():           # 关闭梯度,节省显存
    output = model(X_test)
    loss = criterion(output, Y_test)
print(f'Test Loss: {loss.item():.4f}')

7. 常见网络家族一览
表格
网络缩写
全称
典型场景
FNN
前馈神经网络
表格数据、简单回归
CNN
卷积神经网络
图像、语音频谱
RNN
循环神经网络
股票、文本、时间序列
LSTM
长短期记忆网络(RNN 升级版)
长文本、机器翻译

Day1'

通过命令提示符:
bash
net start mysql
关闭MySQL服务器
通过“服务”管理工具:
打开“运行”对话框(Win + R),输入services.msc,找到“MySQL”服务,右击选择“停止”。

通过命令提示符:
bash
net stop mysql
MySQL的增删改查操作指令
创建数据库
sql
CREATE DATABASE database_name;
创建表
sql
CREATE TABLE table_name (
column1 datatype,
column2 datatype,

);
插入数据
sql
INSERT INTO table_name (column1, column2, …)
VALUES (value1, value2, …);
查询数据
sql
SELECT column1, column2, …
FROM table_name
WHERE condition;
更新数据
sql
UPDATE table_name
SET column1 = value1, column2 = value2, …
WHERE condition;
删除数据
sql
DELETE FROM table_name
WHERE condition;
删除表
sql
DROP TABLE table_name;
删除数据库
sql
DROP DATABASE database_name;