diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..0e46c11 --- /dev/null +++ b/README.en.md @@ -0,0 +1,159 @@ +# Markdown To Web + +> Turn a local Markdown notes folder into a deployable static React site. + +This project scans all `.md` files inside `public/mengyanote/`, generates JSON datasets (directory tree, file contents, stats) at build time, and renders them client‑side with React + `react-markdown`. The output is a **pure static site** (no server / no DB) suitable for GitHub Pages, Netlify, Vercel, or any static hosting. + +Chinese documentation: see `README.md`. + +## ✨ Features + +- 🚀 One‑command data generation (recursive scan → JSON assets) +- 📦 Fully static deployment (no runtime backend needed) +- 🧭 Expandable directory tree with stable IDs / paths +- 📝 Rich Markdown: GFM (tables, task lists, strikethrough), soft line breaks, math (KaTeX), code highlighting +- 🧮 Math via `remark-math` + `rehype-katex` +- 💡 Enhanced code blocks: language label + copy button +- 📚 Breadcrumb navigation derived from file path +- 🔌 Pluggable remark / rehype pipeline (easy to remove / replace) +- 🕶 Dark theme (fully customizable via CSS) +- 🔍 Multi-path fallback when fetching generated JSON (`/data` → `/src/data` → `./data`) +- 🧯 Ignore mechanism via `ignore.json` +- 📊 Basic statistics (file count, folder count, timestamp) + +## 🛠 Tech Stack + +- React 19 + Hooks + Context +- Vite +- `react-markdown` + remark / rehype plugins: + - `remark-gfm`, `remark-math`, `remark-breaks` + - `rehype-raw`, `rehype-katex`, `rehype-highlight` +- Highlight.js theme (replaceable) +- KaTeX (optional) + +## ⚡ Quick Start + +```bash +npm install +npm run dev # generate data + start dev server +npm run build # generate data + build static site (dist/) +npm run preview # preview production build +npm run generate-data # only regenerate JSON +npm run lint +``` + +## 📂 Key Structure + +``` +public/ + mengyanote/ # Source Markdown tree (add your .md here) + data/ # Public copy of generated JSON +scripts/ + generateData.js # Node script: scans + emits JSON +src/ + data/ # Generated JSON (consumed in dev/build) + components/ # UI (MarkdownRenderer, Sidebar, ...) + context/ # AppContext (state + actions) + utils/fileUtils.js # Fetch + helpers + breadcrumbs +``` + +## 🧬 How It Works + +1. `generateData.js` walks `public/mengyanote/` (applying `ignore.json` rules) +2. Builds: + - `directoryTree.json` (hierarchical tree) + - `fileContents.json` (path → raw markdown text) + - `stats.json` (counts + timestamp) +3. Writes duplicates to `src/data/` (for imports / dev) and `public/data/` (for runtime fetch in final build) +4. Frontend loads JSON (tries `/data` → `/src/data` → `./data`) and renders selected file + +``` +Markdown(.md) --> generateData.js --> JSON (tree, contents, stats) --> React (render) +``` + +## 🧯 Ignore Rules + +Default ignored: `.obsidian`, `.trash`, `.git`, `node_modules`, any dot‑prefixed file/dir. + +Custom ignore: create `public/mengyanote/ignore.json`: + +```json +{ "ignore": ["Drafts", "private", "Scratch.md"] } +``` + +## 🎨 Customization Cheatsheet + +| Goal | Where | Action | +|------|-------|--------| +| Remove math | `MarkdownRenderer.jsx` | Drop `remark-math` + `rehype-katex` + CSS import | +| Remove code highlighting | `MarkdownRenderer.jsx` | Remove `rehype-highlight` and theme CSS | +| New highlight theme | Add dependency | Replace imported highlight style | +| Inline code as plain text | Already done | Custom plugin strips inline code styling | +| Change image layout | `MarkdownRenderer.css` | Adjust `.markdown-image img` | +| Change breadcrumb format | `fileUtils.generateBreadcrumbs` | Modify join logic | + +## 🚢 Deployment + +Build output: `dist/` (fully static). + +Platforms: + +| Platform | Notes | +|----------|-------| +| GitHub Pages | Push `dist/` to `gh-pages` or use an Action | +| Netlify | Build: `npm run build`, Publish: `dist` | +| Vercel | Auto-detect Vite | +| Any static host / Nginx | Upload `dist/` | + +Example Nginx: + +``` +server { + listen 80; + server_name example.com; + root /var/www/markdown-to-web/dist; + location / { try_files $uri /index.html; } + add_header Cache-Control "public, max-age=31536000"; +} +``` + +## FAQ + +**New file not appearing?** Regenerate data: `npm run generate-data` (or rerun dev/build). + +**Ignore not working?** Ensure `ignore.json` sits directly in `public/mengyanote/` and key is exactly `ignore`. + +**Large number of files causes slow load?** Consider splitting `fileContents.json` into per‑file JSON (enhancement idea). + +**Search support?** Not yet. You can integrate `minisearch` or `lunr` during build. + +**Can I support frontmatter?** Extend the generator to parse YAML frontmatter and attach metadata to each node. + +## Roadmap (Open for Contributions) + +- [ ] Full‑text search +- [ ] Per‑file lazy loading +- [ ] Recent updates panel / changelog +- [ ] Frontmatter tags + filters +- [ ] RSS / JSON feed generation +- [ ] PDF / print friendly mode +- [ ] Service Worker caching +- [ ] GitHub Actions deploy workflow example + +## Contributing & License + +Issues / PRs welcome. Please open an issue before large feature work; attach screenshots for UI changes. License: see `LICENSE`. + +## Contact + +Open an issue describing: + +- Desired visual style (links / screenshots) +- Needed deployment pipeline (e.g., GitHub Pages Action) +- Theming or performance concerns + +I can suggest patches or configuration examples. + +--- + +Happy publishing! If you build cool themes (minimal / book‑like / image‑first), consider sharing them back. 🙌 diff --git a/README.md b/README.md index 1ca15fa..33ebb63 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,47 @@ # Markdown To Web -此仓库将一组本地 Markdown 笔记(位于 `public/mengyanote`)转换成一个静态的 React 网站,便于浏览、检索和发布到网络上。 +> 将本地 Markdown 笔记目录“一键”编译为可部署的静态 React 网站。 -本 README 为中文说明,包含项目简介、运行/构建步骤、目录结构、如何编辑笔记以及部署和贡献指南,方便直接发布到 GitHub。 +此仓库会读取 `public/mengyanote/` 下的所有 Markdown 文件,生成 JSON 数据,并在前端通过 React + react-markdown 渲染,最终可直接构建成 **纯静态站点**(可部署到 GitHub Pages / Netlify / Vercel / 任意 Nginx / OSS 等)。 -## 主要特性 +本 README(中文)包含:项目定位、特性说明、运行与构建、内部工作原理、目录结构、忽略与定制、部署方式、常见问题(FAQ)与未来计划(Roadmap)。 -- 从本地目录(`public/mengyanote`)递归读取 Markdown 文件并生成静态数据(`src/data`)。 -- 使用 `react-markdown` 渲染 Markdown,支持数学公式(remark/rehype 插件)与代码高亮。 -- 目录树侧边栏、内容渲染器等基础浏览功能。 -- 通过简单脚本将 Markdown 文件转为项目需要的 JSON 数据,便于在静态站点中直接使用。 +如需英文版本,请查看 `README.en.md`。 -## 技术栈 +## ✨ 主要特性 -- React 19 -- Vite -- react-markdown + remark/rehype 插件(remark-gfm、remark-math、rehype-katex、rehype-highlight 等) +- 🚀 **一键生成数据**:脚本自动递归扫描 `public/mengyanote`,提取目录树、文件内容与统计信息。 +- 📦 **纯静态输出**:构建阶段就准备好全部数据,无需后端 / Serverless API。 +- 🧭 **动态目录树**:可展开/折叠,每个节点保留唯一 `path` 与 `id`。 +- 📝 **Markdown 全面支持**:GFM(表格 / 任务列表 / 删除线)、换行、数学公式(KaTeX)、代码块高亮(Highlight.js)。 +- 🧮 **数学公式渲染**:`remark-math` + `rehype-katex`。 +- 💡 **代码体验增强**:复制按钮、语言标签、自动高亮。 +- 📚 **面包屑导航**:基于文件路径实时生成。 +- 🧱 **可定制渲染组件**:可移除/替换任意 remark/rehype 插件,或覆写组件(如链接、图片、表格、代码块)。 +- 🕶 **深色风格**(可自定义):CSS 易修改,可换成“极简/原味/图片优先”布局。 +- 🔍 **预生成数据多路径兜底**:前端运行时尝试从 `/data` 或 `/src/data` 加载,兼容不同构建/部署结构。 +- 🧯 **忽略机制**:支持 `ignore.json` 自定义排除目录 / 文件。 +- 📊 **统计信息**:生成文件总数、文件夹总数、生成时间等元数据。 -## 快速开始(Windows / cmd.exe) +> 该项目适合:知识库发布、学习笔记归档、团队内部静态文档、离线备份网页化。 + +## 🛠 技术栈 + +- React 19 + Hooks + Context +- Vite 构建 +- react-markdown + remark / rehype 插件: + - `remark-gfm`(扩展语法) + - `remark-math`(数学公式) + - `remark-breaks`(软换行) + - `rehype-raw`(允许原始 HTML 渲染) + - `rehype-katex`(数学公式渲染) + - `rehype-highlight`(代码高亮) +- Highlight.js 默认主题(可替换) +- KaTeX 样式(按需可移除) + +所有数据生成逻辑在 **Node 脚本层** 完成,前端只做纯渲染,部署安全轻量。 + +## ⚡ 快速开始(Windows / cmd.exe) 1. 安装依赖 @@ -57,7 +81,7 @@ npm run generate-data npm run lint ``` -## 项目结构(重要文件/目录) +## 🧬 项目结构(重要文件/目录) - `public/mengyanote/` - 源 Markdown 笔记目录(请把你的 .md 文件放在这里以纳入站点)。 - `scripts/generateData.js` - 将 Markdown 文件读取并生成 `src/data` 的脚本。 @@ -70,15 +94,26 @@ npm run lint 示例:如果你想让 Markdown 渲染更简洁(“换成我图片那种”样式),可以编辑 `src/components/MarkdownRenderer.css` 或直接修改 `MarkdownRenderer.jsx` 中的渲染类名/元素结构。 -## 如何编辑/添加笔记 +## ✍️ 如何编辑/添加笔记 1. 在 `public/mengyanote` 下增加或修改 `.md` 文件,保持目录组织即可。 2. 运行 `npm run generate-data`(或 `npm run dev`)以重新生成 `src/data`。 3. 刷新浏览器查看最新内容。 -注意:脚本会忽略以 `.` 开头的文件/目录(例如 `.obsidian`)和一些预设项(`node_modules`、`.git` 等)。 +### 忽略机制 -## 部署建议 +- 默认忽略:`.obsidian`、`.trash`、`.git`、`node_modules`、所有以 `.` 开头的文件或目录。 +- 自定义忽略:在 `public/mengyanote/ignore.json` 中加入: + +```jsonc +{ + "ignore": ["临时", "草稿.md", "private"] +} +``` + +> ignore.json 位于源根目录(`public/mengyanote`),脚本运行时会打印“已加载忽略配置”。 + +## 🚢 部署建议 - 静态站点:`npm run build` 会在 `dist/` 生成静态文件,适合部署到 GitHub Pages、Netlify、Vercel、或任意静态文件托管服务。 - GitHub Pages:构建后将 `dist/` 的内容发布到 gh-pages 分支或通过 GitHub Actions 自动发布。 @@ -93,20 +128,115 @@ npm run build 2. 将 `dist/` 内容上传到你的静态托管服务或 gh-pages 分支。 -如果需要,我可以为你添加一个自动部署到 GitHub Pages 的 GitHub Actions 工作流。 +如果需要,我可以为你添加一个自动部署到 GitHub Pages 的 GitHub Actions 工作流(`deploy.yml`)。示例工作流会: -## 定制渲染样式 +1. 触发条件:`push` 到 `main` 或手动触发 +2. 安装依赖 & 运行 `npm run build` +3. 发布 `dist/` 到 `gh-pages` 分支 + +(如需请开 Issue 或在 PR 中请求) + +### 其他托管方式 + +| 平台 | 方式 | 备注 | +|------|------|------| +| GitHub Pages | gh-pages 分支 / Action | 需启用 Pages | +| Netlify | 直接连接仓库 | Build 命令:`npm run build`,Publish:`dist` | +| Vercel | 导入项目 | 自动识别 Vite | +| OSS / Nginx | 上传 dist | 纯静态即可 | + +### 基础 Nginx 配置示例 + +```nginx +server { + listen 80; + server_name example.com; + root /var/www/markdown-to-web/dist; + location / { try_files $uri /index.html; } + add_header Cache-Control "public, max-age=31536000"; +} +``` + +## 🎨 定制渲染样式 如果你觉得当前 Markdown 美化太重并想改回更简洁的“图片优先”或原始样式: - 编辑 `src/components/MarkdownRenderer.css`:移除或覆盖过度的样式(字体、背景、代码块高亮等)。 - 编辑 `src/components/MarkdownRenderer.jsx`:调整渲染器的 className、元素包装或忽略某些 remark/rehype 插件。 -常见修改点: -- 移除 KaTeX 或代码高亮:在 `src/components/MarkdownRenderer.jsx` 中删除相应的 rehype 插件 import 与使用。 -- 简化图片样式:在 CSS 中将 img 的 max-width、margin 等属性调整为你想要的样式。 +### 常见修改点 -## 贡献与许可 +| 需求 | 修改位置 | 说明 | +|------|----------|------| +| 去掉公式支持 | `MarkdownRenderer.jsx` | 移除 `remark-math` / `rehype-katex` 并删 CSS 引入 | +| 去掉代码高亮 | `MarkdownRenderer.jsx` | 移除 `rehype-highlight` 与对应样式 | +| 禁用内联代码特殊样式 | 已内置 | 自定义插件 `remarkDisableInlineCode` 已将 inlineCode 转普通文本 | +| 改图片最大宽度 | `MarkdownRenderer.css` | 调整 `.markdown-image img` | +| 更换高亮主题 | 安装新主题 | 引入其他 highlight.js CSS | +| 调整面包屑 | `fileUtils.generateBreadcrumbs` | 可改分隔符或格式 | + +### 架构 / 数据流程简述 + +``` +┌──────────────┐ 扫描/过滤 ┌────────────────┐ JSON写入 ┌───────────────┐ +│ public/mengya │ ─────────────▶ │ generateData.js │ ───────────▶ │ src/data/*.json │ +│ note/ (原始MD)│ ignore.json │ (Node脚本) │ public/data │ (目录/内容/统计)│ +└──────────────┘ └────────────────┘ └───────────────┘ + │ + ▼ + 前端 (React 渲染) +``` + +前端加载策略:尝试按顺序 fetch:`/data/...` → `/src/data/...` → `./data/...`。 + +### 渲染组件要点 + +- 代码块组件:支持复制、语言标签、降尾换行处理 +- 图片:包裹 `
` + `
` +- 标题:自动生成 `id` + 锚点链接 +- 链接:区分内部/外部,`[[wikilink]]` 保留为文本标签(可扩展) +- 表格:外层包裹 div 实现横向滚动容器 + +### 性能提示 + +- Markdown 数量巨大时,可按需拆分 lazy-load(目前为一次性加载全部 JSON) +- 可拓展为:构建阶段拆分单文件 JSON,运行时按需请求 +- 可增加 Service Worker 缓存静态 JSON + +## ❓ 常见问题(FAQ) + +**Q: 为什么我新增文件后页面没有显示?** +A: 需要重新运行 `npm run generate-data` 或 `npm run dev` 让脚本再生成数据。 + +**Q: 想忽略某个目录但它还是出现?** +A: 确认 `ignore.json` 位于 `public/mengyanote/` 根目录,键名是 `ignore`,数组项不要写路径前缀。 + +**Q: 能否按需加载而不是一次性加载所有内容?** +A: 当前实现为构建期大 JSON。可拓展为“每文件单独 JSON + 动态 fetch”。 + +**Q: 是否支持搜索?** +A: 目前未实现。可通过构建阶段生成反向索引(lunr / minisearch)再前端搜索。 + +**Q: 图片如何放大预览?** +A: 可在 `MarkdownRenderer.jsx` 中为 `img` 包裹 Lightbox 组件或添加点击事件。 + +**Q: 可以改成多语言站点?** +A: 可在数据生成脚本中区分语言目录(如 `en/`、`zh/`),渲染层添加语言切换上下文。 + +## 🧭 Roadmap(计划) + +- [ ] 全文搜索(可选:关键词高亮) +- [ ] 按需加载:文件内容拆分 +- [ ] 文件更新 diff / 最近更新列表 +- [ ] Tag/Frontmatter 支持(YAML 解析) +- [ ] RSS / JSON Feed 输出 +- [ ] 导出 PDF / 打印优化 +- [ ] Service Worker 缓存加速 +- [ ] GitHub Actions 自动部署工作流示例 + +欢迎在 Issue 中补充你的需求。 + +## 🤝 贡献与许可 欢迎提交 Issue 或 Pull Request。仓库包含 `LICENSE`(请查看该文件以确认许可证类型)。 @@ -114,14 +244,5 @@ npm run build - 新功能请先创建 issue 讨论。 - 提交 PR 时附带简短说明和相关截图(如果是 UI 变更)。 -## 联系方式 -如需帮助或定制:在 Issue 中描述你想要的样式和示例图片/链接,我可以帮你修改 `MarkdownRenderer.css` / `MarkdownRenderer.jsx` 实现视觉风格。 - ---- - -祝发布顺利!如果你想,我可以: - -- 帮你把 README 翻译成英文版本并放在 `README.en.md`; -- 或直接替你修改 Markdown 渲染样式(把渲染改成更像你“图片那种”的风格)。 diff --git a/index.html b/index.html index 452075c..e1fde15 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,9 @@ - + - markdown-to-web + 萌芽笔记
diff --git a/public/data/directoryTree.json b/public/data/directoryTree.json new file mode 100644 index 0000000..0e5b08d --- /dev/null +++ b/public/data/directoryTree.json @@ -0,0 +1,1612 @@ +[ + { + "id": "编程语言", + "name": "编程语言", + "type": "folder", + "path": "编程语言", + "children": [ + { + "id": "编程语言/Android", + "name": "Android", + "type": "folder", + "path": "编程语言/Android", + "children": [ + { + "id": "编程语言/Android/安卓Gradle构建常用命令总结.md", + "name": "安卓Gradle构建常用命令总结.md", + "type": "file", + "path": "编程语言/Android/安卓Gradle构建常用命令总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/Android/Linux配置安卓Gradle构建环境.md", + "name": "Linux配置安卓Gradle构建环境.md", + "type": "file", + "path": "编程语言/Android/Linux配置安卓Gradle构建环境.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/C", + "name": "C", + "type": "folder", + "path": "编程语言/C", + "children": [ + { + "id": "编程语言/C/C 代码概述:检查特定条件的素数.md", + "name": "C 代码概述:检查特定条件的素数.md", + "type": "file", + "path": "编程语言/C/C 代码概述:检查特定条件的素数.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C/C语言不设置临时变量交换x和y的值(方法).md", + "name": "C语言不设置临时变量交换x和y的值(方法).md", + "type": "file", + "path": "编程语言/C/C语言不设置临时变量交换x和y的值(方法).md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/C++", + "name": "C++", + "type": "folder", + "path": "编程语言/C++", + "children": [ + { + "id": "编程语言/C++/标准库解析", + "name": "标准库解析", + "type": "folder", + "path": "编程语言/C++/标准库解析", + "children": [ + { + "id": "编程语言/C++/标准库解析/algorithim库二次总结.md", + "name": "algorithim库二次总结.md", + "type": "file", + "path": "编程语言/C++/标准库解析/algorithim库二次总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/标准库解析/algorithm算法库.md", + "name": "algorithm算法库.md", + "type": "file", + "path": "编程语言/C++/标准库解析/algorithm算法库.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/标准库解析/list库-豆包.md", + "name": "list库-豆包.md", + "type": "file", + "path": "编程语言/C++/标准库解析/list库-豆包.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/标准库解析/list库-deepseek.md", + "name": "list库-deepseek.md", + "type": "file", + "path": "编程语言/C++/标准库解析/list库-deepseek.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/标准库解析/queue库.md", + "name": "queue库.md", + "type": "file", + "path": "编程语言/C++/标准库解析/queue库.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/标准库解析/stack库.md", + "name": "stack库.md", + "type": "file", + "path": "编程语言/C++/标准库解析/stack库.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/标准库解析/string库.md", + "name": "string库.md", + "type": "file", + "path": "编程语言/C++/标准库解析/string库.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/标准库解析/vector库.md", + "name": "vector库.md", + "type": "file", + "path": "编程语言/C++/标准库解析/vector库.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/C++/变量使用set,get方法原因.md", + "name": "变量使用set,get方法原因.md", + "type": "file", + "path": "编程语言/C++/变量使用set,get方法原因.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/多个set方法.md", + "name": "多个set方法.md", + "type": "file", + "path": "编程语言/C++/多个set方法.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/暂停1s执行.md", + "name": "暂停1s执行.md", + "type": "file", + "path": "编程语言/C++/暂停1s执行.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/值传递和地址传递的区别.md", + "name": "值传递和地址传递的区别.md", + "type": "file", + "path": "编程语言/C++/值传递和地址传递的区别.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/指针变量的区别.md", + "name": "指针变量的区别.md", + "type": "file", + "path": "编程语言/C++/指针变量的区别.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/指针简单讲解.md", + "name": "指针简单讲解.md", + "type": "file", + "path": "编程语言/C++/指针简单讲解.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/C++关联文件.md", + "name": "C++关联文件.md", + "type": "file", + "path": "编程语言/C++/C++关联文件.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/C++模拟考试.md", + "name": "C++模拟考试.md", + "type": "file", + "path": "编程语言/C++/C++模拟考试.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/C++中的语法糖.md", + "name": "C++中的语法糖.md", + "type": "file", + "path": "编程语言/C++/C++中的语法糖.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/C++/C语言学习笔记.md", + "name": "C语言学习笔记.md", + "type": "file", + "path": "编程语言/C++/C语言学习笔记.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/CSharp", + "name": "CSharp", + "type": "folder", + "path": "编程语言/CSharp", + "children": [ + { + "id": "编程语言/CSharp/mono和dotnet的区别.md", + "name": "mono和dotnet的区别.md", + "type": "file", + "path": "编程语言/CSharp/mono和dotnet的区别.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/Flutter", + "name": "Flutter", + "type": "folder", + "path": "编程语言/Flutter", + "children": [ + { + "id": "编程语言/Flutter/Flutter安卓构建注意事项.md", + "name": "Flutter安卓构建注意事项.md", + "type": "file", + "path": "编程语言/Flutter/Flutter安卓构建注意事项.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/Flutter/Flutter常用命令.md", + "name": "Flutter常用命令.md", + "type": "file", + "path": "编程语言/Flutter/Flutter常用命令.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/Flutter/Flutter构建平台产物位置.md", + "name": "Flutter构建平台产物位置.md", + "type": "file", + "path": "编程语言/Flutter/Flutter构建平台产物位置.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/Java", + "name": "Java", + "type": "folder", + "path": "编程语言/Java", + "children": [ + { + "id": "编程语言/Java/Java基础-导入java文件.md", + "name": "Java基础-导入java文件.md", + "type": "file", + "path": "编程语言/Java/Java基础-导入java文件.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/Python", + "name": "Python", + "type": "folder", + "path": "编程语言/Python", + "children": [ + { + "id": "编程语言/Python/Kivy", + "name": "Kivy", + "type": "folder", + "path": "编程语言/Python/Kivy", + "children": [ + { + "id": "编程语言/Python/Kivy/kivy编译安卓APK.md", + "name": "kivy编译安卓APK.md", + "type": "file", + "path": "编程语言/Python/Kivy/kivy编译安卓APK.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "编程语言/Python/Python国内pip加速镜像.md", + "name": "Python国内pip加速镜像.md", + "type": "file", + "path": "编程语言/Python/Python国内pip加速镜像.md", + "children": [], + "isExpanded": false + }, + { + "id": "编程语言/Python/Pywebview库功能一览.md", + "name": "Pywebview库功能一览.md", + "type": "file", + "path": "编程语言/Python/Pywebview库功能一览.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "计算机科普", + "name": "计算机科普", + "type": "folder", + "path": "计算机科普", + "children": [ + { + "id": "计算机科普/多模态大模型识别图片,视频,音频原理.md", + "name": "多模态大模型识别图片,视频,音频原理.md", + "type": "file", + "path": "计算机科普/多模态大模型识别图片,视频,音频原理.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/光纤和网线的特点和区别.md", + "name": "光纤和网线的特点和区别.md", + "type": "file", + "path": "计算机科普/光纤和网线的特点和区别.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/科普-Nagle 算法.md", + "name": "科普-Nagle 算法.md", + "type": "file", + "path": "计算机科普/科普-Nagle 算法.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/术语科普-CVM.md", + "name": "术语科普-CVM.md", + "type": "file", + "path": "计算机科普/术语科普-CVM.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/术语科普-IT行业的A端B端C端.md", + "name": "术语科普-IT行业的A端B端C端.md", + "type": "file", + "path": "计算机科普/术语科普-IT行业的A端B端C端.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/术语科普-MCU.md", + "name": "术语科普-MCU.md", + "type": "file", + "path": "计算机科普/术语科普-MCU.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/术语科普-pwn.md", + "name": "术语科普-pwn.md", + "type": "file", + "path": "计算机科普/术语科普-pwn.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/clash机场三种代理模式科普.md", + "name": "clash机场三种代理模式科普.md", + "type": "file", + "path": "计算机科普/clash机场三种代理模式科普.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/CPU利用率科普.md", + "name": "CPU利用率科普.md", + "type": "file", + "path": "计算机科普/CPU利用率科普.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/IDEA专业版和社区版的区别和特点.md", + "name": "IDEA专业版和社区版的区别和特点.md", + "type": "file", + "path": "计算机科普/IDEA专业版和社区版的区别和特点.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/sim卡作用及原理.md", + "name": "sim卡作用及原理.md", + "type": "file", + "path": "计算机科普/sim卡作用及原理.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/wan口和lan口的区别与特点.md", + "name": "wan口和lan口的区别与特点.md", + "type": "file", + "path": "计算机科普/wan口和lan口的区别与特点.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/WiFi和蓝牙的异同.md", + "name": "WiFi和蓝牙的异同.md", + "type": "file", + "path": "计算机科普/WiFi和蓝牙的异同.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机科普/x64,x86和amd64区别.md", + "name": "x64,x86和amd64区别.md", + "type": "file", + "path": "计算机科普/x64,x86和amd64区别.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "计算机网络", + "name": "计算机网络", + "type": "folder", + "path": "计算机网络", + "children": [ + { + "id": "计算机网络/网络层次划分.md", + "name": "网络层次划分.md", + "type": "file", + "path": "计算机网络/网络层次划分.md", + "children": [], + "isExpanded": false + }, + { + "id": "计算机网络/TCP的三次握手四次握手.md", + "name": "TCP的三次握手四次握手.md", + "type": "file", + "path": "计算机网络/TCP的三次握手四次握手.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "面试八股", + "name": "面试八股", + "type": "folder", + "path": "面试八股", + "children": [ + { + "id": "面试八股/计算机面试经典八股.md", + "name": "计算机面试经典八股.md", + "type": "file", + "path": "面试八股/计算机面试经典八股.md", + "children": [], + "isExpanded": false + }, + { + "id": "面试八股/Nacos功能与应用场景详解.md", + "name": "Nacos功能与应用场景详解.md", + "type": "file", + "path": "面试八股/Nacos功能与应用场景详解.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "嵌入式", + "name": "嵌入式", + "type": "folder", + "path": "嵌入式", + "children": [ + { + "id": "嵌入式/USB拓展坞接口数量决定因素.md", + "name": "USB拓展坞接口数量决定因素.md", + "type": "file", + "path": "嵌入式/USB拓展坞接口数量决定因素.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "生活科普", + "name": "生活科普", + "type": "folder", + "path": "生活科普", + "children": [ + { + "id": "生活科普/打针和注射原理.md", + "name": "打针和注射原理.md", + "type": "file", + "path": "生活科普/打针和注射原理.md", + "children": [], + "isExpanded": false + }, + { + "id": "生活科普/高铁座位.md", + "name": "高铁座位.md", + "type": "file", + "path": "生活科普/高铁座位.md", + "children": [], + "isExpanded": false + }, + { + "id": "生活科普/OTC药和处方药的区别.md", + "name": "OTC药和处方药的区别.md", + "type": "file", + "path": "生活科普/OTC药和处方药的区别.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "生物学科普", + "name": "生物学科普", + "type": "folder", + "path": "生物学科普", + "children": [ + { + "id": "生物学科普/抗生素杀菌原理及作用机制详解.md", + "name": "抗生素杀菌原理及作用机制详解.md", + "type": "file", + "path": "生物学科普/抗生素杀菌原理及作用机制详解.md", + "children": [], + "isExpanded": false + }, + { + "id": "生物学科普/死亡后的尸体现象与死亡时间推断.md", + "name": "死亡后的尸体现象与死亡时间推断.md", + "type": "file", + "path": "生物学科普/死亡后的尸体现象与死亡时间推断.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "数据结构与算法", + "name": "数据结构与算法", + "type": "folder", + "path": "数据结构与算法", + "children": [ + { + "id": "数据结构与算法/递增序列查询算法总结.md", + "name": "递增序列查询算法总结.md", + "type": "file", + "path": "数据结构与算法/递增序列查询算法总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据结构与算法/二分查找图书馆算法总结.md", + "name": "二分查找图书馆算法总结.md", + "type": "file", + "path": "数据结构与算法/二分查找图书馆算法总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据结构与算法/二分查找右侧边界算法总结.md", + "name": "二分查找右侧边界算法总结.md", + "type": "file", + "path": "数据结构与算法/二分查找右侧边界算法总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据结构与算法/二分查找左侧边界算法总结.md", + "name": "二分查找左侧边界算法总结.md", + "type": "file", + "path": "数据结构与算法/二分查找左侧边界算法总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据结构与算法/快速幂算法(一).md", + "name": "快速幂算法(一).md", + "type": "file", + "path": "数据结构与算法/快速幂算法(一).md", + "children": [], + "isExpanded": false + }, + { + "id": "数据结构与算法/判断素数.md", + "name": "判断素数.md", + "type": "file", + "path": "数据结构与算法/判断素数.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据结构与算法/十大排序算法简介.md", + "name": "十大排序算法简介.md", + "type": "file", + "path": "数据结构与算法/十大排序算法简介.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据结构与算法/跳石头二分算法总结.md", + "name": "跳石头二分算法总结.md", + "type": "file", + "path": "数据结构与算法/跳石头二分算法总结.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "数据库", + "name": "数据库", + "type": "folder", + "path": "数据库", + "children": [ + { + "id": "数据库/json文件储存和MongoDB储存优缺点.md", + "name": "json文件储存和MongoDB储存优缺点.md", + "type": "file", + "path": "数据库/json文件储存和MongoDB储存优缺点.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据库/MongoDB的索引一览.md", + "name": "MongoDB的索引一览.md", + "type": "file", + "path": "数据库/MongoDB的索引一览.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据库/MongoDB数据库优化方式一览.md", + "name": "MongoDB数据库优化方式一览.md", + "type": "file", + "path": "数据库/MongoDB数据库优化方式一览.md", + "children": [], + "isExpanded": false + }, + { + "id": "数据库/MySQL数据库支持的数据类型.md", + "name": "MySQL数据库支持的数据类型.md", + "type": "file", + "path": "数据库/MySQL数据库支持的数据类型.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "游戏引擎", + "name": "游戏引擎", + "type": "folder", + "path": "游戏引擎", + "children": [ + { + "id": "游戏引擎/Godot", + "name": "Godot", + "type": "folder", + "path": "游戏引擎/Godot", + "children": [ + { + "id": "游戏引擎/Godot/BBCode 标签学习.md", + "name": "BBCode 标签学习.md", + "type": "file", + "path": "游戏引擎/Godot/BBCode 标签学习.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Godot/DisplayServer简单总结.md", + "name": "DisplayServer简单总结.md", + "type": "file", + "path": "游戏引擎/Godot/DisplayServer简单总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Godot/godot小代码.md", + "name": "godot小代码.md", + "type": "file", + "path": "游戏引擎/Godot/godot小代码.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Godot/Godot字典的详细用法.md", + "name": "Godot字典的详细用法.md", + "type": "file", + "path": "游戏引擎/Godot/Godot字典的详细用法.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Godot/OS类简单总结.md", + "name": "OS类简单总结.md", + "type": "file", + "path": "游戏引擎/Godot/OS类简单总结.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity", + "name": "Unity", + "type": "folder", + "path": "游戏引擎/Unity", + "children": [ + { + "id": "游戏引擎/Unity/Unity代码片段", + "name": "Unity代码片段", + "type": "folder", + "path": "游戏引擎/Unity/Unity代码片段", + "children": [ + { + "id": "游戏引擎/Unity/Unity代码片段/保留整数.md", + "name": "保留整数.md", + "type": "file", + "path": "游戏引擎/Unity/Unity代码片段/保留整数.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity/Unity代码片段/设置在几个特定点钟随机生成.md", + "name": "设置在几个特定点钟随机生成.md", + "type": "file", + "path": "游戏引擎/Unity/Unity代码片段/设置在几个特定点钟随机生成.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity/Unity代码片段/unity导出到Windows改变窗口.md", + "name": "unity导出到Windows改变窗口.md", + "type": "file", + "path": "游戏引擎/Unity/Unity代码片段/unity导出到Windows改变窗口.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity/Unity代码片段/Unity获取同一场景中其他对象的属性&组件.md", + "name": "Unity获取同一场景中其他对象的属性&组件.md", + "type": "file", + "path": "游戏引擎/Unity/Unity代码片段/Unity获取同一场景中其他对象的属性&组件.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity/Unity代码片段/unity碰撞体撞到指定标签的碰撞体后操作.md", + "name": "unity碰撞体撞到指定标签的碰撞体后操作.md", + "type": "file", + "path": "游戏引擎/Unity/Unity代码片段/unity碰撞体撞到指定标签的碰撞体后操作.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity/Unity代码片段/unity修改物理碰撞层.md", + "name": "unity修改物理碰撞层.md", + "type": "file", + "path": "游戏引擎/Unity/Unity代码片段/unity修改物理碰撞层.md", + "children": [], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity/Unity代码片段/Unity中的单例模式(全局变量).md", + "name": "Unity中的单例模式(全局变量).md", + "type": "file", + "path": "游戏引擎/Unity/Unity代码片段/Unity中的单例模式(全局变量).md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "游戏引擎/Unity/Unity简单解决字体放大模糊问题.md", + "name": "Unity简单解决字体放大模糊问题.md", + "type": "file", + "path": "游戏引擎/Unity/Unity简单解决字体放大模糊问题.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "杂项", + "name": "杂项", + "type": "folder", + "path": "杂项", + "children": [ + { + "id": "杂项/10月23日大学英语笔记.md", + "name": "10月23日大学英语笔记.md", + "type": "file", + "path": "杂项/10月23日大学英语笔记.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/古诗.md", + "name": "古诗.md", + "type": "file", + "path": "杂项/古诗.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/计算机刷题网站.md", + "name": "计算机刷题网站.md", + "type": "file", + "path": "杂项/计算机刷题网站.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/文本颜色测试.md", + "name": "文本颜色测试.md", + "type": "file", + "path": "杂项/文本颜色测试.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md", + "name": "c++如何快速的检测一个字串符在另一个字串符的出现次数.md", + "type": "file", + "path": "杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/markdown格式(没什么用).md", + "name": "markdown格式(没什么用).md", + "type": "file", + "path": "杂项/markdown格式(没什么用).md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/Markdown格式大全.md", + "name": "Markdown格式大全.md", + "type": "file", + "path": "杂项/Markdown格式大全.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/PTA好题-计算众数.md", + "name": "PTA好题-计算众数.md", + "type": "file", + "path": "杂项/PTA好题-计算众数.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/PTA好题-英文单词排序.md", + "name": "PTA好题-英文单词排序.md", + "type": "file", + "path": "杂项/PTA好题-英文单词排序.md", + "children": [], + "isExpanded": false + }, + { + "id": "杂项/PTA万能代码.md", + "name": "PTA万能代码.md", + "type": "file", + "path": "杂项/PTA万能代码.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "AI", + "name": "AI", + "type": "folder", + "path": "AI", + "children": [ + { + "id": "AI/AI提示词工程", + "name": "AI提示词工程", + "type": "folder", + "path": "AI/AI提示词工程", + "children": [ + { + "id": "AI/AI提示词工程/开发前后端分离网站提示词.md", + "name": "开发前后端分离网站提示词.md", + "type": "file", + "path": "AI/AI提示词工程/开发前后端分离网站提示词.md", + "children": [], + "isExpanded": false + }, + { + "id": "AI/AI提示词工程/AI绘画提示词.md", + "name": "AI绘画提示词.md", + "type": "file", + "path": "AI/AI提示词工程/AI绘画提示词.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "AI/阿里云百炼平台模型API调用示例.md", + "name": "阿里云百炼平台模型API调用示例.md", + "type": "file", + "path": "AI/阿里云百炼平台模型API调用示例.md", + "children": [], + "isExpanded": false + }, + { + "id": "AI/大语言模型的API 调用.md", + "name": "大语言模型的API 调用.md", + "type": "file", + "path": "AI/大语言模型的API 调用.md", + "children": [], + "isExpanded": false + }, + { + "id": "AI/大语言模型的API key.md", + "name": "大语言模型的API key.md", + "type": "file", + "path": "AI/大语言模型的API key.md", + "children": [], + "isExpanded": false + }, + { + "id": "AI/Qwen-Code官方文档使用教程.md", + "name": "Qwen-Code官方文档使用教程.md", + "type": "file", + "path": "AI/Qwen-Code官方文档使用教程.md", + "children": [], + "isExpanded": false + }, + { + "id": "AI/Qwen-Code命令行安装使用教程.md", + "name": "Qwen-Code命令行安装使用教程.md", + "type": "file", + "path": "AI/Qwen-Code命令行安装使用教程.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Docker", + "name": "Docker", + "type": "folder", + "path": "Docker", + "children": [ + { + "id": "Docker/优秀好用的Docker镜像", + "name": "优秀好用的Docker镜像", + "type": "folder", + "path": "Docker/优秀好用的Docker镜像", + "children": [ + { + "id": "Docker/优秀好用的Docker镜像/FileCodeBox-文件快递柜.md", + "name": "FileCodeBox-文件快递柜.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/FileCodeBox-文件快递柜.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/Gitea-私有化仓库部署.md", + "name": "Gitea-私有化仓库部署.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/Gitea-私有化仓库部署.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/MongoDB-数据库.md", + "name": "MongoDB-数据库.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/MongoDB-数据库.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/MySQL-数据库.md", + "name": "MySQL-数据库.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/MySQL-数据库.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md", + "name": "NapCat-QQ机器人框架.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/Ntfy-萌芽通知.md", + "name": "Ntfy-萌芽通知.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/Ntfy-萌芽通知.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/Postgres-数据库.md", + "name": "Postgres-数据库.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/Postgres-数据库.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/优秀好用的Docker镜像/Redis-内存数据库.md", + "name": "Redis-内存数据库.md", + "type": "file", + "path": "Docker/优秀好用的Docker镜像/Redis-内存数据库.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Docker/Docker 镜像相关.md", + "name": "Docker 镜像相关.md", + "type": "file", + "path": "Docker/Docker 镜像相关.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/Docker镜像快速迁移.md", + "name": "Docker镜像快速迁移.md", + "type": "file", + "path": "Docker/Docker镜像快速迁移.md", + "children": [], + "isExpanded": false + }, + { + "id": "Docker/Docker命令集合.md", + "name": "Docker命令集合.md", + "type": "file", + "path": "Docker/Docker命令集合.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Github", + "name": "Github", + "type": "folder", + "path": "Github", + "children": [ + { + "id": "Github/Github仓库公共API总结.md", + "name": "Github仓库公共API总结.md", + "type": "file", + "path": "Github/Github仓库公共API总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "Github/Github获取仓库密钥.md", + "name": "Github获取仓库密钥.md", + "type": "file", + "path": "Github/Github获取仓库密钥.md", + "children": [], + "isExpanded": false + }, + { + "id": "Github/linux常用git命令.md", + "name": "linux常用git命令.md", + "type": "file", + "path": "Github/linux常用git命令.md", + "children": [], + "isExpanded": false + }, + { + "id": "Github/Linux下使用git探索.md", + "name": "Linux下使用git探索.md", + "type": "file", + "path": "Github/Linux下使用git探索.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "LeetCode", + "name": "LeetCode", + "type": "folder", + "path": "LeetCode", + "children": [ + { + "id": "LeetCode/力扣-两数之和详解.md", + "name": "力扣-两数之和详解.md", + "type": "file", + "path": "LeetCode/力扣-两数之和详解.md", + "children": [], + "isExpanded": false + }, + { + "id": "LeetCode/力扣1-两数相加问题.md", + "name": "力扣1-两数相加问题.md", + "type": "file", + "path": "LeetCode/力扣1-两数相加问题.md", + "children": [], + "isExpanded": false + }, + { + "id": "LeetCode/力扣2-两数之和.md", + "name": "力扣2-两数之和.md", + "type": "file", + "path": "LeetCode/力扣2-两数之和.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Linux", + "name": "Linux", + "type": "folder", + "path": "Linux", + "children": [ + { + "id": "Linux/Termux", + "name": "Termux", + "type": "folder", + "path": "Linux/Termux", + "children": [ + { + "id": "Linux/Termux/Termux-api用法总结", + "name": "Termux-api用法总结", + "type": "folder", + "path": "Linux/Termux/Termux-api用法总结", + "children": [ + { + "id": "Linux/Termux/Termux-api用法总结/弹窗.md", + "name": "弹窗.md", + "type": "file", + "path": "Linux/Termux/Termux-api用法总结/弹窗.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Termux/Termux-api用法总结/录音.md", + "name": "录音.md", + "type": "file", + "path": "Linux/Termux/Termux-api用法总结/录音.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Termux/Termux-api用法总结/闪光灯.md", + "name": "闪光灯.md", + "type": "file", + "path": "Linux/Termux/Termux-api用法总结/闪光灯.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Termux/Termux-api用法总结/所有支持的api.md", + "name": "所有支持的api.md", + "type": "file", + "path": "Linux/Termux/Termux-api用法总结/所有支持的api.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Linux/Termux/shell2http举例.md", + "name": "shell2http举例.md", + "type": "file", + "path": "Linux/Termux/shell2http举例.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Termux/shell2HTTP软件简单总结.md", + "name": "shell2HTTP软件简单总结.md", + "type": "file", + "path": "Linux/Termux/shell2HTTP软件简单总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Termux/termux的pkg命令总结.md", + "name": "termux的pkg命令总结.md", + "type": "file", + "path": "Linux/Termux/termux的pkg命令总结.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Linux/把Ubuntu镜像源切换到阿里云.md", + "name": "把Ubuntu镜像源切换到阿里云.md", + "type": "file", + "path": "Linux/把Ubuntu镜像源切换到阿里云.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/编译alist.md", + "name": "编译alist.md", + "type": "file", + "path": "Linux/编译alist.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/编译busybox步骤.md", + "name": "编译busybox步骤.md", + "type": "file", + "path": "Linux/编译busybox步骤.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/飞牛os切换root.md", + "name": "飞牛os切换root.md", + "type": "file", + "path": "Linux/飞牛os切换root.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/构建最小Linux系统.md", + "name": "构建最小Linux系统.md", + "type": "file", + "path": "Linux/构建最小Linux系统.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/某安卓板子不知名初始化脚本.md", + "name": "某安卓板子不知名初始化脚本.md", + "type": "file", + "path": "Linux/某安卓板子不知名初始化脚本.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/手动配置alist.md", + "name": "手动配置alist.md", + "type": "file", + "path": "Linux/手动配置alist.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/树萌芽常用Linux命令集合.md", + "name": "树萌芽常用Linux命令集合.md", + "type": "file", + "path": "Linux/树萌芽常用Linux命令集合.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/树萌芽的局域网中网IP分配.md", + "name": "树萌芽的局域网中网IP分配.md", + "type": "file", + "path": "Linux/树萌芽的局域网中网IP分配.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/我想全局执行某个sh脚本,该放在Linux哪个目录.md", + "name": "我想全局执行某个sh脚本,该放在Linux哪个目录.md", + "type": "file", + "path": "Linux/我想全局执行某个sh脚本,该放在Linux哪个目录.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/busybox v1.36命令简介.md", + "name": "busybox v1.36命令简介.md", + "type": "file", + "path": "Linux/busybox v1.36命令简介.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/busybox玩法总结.md", + "name": "busybox玩法总结.md", + "type": "file", + "path": "Linux/busybox玩法总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/crontab的使用.md", + "name": "crontab的使用.md", + "type": "file", + "path": "Linux/crontab的使用.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/docker,LXC,qemu,k8s,chroot等的特点.md", + "name": "docker,LXC,qemu,k8s,chroot等的特点.md", + "type": "file", + "path": "Linux/docker,LXC,qemu,k8s,chroot等的特点.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/docker配置.md", + "name": "docker配置.md", + "type": "file", + "path": "Linux/docker配置.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/frp配置.md", + "name": "frp配置.md", + "type": "file", + "path": "Linux/frp配置.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Git常用命令.md", + "name": "Git常用命令.md", + "type": "file", + "path": "Linux/Git常用命令.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux zip 命令总结.md", + "name": "Linux zip 命令总结.md", + "type": "file", + "path": "Linux/Linux zip 命令总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/linux安装nodejs22.md", + "name": "linux安装nodejs22.md", + "type": "file", + "path": "Linux/linux安装nodejs22.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux安装ollama.md", + "name": "Linux安装ollama.md", + "type": "file", + "path": "Linux/Linux安装ollama.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux不同格式解压命令.md", + "name": "Linux不同格式解压命令.md", + "type": "file", + "path": "Linux/Linux不同格式解压命令.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux查看无线网口.md", + "name": "Linux查看无线网口.md", + "type": "file", + "path": "Linux/Linux查看无线网口.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux常用软件包安装.md", + "name": "Linux常用软件包安装.md", + "type": "file", + "path": "Linux/Linux常用软件包安装.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux的Proc目录解析.md", + "name": "Linux的Proc目录解析.md", + "type": "file", + "path": "Linux/Linux的Proc目录解析.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux复制文件命令.md", + "name": "Linux复制文件命令.md", + "type": "file", + "path": "Linux/Linux复制文件命令.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux后台运行程序.md", + "name": "Linux后台运行程序.md", + "type": "file", + "path": "Linux/Linux后台运行程序.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux命令风格解析.md", + "name": "Linux命令风格解析.md", + "type": "file", + "path": "Linux/Linux命令风格解析.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux软件包存放地址.md", + "name": "Linux软件包存放地址.md", + "type": "file", + "path": "Linux/Linux软件包存放地址.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux下的scp命令总结.md", + "name": "Linux下的scp命令总结.md", + "type": "file", + "path": "Linux/Linux下的scp命令总结.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Linux一些奇奇怪怪的命令.md", + "name": "Linux一些奇奇怪怪的命令.md", + "type": "file", + "path": "Linux/Linux一些奇奇怪怪的命令.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/nodejsmarkdown库.md", + "name": "nodejsmarkdown库.md", + "type": "file", + "path": "Linux/nodejsmarkdown库.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/QQ机器人napcat命令.md", + "name": "QQ机器人napcat命令.md", + "type": "file", + "path": "Linux/QQ机器人napcat命令.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/screen常用指令.md", + "name": "screen常用指令.md", + "type": "file", + "path": "Linux/screen常用指令.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/SSH服务端配置.md", + "name": "SSH服务端配置.md", + "type": "file", + "path": "Linux/SSH服务端配置.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/systemctl命令详细总结-豆包.md", + "name": "systemctl命令详细总结-豆包.md", + "type": "file", + "path": "Linux/systemctl命令详细总结-豆包.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Termux-SSH相关.md", + "name": "Termux-SSH相关.md", + "type": "file", + "path": "Linux/Termux-SSH相关.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/ubuntu设置root登陆.md", + "name": "ubuntu设置root登陆.md", + "type": "file", + "path": "Linux/ubuntu设置root登陆.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/Windows文件一键上传到Linux.md", + "name": "Windows文件一键上传到Linux.md", + "type": "file", + "path": "Linux/Windows文件一键上传到Linux.md", + "children": [], + "isExpanded": false + }, + { + "id": "Linux/wlan0简单介绍.md", + "name": "wlan0简单介绍.md", + "type": "file", + "path": "Linux/wlan0简单介绍.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Minecraft", + "name": "Minecraft", + "type": "folder", + "path": "Minecraft", + "children": [ + { + "id": "Minecraft/Minecraft常用命令.md", + "name": "Minecraft常用命令.md", + "type": "file", + "path": "Minecraft/Minecraft常用命令.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "Obsidion", + "name": "Obsidion", + "type": "folder", + "path": "Obsidion", + "children": [ + { + "id": "Obsidion/Obsidion美化.md", + "name": "Obsidion美化.md", + "type": "file", + "path": "Obsidion/Obsidion美化.md", + "children": [], + "isExpanded": false + } + ], + "isExpanded": false + }, + { + "id": "首页.md", + "name": "首页.md", + "type": "file", + "path": "首页.md", + "children": [], + "isExpanded": false + } +] \ No newline at end of file diff --git a/public/data/fileContents.json b/public/data/fileContents.json new file mode 100644 index 0000000..01e1469 --- /dev/null +++ b/public/data/fileContents.json @@ -0,0 +1,165 @@ +{ + "AI/AI提示词工程/AI绘画提示词.md": "*by 树萌芽*\n\n**图片风格为2D像素像素化风格,比例 「1:1」 画一个游戏道具,背景是纯黑色,纯黑色** \n**不带任何文字,没有任何文字,现在我要你画 一个闪闪发光的金黄色金币卡**\n\n\n**图片风格为2D像素风格,比例 「1:1」 画一个游戏元素,风格为2.5D 就是上帝视角,就是正交斜视角那种有立体感,背景是纯黑色,纯黑色 不带任何文字,现在我要你画一个** \n**一丛茂密的灌木丛 记住一定要3d立体感 只要 灌木丛 只要 灌木丛!**\n\n\n比例 「1:1」图片风格为2D像素风格, 画一个游戏装饰元素,风格为2.5D 就是上帝视角,就是正交斜视角那种有立体感,背景是纯黑色,纯黑色 不带任何文字,现在我要你画一个 占卜测运算命台 相关的装饰可以多一点 记住一定要3d立体感 ", + "AI/AI提示词工程/开发前后端分离网站提示词.md": "1.取消CORS跨域限制,允许任何链接\n2.前端使用React框架,后端使用python的Flask框架\n3.前端修改在frontend文件夹,后端修改在backend文件夹", + "AI/Qwen-Code命令行安装使用教程.md": "**Qwen Code** 是一个 CLI 工具,修改自 **Gemini CLI**,针对 Qwen3‑Coder系列的模型增强了解析器和工具支持。\n\n确保已安装 Node.js 20 及以上版本,可以通过以下命令安装:\n\n```bash\ncurl -qL https://www.npmjs.com/install.sh | sh\n```\n\n然后通过 npm 管理器安装 Qwen Code:\n\n```bash\nnpm i -g @qwen-code/qwen-code\n```\n\n> 另一种方式是从源码安装:\n> \n> ```bash\n> git clone https://github.com/QwenLM/qwen-code.git\n> cd qwen-code && npm install && npm install -g\n> ```\n\nQwen Code 支持 OpenAI SDK 调用 LLM,你可以导出以下环境变量,或者简单地将其放在 `.envfile` 中。\n\n```bash\nexport OPENAI_API_KEY=\"your_api_key_here\"\nexport OPENAI_BASE_URL=\"https://dashscope.aliyuncs.com/compatible-mode/v1\"\nexport OPENAI_MODEL=\"qwen3-coder-plus\"\n```\n\n现在,你可以通过简单地输入 **`qwen`** 来享受 Qwen-Code 和 Qwen 带来的编程体验。\n\n### Claude Code\n\n除了 Qwen Code 之外,现在还可以将 Qwen3‑Coder 与 Claude Code 搭配使用。只需在[阿里云百炼](https://bailian.console.aliyun.com/)平台申请 API Key,并安装 Claude Code,即可开始畅享编码体验。\n\n```bash\nnpm install -g @anthropic-ai/claude-code\n```\n\n我们提供了两种接入方式,帮助你无缝地用 Qwen3‑Coder 进行编码。\n\n#### 使用dashscope提供的代理  API\n\n只需要将Anthropic的base url替换成dashscope上提供的endpoint即可。\n\n```bash\nexport ANTHROPIC_BASE_URL=https://dashscope.aliyuncs.com/api/v2/apps/claude-code-proxy\nexport ANTHROPIC_AUTH_TOKEN=your-dashscope-apikey\n```\n\n可选方案 2:使用 claude-code-config 自定义路由\n\n#### Optional 2: 使用 claude-code-config 自定义路由\n\nclaude-code-router 是一个第三方的路由工具,用于为 Claude Code 灵活地切换不同的后端 API。dashScope平台提供了一个简单的扩展包 claude-code-config,可为 claude-code-router 生成包含 dashScope 支持的默认配置。\n\n```bash\nnpm install -g @musistudio/claude-code-router\nnpm install -g @dashscope-js/claude-code-config\n```\n\n生成配置文件和插件目录:\n\n```bash\nccr-dashscope\n```\n\n该命令会自动生成 ccr 所需的配置文件和插件目录。你也可以手动调整 ~/.claude-code-router/config.json 和 ~/.claude-code-router/plugins/ 中的配置。\n\n最后,通过 ccr 开始使用 Claude Code:\n\n```bash\nccr code\n```\n\n至此,你即可通过 ccr 使用 Claude Code 畅享 Qwen3‑Coder 的强大编码能力。祝开发顺利!\n\n### Cline\n\n配置 Qwen3-Coder-480B-A35B-instruct 以使用 cline ‒ 进入 cline 的配置设置 ‒ 选择“OpenAI Compatible”模式 ‒ 在 OpenAI Compatible API tokens处,输入从 Dashscope 获取的密钥 ‒ 勾选“使用自定义基础 URL”,并输入:`https://dashscope.aliyuncs.com/compatible-mode/v1` ‒ 输入模型名称:`qwen3-coder-plus`", + "AI/Qwen-Code官方文档使用教程.md": "\n---\n\nQwen Code 是一款专为 **Qwen3-Coder** 模型优化的命令行 AI 工作流工具,通过先进的代码理解能力、自动化任务和智能辅助功能,显著提升开发效率。\n\n---\n\n## 🛠 操作步骤\n\n### 1️⃣ 获取阿里云百炼 API Key\n\n1. 登录 **阿里云百炼大模型服务平台**。\n \n2. 如果页面顶部显示 **image**,说明需要开通服务。\n \n - 开通后可领取新人免费额度(30~180天)。\n \n - 如果提示 **实名认证**,请先完成认证。\n \n3. 免费额度详情可在 **新人免费额度页面** 查看。\n \n4. 获取 **阿里云百炼 API Key**。\n \n\n---\n\n### 2️⃣ 选择模型\n\nQwen Code 支持 **OpenAI 兼容接口模型**,包括:\n\n- 🌟 **qwen3-coder-plus**(推荐,2025年7月23日起限时优惠)\n \n- qwen3-coder-480b-a35b-instruct\n \n- qwen3-coder-flash\n \n- qwen3-coder-30b-a3b-instruct\n \n\n---\n\n### 3️⃣ 安装与配置 Qwen Code\n\n#### ✅ Node.js 版本检查\n\n```bash\nnode -v\n```\n\n需 **Node.js 20+**,低于则需重新安装。\n\n#### 📦 安装 Qwen Code\n\n```bash\n# 配置镜像源加速\nnpm config set registry https://registry.npmmirror.com\n\n# 安装 Qwen Code\nnpm install -g @qwen-code/qwen-code@latest\n```\n\n---\n\n### 4️⃣ 启动并配置 Qwen Code\n\n1. 在终端中输入:\n \n ```bash\n qwen\n ```\n \n2. 选择认证方式 → **OpenAI**\n \n3. 填写以下信息:\n \n\n|配置项|说明|\n|---|---|\n|🔑 API Key|阿里云百炼 API Key|\n|🌐 Base URL|`https://dashscope.aliyuncs.com/compatible-mode/v1`|\n|🤖 Model|推荐 `qwen3-coder-plus`|\n\n👉 若不想每次都输入,请配置 **环境变量**。\n\n---\n\n### 5️⃣ 配置环境变量\n\n在系统中设置:\n\n```bash\nexport OPENAI_API_KEY=你的APIKey\nexport OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1\nexport OPENAI_MODEL=qwen3-coder-plus\n```\n\n---\n\n### 6️⃣ 向 Qwen Code 提问\n\n💡 示例问题:\n\n```\n如何用python实现一个二叉搜索树?\n```\n\nQwen Code 会自动创建文件、写入并执行代码。\n\n---\n\n### 7️⃣ 查看 Token 消耗\n\n输入:\n\n```bash\n/stats model\n```\n\n即可查看本次启动后的 **Token 消耗** 与 **API 调用次数**。\n\n---\n\n## 🎁 免费额度\n\n- 阿里云百炼:**每个模型 100 万免费 Token**\n \n- Qwen Code:**每天 2000 次免费调用**\n \n\n👉 为避免额外消费,可开启 **免费额度用完即停** 按钮。\n\n---\n\n## 🔧 进阶操作\n\n更多功能请参考:\n\n- 📘 [Qwen Code 文档]\n \n- 📘 [阿里云百炼代码能力]\n \n\n---\n\n## ❓ 常见问题 (FAQ)\n\n### ❓ Q:为什么 Token 消耗快?\n\n✅ A:可能多次调用 API。 \n👉 控制方法:\n\n- 精简工作目录(避免在项目根目录运行)。\n \n- 设置 Token 限额:\n \n\n```json\n{\n \"sessionTokenLimit\": 32000\n}\n```\n\n- 使用指令:\n \n - `/compress` → 压缩对话历史\n \n - `/clear` → 清空历史\n \n\n---\n\n### ❓ Q:如何切换模型?\n\n- 未配置环境变量:\n \n 1. `/quit` 退出\n \n 2. `qwen` 重新启动,手动输入 API Key、Base URL、模型名\n \n- 已配置环境变量:\n \n 1. 修改 `OPENAI_MODEL`\n \n 2. `/quit` → `qwen` 重启\n \n\n---\n\n### ❓ Q:如何使用每天 2000 次免费额度?\n\n- 输入 `/auth` → 选择 **Qwen Oauth** → 登录 **Qwen Chat**\n \n- 每天可免费调用 `qwen3-coder-plus` **2000 次**\n \n- 超过 2000 次 → 切换回 **OpenAI 认证方式**\n \n\n---\n\n### ❓ Q:为什么报 `401 Incorrect API key provided` 错误?\n\n✅ 检查以下:\n\n- API Key 是否正确\n \n- 是否有全局环境变量覆盖了配置文件\n \n\n---", + "AI/大语言模型的API key.md": "#### deepseek :\n**调用密钥:**\nsk-832f8e5250464de08a31523c7fd71295\n**调用地址:**\nhttps://api.deepseek.com\n**调用模型:**\ndeepseek-chat \ndeepseek-reasoner\n\n\n\n阿里云百炼大模型平台:\n通用秘钥:sk-3d9e8e02a3704868b1a7159d52f2643d\n\n\n字节火山方舟模型控制台:\n通用秘钥:fc439240-ed3c-4e65-acaf-3541c66c6ebc\n\n\n#### Kimi :\n**调用密钥:**\nsk-zdg9NBpTlhOcDDpoWfaBKu0KNDdGv18SipORnL2utawja0bE\n**调用地址:**\nhttps://api.moonshot.cn\n**调用模型:**\nkimi-k2-0905-preview \nkimi-k2-0711-preview\nkimi-k2-turbo-preview 这个非常贵\nkimi-latest-8k 支持图片理解\nkimi-latest-32k\nkimi-latest-128k 这个非常贵\n", + "AI/大语言模型的API 调用.md": "deepseek api秘钥:\n调用密钥:\nsk-16e24c16ff894771849ee6e15d4fb301\n调用地址:\nhttps://api.deepseek.com\n\n阿里云百炼大模型平台:\n通用秘钥:\nsk-3d9e8e02a3704868b1a7159d52f2643d\n调用地址:\nhttps://dashscope.aliyuncs.com/compatible-mode/v1\n\n字节火山方舟模型控制台:\n通用秘钥:\nfc439240-ed3c-4e65-acaf-3541c66c6ebc\n调用地址:\nhttps://ark.cn-beijing.volces.com/api/v3/chat/completions\n\nkimi API调用:\n调用密钥:\nsk-32M3DYWQdPlftpaGOmIuS7OFKzqCiSutktFPxPqTWn3oFadM\n调用地址:\nhttps://api.moonshot.cn", + "AI/阿里云百炼平台模型API调用示例.md": "\n### **Python调用示例:**\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n api_key=os.getenv(\"DASHSCOPE_API_KEY\"), # 如果您没有配置环境变量,请在此处用您的API Key进行替换\n base_url=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n)\ncompletion = client.chat.completions.create(\n model=\"qwen3-coder-plus\",\n messages=[\n {'role': 'system', 'content': 'You are a helpful assistant.'},\n {'role': 'user', 'content': '请编写一个Python函数 find_prime_numbers,该函数接受一个整数 n 作为参数,并返回一个包含所有小于 n 的质数(素数)的列表。质数是指仅能被1和其自身整除的正整数,如2, 3, 5, 7等。不要输出非代码的内容。'}],\n )\nprint(\"=\"*20+\"回复内容\"+\"=\"*20)\nprint(completion.choices[0].message.content)\nprint(\"=\"*20+\"Token消耗\"+\"=\"*20)\nprint(completion.usage)\n```\n**返回结果示例:**\n````plaintext\n====================回复内容====================\n```python\ndef find_prime_numbers(n):\n if n <= 2:\n return []\n \n primes = []\n \n for num in range(2, n):\n is_prime = True\n for i in range(2, int(num ** 0.5) + 1):\n if num % i == 0:\n is_prime = False\n break\n if is_prime:\n primes.append(num)\n \n return primes\n```\n====================Token消耗====================\nCompletionUsage(completion_tokens=95, prompt_tokens=91, total_tokens=186, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0))\n````\n\n\n\ncurl调用示例:\n```curl\ncurl -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \\\n-H \"Authorization: Bearer $DASHSCOPE_API_KEY\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\n \"model\": \"qwen3-coder-plus\",\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a helpful assistant.\"\n },\n {\n \"role\": \"user\", \n \"content\": \"请编写一个Python函数 find_prime_numbers,该函数接受一个整数 n 作为参数,并返回一个包含所有小于 n 的质数(素数)的列表。质数是指仅能被1和其自身整除的正整数,如2, 3, 5, 7等。不要输出非代码的内容。\"\n }\n ]\n}'\n```\n\n\n返回结果示例:\n```json\n{\n \"choices\": [\n {\n \"message\": {\n \"content\": \"```python\\ndef find_prime_numbers(n):\\n if n <= 2:\\n return []\\n \\n primes = []\\n \\n for num in range(2, n):\\n is_prime = True\\n for i in range(2, int(num ** 0.5) + 1):\\n if num % i == 0:\\n is_prime = False\\n break\\n if is_prime:\\n primes.append(num)\\n \\n return primes\\n```\",\n \"role\": \"assistant\"\n },\n \"finish_reason\": \"stop\",\n \"index\": 0,\n \"logprobs\": null\n }\n ],\n \"object\": \"chat.completion\",\n \"usage\": {\n \"prompt_tokens\": 91,\n \"completion_tokens\": 95,\n \"total_tokens\": 186,\n \"prompt_tokens_details\": {\n \"cached_tokens\": 0\n }\n },\n \"created\": 1753192010,\n \"system_fingerprint\": null,\n \"model\": \"qwen3-coder-plus\",\n \"id\": \"chatcmpl-798c99c2-7410-9cc4-8385-6dfd757757fa\"\n}\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", + "Docker/Docker 镜像相关.md": "\n**QQ机器人框架NapCat**\n```shell\n#安装\ndocker run -d \\\n-e NAPCAT_GID=$(id -g) \\\n-e NAPCAT_UID=$(id -u) \\\n-p 4080:3000 \\\n-p 4070:3001 \\\n-p 4060:6099 \\\n--name napcat \\\n--restart=always \\\nmlikiowa/napcat-docker:latest\n\n#固化以下路径,方便掉线时快速重新登录\n#QQ 持久化数据路径:/app/.config/QQ\n#NapCat 配置文件路径: /app/napcat/config\n\n#登录 WebUI 后台地址:http://<宿主机ip>:6099/webui\n```\n\n**网页SSH客户端-EasyNode**\n```shell\n#项目地址:https://github.com/chaos-zhu/easynode\n\n# 1. 创建easynode目录\nmkdir -p /root/easynode && cd /root/easynode\n\n# 2. 下载docker-compose.yml文件\nwget https://git.221022.xyz/https://raw.githubusercontent.com/chaos-zhu/easynode/main/docker-compose.yml\n\n# 3. 启动服务\ndocker-compose up -d\n\ndocker run -d -p 8082:8082 --restart=always -v /root/easynode/db:/easynode/app/db chaoszhu/easynode\n\n### 监控服务\n#安装\n# 使用默认端口22022安装\ncurl -o- https://git.221022.xyz/https://raw.githubusercontent.com/chaos-zhu/easynode/main/client/easynode-client-install.sh | bash\n\n# 使用自定义端口安装, 例如54321\ncurl -o- https://git.221022.xyz/https://raw.githubusercontent.com/chaos-zhu/easynode/main/client/easynode-client-install.sh | bash -s -- 54321\n\n#卸载\ncurl -o- https://git.221022.xyz/https://raw.githubusercontent.com/chaos-zhu/easynode/main/client/easynode-client-uninstall.sh | bash\n\n#查看监控服务状态:systemctl status easynode-client \n#查看监控服务日志: journalctl --follow -u easynode-client \n#查看详细日志:journalctl -xe\n```\n\n**docker加速地址**\n\n![[Screenshot_20250717_225309.jpg]]\n\n\ndocker.1ms.run/\n\ndocker run -d -p 4050:80 --restart=always -v /shumengya/tu:/var/www/html docker.1ms.run/oaooa/pichome\n\n\n\n\n\n\n\n", + "Docker/Docker命令集合.md": "\ndocker-compose up -d\n\ndocker-compose down\n\ndocker-compose restart\n\ndocker-compose logs -f\n\ndocker-compose ps \n\ndocker-compose build --no-cache\n\n\n**Docker容器一键更新到最新版镜像(以60s API举例)**\n```bash\n#拉取最新镜像\ndocker pull vikiboss/60s:latest \ndocker pull mlikiowa/napcat-docker:latest\ndocker pull couchdb:latest #Obsidian同步的数据库\ndocker pull aceberg/watchyourlan #扫描局域网的工具\n\ndocker pull dpanel/dpanel:latest\n\n\n#停止并删除旧容器\ndocker stop 60s\ndocker rm 60s\ndocker stop napcat\ndocker rm napcat\n\n#兰空图床免费版\ndocker run -d \\\n --name lsky-pro \\\n -p 8089:80 \\\n -v /shumengya/docker/storage/lsky:/var/www/html \\\n --restart=always \\\n halcyonazure/lsky-pro:latest\n\n\n\n\n\n\n\n\n#可视化Docker面板\ndocker run -d \\\n --name dpanel \\\n -p 8800:8080 \\\n -v /var/run/docker.sock:/var/run/docker.sock \\\n -v /shumengya/docker/storage/dpanel:/dpanel/data \\\n --restart=always \\\n dpanel/dpanel:latest\n\n\n\n#扫描局域网的工具\ndocker run -d \\\n --name watch-your-lan \\\n --restart unless-stopped \\\n --net=host \\\n -e TZ=Asia/Shanghai \\\n -v /shumengya/docker/storage/watchyourlan:/data \\\n aceberg/watchyourlan\n\n#Obsidian 同步数据库\ndocker run -d \\\n --name obsidian-couchdb \\\n -e COUCHDB_USER=shumengya \\\n -e COUCHDB_PASSWORD='tyh@19900420' \\\n -p 5984:5984 \\\n couchdb:latest\n\n#60s api后端\ndocker run -d \\\n --restart always \\\n --name 60s \\\n -p 4399:4399 \\\n vikiboss/60s:latest\n \n#napcat QQ机器人\ndocker run -d \\\n --name napcat \\\n --restart=always \\\n -e NAPCAT_GID=$(id -g) \\\n -e NAPCAT_UID=$(id -u) \\\n -p 4080:3000 \\\n -p 4070:3001 \\\n -p 4060:6099 \\\n -v /shumengya/docker/storage/napcat/qq:/app/.config/QQ \\\n -v /shumengya/docker/storage/napcat/config:/app/napcat/config \\\n mlikiowa/napcat-docker:latest\n\n\n\n\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", + "Docker/Docker镜像快速迁移.md": "\n---\n\n## ✅ 方法一:直接导出容器(container → tar)\n\n如果你运行的是一个 **容器**(而不是镜像),可以直接打包它:\n\n```bash\n# 导出容器\ndocker export <容器ID或名字> -o container.tar\n\n# 在另一台Linux机器上导入\ndocker import container.tar new-image:latest\n```\n\n特点:\n\n- 容器的运行时文件系统会被打包(包含你安装的软件和修改),**但不会包含容器的历史层和环境变量**。\n \n- 类似于“快照”迁移。\n \n\n---\n\n## ✅ 方法二:保存镜像(image → tar)\n\n如果你已经把容器做成了一个镜像,建议用 **save/load**:\n\n```bash\n# 在源主机上保存镜像\ndocker save -o myimage.tar myimage:latest\ndocker save -o frpc-1panel.tar snowdreamtech/frpc:0.63.0\n\n# 拷贝到目标主机(比如用 scp)\nscp myimage.tar user@remote:/path/\n\n# 在目标主机导入\ndocker load -i myimage.tar\n```\n\n特点:\n\n- 保留镜像层和构建历史。\n \n- 推荐这种方式。\n \n\n---\n\n", + "Docker/优秀好用的Docker镜像/FileCodeBox-文件快递柜.md": "\n```bash\ndocker run -d \\\n --name filecodebox \\\n --restart=always \\\n -p 12345:12345 \\\n -v /shumengya/docker/storage/filecodebox:/app/data \\\n lanol/filecodebox:beta\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull lanol/filecodebox:beta\n```\n\n```\ndocker stop lanol/filecodebox:beta\ndocker rm lanol/filecodebox:beta\n```", + "Docker/优秀好用的Docker镜像/Gitea-私有化仓库部署.md": "\n```bash\n#github/gitlab的本地轻量化部署代替-gitea\ndocker run -d \\\n --name gitea \\\n -p 8989:3000 \\\n -p 8022:22 \\\n -e USER_UID=1000 \\\n -e USER_GID=1000 \\\n -v /shumengya/docker/storage/gitea:/data \\\n --restart=always \\\n gitea/gitea:latest\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull gitea/gitea:latest\n```\n\n```\ndocker stop gitea/gitea:latest\ndocker rm gitea/gitea:latest\n```", + "Docker/优秀好用的Docker镜像/MongoDB-数据库.md": "\n```bash\n#MongoDB数据库\ndocker run -d --name mongodb \\\n -e MONGO_INITDB_ROOT_USERNAME=shumengya \\\n -e MONGO_INITDB_ROOT_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mongodb:/data/db \\\n -p 27017:27017 \\\n mongo\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull mongo \n```", + "Docker/优秀好用的Docker镜像/MySQL-数据库.md": "\n```bash\ndocker run -d \\\n --name mysql \\\n -e MYSQL_ROOT_PASSWORD=shumengya520 \\\n -e MYSQL_DATABASE=shumengyadb \\\n -e MYSQL_USER=shumengya \\\n -e MYSQL_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mysql:/var/lib/mysql \\\n -p 3306:3306 \\\n --restart=always \\\n mysql:latest\n \n \ndocker run -d \\\n --name mysql \\\n -e MYSQL_ROOT_PASSWORD=shumengya520 \\\n -e MYSQL_DATABASE=shumengyadb \\\n -e MYSQL_USER=shumengya \\\n -e MYSQL_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mysql:/var/lib/mysql \\\n -p 3306:3306 \\\n --restart=always \\\n mysql:5.7.44\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull mysql:5.7.44\n```\n\n```\ndocker stop mysql\ndocker rm mysql\n```", + "Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md": "\n```bash\ndocker run -d \\\n --name filecodebox \\\n --restart=always \\\n -p 12345:12345 \\\n -v /shumengya/docker/storage/filecodebox:/app/data \\\n lanol/filecodebox:beta\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull lanol/filecodebox:beta\n```\n\n```\ndocker stop lanol/filecodebox:beta\ndocker rm lanol/filecodebox:beta\n```", + "Docker/优秀好用的Docker镜像/Ntfy-萌芽通知.md": "\n```bash\ndocker run -d \\\n --name ntfy \\\n --restart=always \\\n -e TZ=\"Asia/Shanghai\" \\\n -e NTFY_BASE_URL=\"https://ntfy.shumengya.top\" \\\n -e NTFY_CACHE_FILE=\"/var/cache/ntfy/cache.db\" \\\n -e NTFY_AUTH_FILE=\"/var/lib/ntfy/auth.db\" \\\n -e NTFY_AUTH_DEFAULT_ACCESS=\"deny-all\" \\\n -e NTFY_BEHIND_PROXY=\"true\" \\\n -e NTFY_ATTACHMENT_CACHE_DIR=\"/var/lib/ntfy/attachments\" \\\n -e NTFY_ENABLE_LOGIN=\"true\" \\\n -v /shumengya/docker/storage/ntfy/cache:/var/cache/ntfy \\\n -v /shumengya/docker/storage/ntfy/etc:/etc/ntfy \\\n -v /shumengya/docker/storage/ntfy/lib:/var/lib/ntfy \\\n -p 82:80 \\\n binwiederhier/ntfy:latest \\\n serve\n\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull binwiederhier/ntfy:latest\n```\n\n```\ndocker stop binwiederhier/ntfy:latest\ndocker rm binwiederhier/ntfy:latest\n```", + "Docker/优秀好用的Docker镜像/Postgres-数据库.md": "\n```bash\n#postgres数据库\ndocker run -d \\\n --name postgres \\\n -e POSTGRES_PASSWORD=shumengya520 \\\n -e POSTGRES_USER=shumengya \\\n -e POSTGRES_DB=shumengyadb \\\n -v /shumengya/docker/storage/postgres:/data \\\n -e PGDATA=/data/pgdata \\\n -p 5432:5432 \\\n --restart=always \\\n postgres:latest\n\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull postgres:latest\n```\n\n```\ndocker stop postgres:latest\ndocker rm postgres:latest\n```", + "Docker/优秀好用的Docker镜像/Redis-内存数据库.md": "\n```bash\n#MongoDB数据库\ndocker run -d --name mongodb \\\n -e MONGO_INITDB_ROOT_USERNAME=shumengya \\\n -e MONGO_INITDB_ROOT_PASSWORD=shumengya520 \\\n -v /shumengya/docker/storage/mongodb:/data/db \\\n -p 27017:27017 \\\n mongo\n```\n\n```bash\n#典型的非关系型数据库(json)\ndocker pull mongo \n```", + "Github/Github仓库公共API总结.md": "\n---\n\n## Releases(发行版本)相关接口\n\n- **获取最新发布版本(Latest Release)** \n `GET /repos/{owner}/{repo}/releases/latest` \n 返回最新非预发布、非草稿版的发布详情,包括版本号、发布时间、说明等。([GitHub Docs](https://docs.github.com/en/rest/releases?utm_source=chatgpt.com \"REST API endpoints for releases and release assets\"))\n \n- **列出所有发布版本(List Releases)** \n `GET /repos/{owner}/{repo}/releases` \n 返回该仓库所有发布版本的列表,不包含未关联发布的普通 Git 标签。([GitHub Docs](https://docs.github.com/en/rest/releases/releases?utm_source=chatgpt.com \"REST API endpoints for releases\"))\n \n- **通过 Tag 获取指定发布版本(Get a Release by Tag)** \n `GET /repos/{owner}/{repo}/releases/tags/{tag}` \n 根据具体 tag 名称获取对应发布版本的信息。([GitHub Docs](https://docs.github.com/en/rest/releases?utm_source=chatgpt.com \"REST API endpoints for releases and release assets\"))\n \n- **创建、更新、删除发布版本(Create / Update / Delete Release)**\n \n - `POST /repos/{owner}/{repo}/releases` — 创建新的发布版本\n \n - `PATCH /repos/{owner}/{repo}/releases/{release_id}` — 更新发布版本\n \n - `DELETE /repos/{owner}/{repo}/releases/{release_id}` — 删除发布版本 \n (这些操作通常需要认证权限。)([GitHub Docs](https://docs.github.com/en/rest/releases?utm_source=chatgpt.com \"REST API endpoints for releases and release assets\"))\n \n\n---\n\n## Git Tags(标签)相关接口\n\n- **列出仓库的 Git 标签** \n `GET /repos/{owner}/{repo}/tags` \n 返回该仓库所有标签(包括 lightweight 和 annotated)。([Stack Overflow](https://stackoverflow.com/questions/18384873/how-to-list-the-releases-of-a-repository?utm_source=chatgpt.com \"github - How to list the releases of a repository?\"), [GitHub Docs](https://docs.github.com/en/rest/repos/tags?utm_source=chatgpt.com \"REST API endpoints for repository tags\"))\n \n- **获取标签引用(Tag Reference)** \n `GET /repos/{owner}/{repo}/git/refs/tags/{tag_name}` \n 可获取该标签所对应的对象(TAG_SHA),用于进一步查询。([Stack Overflow](https://stackoverflow.com/questions/72429056/how-to-get-single-tag-information-using-github-api?utm_source=chatgpt.com \"How to get Single tag Information using GitHub Api?\"))\n \n- **获取 Annotated Tag 对象详情** \n `GET /repos/{owner}/{repo}/git/tags/{tag_sha}` \n 获取标签对象的完整信息,包括 `object.sha` 即对应的 commit SHA、tagger、message 等。([Stack Overflow](https://stackoverflow.com/questions/72429056/how-to-get-single-tag-information-using-github-api?utm_source=chatgpt.com \"How to get Single tag Information using GitHub Api?\"))\n \n\n---\n\n## Commits(提交)相关接口\n\n- **列出提交记录(List Commits)** \n `GET /repos/{owner}/{repo}/commits` \n 返回最新的提交列表,第一个通常为最新提交。响应中包含 SHA、作者、提交信息、签名验证信息等。([GitHub Docs](https://docs.github.com/en/rest/commits/commits?utm_source=chatgpt.com \"REST API endpoints for commits\"))\n \n- **获取单个提交详情(Get a Commit)** \n `GET /repos/{owner}/{repo}/commits/{commit_sha}` \n 获取指定提交的详细信息。([GitHub Docs](https://docs.github.com/en/rest/commits?utm_source=chatgpt.com \"REST API endpoints for commits\"))\n \n- **比较两个提交(Compare Commits)** \n `GET /repos/{owner}/{repo}/compare/{base}...{head}` \n 用于比较两个 commit 或两个 tag 之间的差异。([Stack Overflow](https://stackoverflow.com/questions/61359461/get-all-commits-in-a-git-tag-through-github-api-return-only-the-first-commit?utm_source=chatgpt.com \"get all commits in a Git tag through GitHub API return only ...\"))\n \n\n---\n\n## 综合流程示例\n\n下面是一个常见逻辑,例如想获取最新发布对应的 commit SHA:\n\n1. 调用 `GET /repos/{owner}/{repo}/releases/latest` 获取最新 release 的 `tag_name`。\n \n2. 调用 `GET /repos/{owner}/{repo}/git/refs/tags/{tag_name}` 获取 TAG_SHA。\n \n3. 调用 `GET /repos/{owner}/{repo}/git/tags/{tag_sha}` 获取该标签对象的 commit SHA(object.sha)。\n \n\n这套流程常用于从发布版本跳转到对应的 Git 提交。([Stack Overflow](https://stackoverflow.com/questions/67040794/how-can-i-get-the-commit-hash-of-the-latest-release-from-github-api?utm_source=chatgpt.com \"How can I get the commit hash of the latest release from ...\"))\n\n---\n\n## 表格总结\n\n|功能需求|接口路径 / 方法|\n|---|---|\n|最新发布版本信息|`GET /repos/{owner}/{repo}/releases/latest`|\n|列出所有发布版本|`GET /repos/{owner}/{repo}/releases`|\n|通过 tag 查询发布|`GET /repos/{owner}/{repo}/releases/tags/{tag}`|\n|获取标签列表|`GET /repos/{owner}/{repo}/tags`|\n|获取标签引用(TAG_SHA)|`GET /repos/{owner}/{repo}/git/refs/tags/{tag_name}`|\n|获取标签对象详情|`GET /repos/{owner}/{repo}/git/tags/{tag_sha}`|\n|列出提交|`GET /repos/{owner}/{repo}/commits`|\n|获取指定 commit 信息|`GET /repos/{owner}/{repo}/commits/{commit_sha}`|\n|比较两个 commit/tag|`GET /repos/{owner}/{repo}/compare/{base}...{head}`|\n\n---\n\n如果你还希望了解更多,如 API 速率限制、认证方式(匿名 vs token)、分页处理(per_page、page 参数)、使用 GraphQL API 实现同类功能,或具体的 JavaScript `fetch` 调用示例,都可以随时继续讨论!", + "Github/Github获取仓库密钥.md": "这个地方要注意:\n\n你输入 `git push` 时出现\n\n```\nUsername for 'https://github.com': shumengya\nPassword for 'https://shumengya@github.com':\n```\n\n这里的 **Password** 已经不是 GitHub 登录密码了。\n从 2021 年 8 月开始,GitHub **禁用了账户密码推送**,必须用 **Personal Access Token (PAT)** 或 **SSH Key** 来认证。\n\n---\n\n### ✅ 方案一:生成 Personal Access Token(HTTPS 推荐)\n\n1. 登录 GitHub → 右上角头像 → **Settings**\n2. 左侧栏 → **Developer settings** → **Personal access tokens** → **Tokens (classic)**\n3. 点击 **Generate new token (classic)**\n\n * 勾选 **repo**(访问和推送仓库必须要有)\n * 设置有效期(比如 90 天或无期限)\n * 点击生成\n4. 复制生成的 Token(只会显示一次)\n\n之后推送时:\n\n* **Username**:填 GitHub 用户名(`shumengya`)\n* **Password**:填刚生成的 Token\n\n---\n\n### ✅ 方案二:改用 SSH Key(更方便)\n\n1. 本地生成 SSH Key:\n\n ```bash\n ssh-keygen -t ed25519 -C \"你的邮箱\"\n ```\n\n 按回车保存,默认会在 `~/.ssh/id_ed25519` 和 `~/.ssh/id_ed25519.pub`。\n2. 查看公钥:\n\n ```bash\n cat ~/.ssh/id_ed25519.pub\n ```\n3. 复制内容 → GitHub → **Settings → SSH and GPG keys → New SSH key** → 粘贴保存。\n4. 修改仓库地址为 SSH:\n\n ```bash\n git remote set-url origin git@github.com:shumengya/你的仓库名.git\n ```\n5. 之后直接 `git push` 就不用输密码了。\n\n---\n\n👉 建议你选 **SSH Key**,因为用一次就永久生效,不会过期。\n\n要不要我给你写一份 **完整 SSH Key 配置和测试流程**(从生成到验证)?\n\n", + "Github/Linux下使用git探索.md": "**修改全局代理为http1**\n```\ngit config --global http.version HTTP/1.1\n```\n\n**相当于 git fetch + git merge,会把远程最新提交合并到你当前分支。**\n```\ngit pull\n```\n\n**这会把你的本地提交临时“挪开”,先更新远程提交,然后再把你的提交放回去,避免多余的合并记录。**\n```\ngit pull --rebase\n```\n\n**如果只想下载最新提交但不合并**\n```\ngit fetch\n```\n\n**树萌芽GitHub仓库提交代码通用密钥:**\n```\n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\n```\n\n### 1. 添加所有改动\n```\ngit add .\n```\n### 2. 提交,写上提交说明\n```\ngit commit -m \"更新说明\"\n```\n### 3. 推送到远程仓库(假设分支是 main)\n```\ngit push origin main\n```\n\n\n**压缩成一条命令实现:**\n```\ngit add . && git commit -m \"update\" && git push origin main\n```\n\n**或者设置命令别名,比如写进 ~/.bashrc 或 ~/.zshrc:**\n```\nalias gopush='git add . && git commit -m \"update\" && git push origin main'\n```\n\n\n注意:校园网可能会屏蔽梯子,必要时开热点提交\n\n", + "Github/linux常用git命令.md": "下面给你整理了一份 **Linux 下常用的 Git 命令速查表**,涵盖从初始化到协作的常见操作:\n\n---\n\n## 🔹 基础配置\n\n```bash\ngit config --global user.name \"你的名字\" # 设置用户名\ngit config --global user.email \"你的邮箱\" # 设置邮箱\ngit config --global core.editor \"vim\" # 设置默认编辑器\ngit config --list # 查看当前配置 \n```\n\n---\n\n## 🔹 仓库初始化与克隆\n\n```bash\ngit init # 初始化一个本地仓库\ngit clone # 克隆远程仓库\ngit clone myproj # 克隆并重命名文件夹\n```\n\n---\n\n## 🔹 文件操作\n\n```bash\ngit status # 查看仓库当前状态\ngit add # 添加文件到暂存区\ngit add . # 添加所有修改到暂存区\ngit reset # 从暂存区撤销已添加的文件\ngit rm # 删除文件并记录到暂存区\ngit mv old new # 重命名文件并记录到暂存区\n```\n\n---\n\n## 🔹 提交相关\n\n```bash\ngit commit -m \"说明\" # 提交暂存区到仓库\ngit commit -am \"说明\" # 添加修改并提交(跳过 git add)\ngit log # 查看提交历史\ngit log --oneline --graph # 图形化查看分支提交记录\n```\n\n---\n\n## 🔹 分支操作\n\n```bash\ngit branch # 查看分支\ngit branch # 创建分支\ngit checkout # 切换分支\ngit checkout -b # 新建并切换分支\ngit merge # 合并分支到当前分支\ngit branch -d # 删除分支\n```\n\n---\n\n## 🔹 远程仓库\n\n```bash\ngit remote -v # 查看远程仓库地址\ngit remote add origin # 添加远程仓库\ngit remote remove origin # 删除远程仓库\ngit push origin master # 推送 master 分支到远程\ngit push -u origin # 推送并设置默认分支\ngit pull origin master # 拉取远程更新并合并\ngit fetch origin # 抓取远程分支(不合并)\n```\n\n---\n\n## 🔹 回退与撤销\n\n```bash\ngit checkout -- # 撤销工作区修改\ngit reset HEAD # 取消暂存区文件\ngit reset --hard HEAD~1 # 回退到上一个提交\ngit revert # 撤销指定提交,生成新提交\n```\n\n---\n\n## 🔹 标签管理\n\n```bash\ngit tag # 查看标签\ngit tag v1.0 # 打标签\ngit tag -a v1.0 -m \"说明\" # 创建附注标签\ngit push origin v1.0 # 推送标签到远程\ngit push origin --tags # 推送所有标签\n```\n\n---\n\n## 🔹 常用技巧\n\n```bash\ngit stash # 临时保存修改\ngit stash pop # 恢复最近一次保存\ngit diff # 查看未暂存的修改\ngit diff --cached # 查看已暂存的修改\n```\n\n---\n\n\n", + "LeetCode/力扣-两数之和详解.md": "两数之和问题 - 详细运算过程解析\n\n算法思路回顾\n\n使用哈希表(字典)来存储已经遍历过的数字及其索引,对于每个当前数字,计算其与目标值的差值(补数),并检查该补数是否已经在哈希表中存在。\n\n详细运算过程\n\n让我们通过一个具体例子来详细解析算法的执行过程:\n\n示例: nums = [2, 7, 11, 15], target = 9\n\n初始化阶段\n\n```python\nnum_map = {} # 创建一个空字典用于存储数字和索引的映射\n```\n\n第一次迭代 (i=0, num=2)\n\n1. 计算补数:complement = target - num = 9 - 2 = 7\n2. 检查补数7是否在num_map中:7 in num_map → 结果为False(因为字典为空)\n3. 将当前数字和索引存入字典:num_map[2] = 0\n4. 此时字典状态:{2: 0}\n\n第二次迭代 (i=1, num=7)\n\n1. 计算补数:complement = target - num = 9 - 7 = 2\n2. 检查补数2是否在num_map中:2 in num_map → 结果为True(因为字典中有键2)\n3. 找到匹配,返回结果:[num_map[2], 1] → [0, 1]\n4. 算法结束,返回结果[0, 1]\n\n运算过程可视化\n\n迭代次数 当前索引(i) 当前值(num) 补数(complement) 补数是否在num_map中 num_map更新 操作说明\n1 0 2 7 否 {2:0} 将2和索引0存入字典\n2 1 7 2 是 - 找到匹配,返回[0,1]\n\n关键点解析\n\n1. 补数计算:对于每个数字,计算target - num得到补数,这个补数就是我们需要在之前遍历过的数字中寻找的值。\n2. 哈希表的作用:哈希表用于存储已经遍历过的数字及其索引,这样可以在O(1)时间内检查补数是否存在。\n3. 顺序重要性:算法先检查补数是否存在,然后再将当前数字存入字典,这样可以确保不会使用同一个元素两次。\n4. 时间复杂度:每个元素只被访问一次,哈希表的插入和查找操作平均时间复杂度为O(1),因此总时间复杂度为O(n)。\n5. 空间复杂度:最坏情况下需要存储所有n个元素,因此空间复杂度为O(n)。\n\n为什么这种方法有效?\n\n这种方法有效的关键在于利用了数学关系:如果a + b = target,那么target - a = b。通过存储已经遍历过的数字,我们可以快速检查当前数字的补数是否已经出现过。\n\n这种方法比暴力解法(双重循环)高效得多,将时间复杂度从O(n²)降低到O(n),是典型的\"以空间换时间\"策略。\n\n边界情况处理\n\n虽然题目保证有解,但实际应用中可能需要考虑无解的情况。我们的代码在无解时会返回空列表,这是一种合理的处理方式。\n\n这种算法设计简洁高效,是解决两数之和问题的标准方法,被广泛应用于各种编程面试和实际开发中。", + "LeetCode/力扣1-两数相加问题.md": "两数相加问题\n\n问题描述\n\n给定两个非空链表,表示两个非负整数。每位数字按照逆序方式存储,每个节点存储一位数字。将两个数相加,并以相同形式返回表示和的链表。\n\n假设除了数字0之外,这两个数都不会以0开头。\n\n示例\n\n示例 1:\n\n```\n输入:l1 = [2,4,3], l2 = [5,6,4]\n输出:[7,0,8]\n解释:342 + 465 = 807\n```\n\n示例 2:\n\n```\n输入:l1 = [0], l2 = [0]\n输出:[0]\n```\n\n示例 3:\n\n```\n输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]\n输出:[8,9,9,9,0,0,0,1]\n```\n\n提示\n\n· 每个链表中的节点数在范围 [1, 100] 内\n· 0 <= Node.val <= 9\n· 题目数据保证列表表示的数字不含前导零\n\n方法思路\n\n问题分析\n\n两个链表表示的数字是逆序存储的,即链表的头节点表示个位数,第二个节点表示十位数,以此类推。我们需要模拟加法运算,从低位到高位逐位相加,并处理进位问题。\n\n算法选择\n\n· 使用一个虚拟头节点(dummy node)简化链表操作\n· 同时遍历两个链表,逐位相加并处理进位\n· 如果链表长度不同,较短链表的缺失位视为0\n· 最后如果还有进位,需要额外创建一个节点\n\n算法步骤\n\n1. 初始化虚拟头节点和当前指针\n2. 初始化进位值为0\n3. 同时遍历两个链表,直到两个链表都遍历完且没有进位\n4. 计算当前位的和:两个链表当前节点的值加上进位\n5. 计算新的进位和当前位的值\n6. 创建新节点并连接到结果链表\n7. 移动所有指针到下一个位置\n8. 返回虚拟头节点的下一个节点\n\n复杂度分析\n\n· 时间复杂度:O(max(m, n)),其中m和n分别是两个链表的长度\n· 空间复杂度:O(max(m, n)),结果链表的长度最多为max(m, n) + 1\n\n解决代码\n\n```python\n# Definition for singly-linked list.\nclass ListNode:\n def __init__(self, val=0, next=None):\n self.val = val\n self.next = next\n\nclass Solution:\n def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:\n \"\"\"\n 将两个逆序存储的数字链表相加,返回结果链表\n \n 参数:\n l1: ListNode - 第一个数字链表\n l2: ListNode - 第二个数字链表\n \n 返回:\n ListNode - 相加结果的链表\n \"\"\"\n dummy = ListNode(0) # 虚拟头节点\n current = dummy # 当前指针\n carry = 0 # 进位值\n \n # 遍历两个链表,直到两个链表都为空且没有进位\n while l1 or l2 or carry:\n # 获取当前节点的值,如果节点为空则为0\n val1 = l1.val if l1 else 0\n val2 = l2.val if l2 else 0\n \n # 计算当前位的和\n total = val1 + val2 + carry\n carry = total // 10 # 计算进位\n digit = total % 10 # 计算当前位的值\n \n # 创建新节点并连接到结果链表\n current.next = ListNode(digit)\n current = current.next\n \n # 移动到下一个节点\n if l1:\n l1 = l1.next\n if l2:\n l2 = l2.next\n \n return dummy.next # 返回结果链表的头节点\n```\n\n代码解释\n\n1. 链表节点定义:ListNode类定义了链表节点的结构,包含值val和指向下一个节点的指针next。\n2. 初始化:\n · 创建虚拟头节点dummy,简化链表操作\n · 设置当前指针current指向虚拟头节点\n · 初始化进位carry为0\n3. 循环处理:\n · 使用while循环遍历两个链表,直到两个链表都遍历完且没有进位\n · 循环条件l1 or l2 or carry确保处理所有情况\n4. 获取当前值:\n · 如果链表节点存在,获取其值;否则视为0\n · 这样可以处理链表长度不同的情况\n5. 计算和与进位:\n · 计算当前位的总和:val1 + val2 + carry\n · 计算新的进位:total // 10\n · 计算当前位的值:total % 10\n6. 创建新节点:\n · 根据当前位的值创建新节点\n · 将新节点连接到结果链表\n · 移动当前指针到新节点\n7. 移动指针:\n · 如果链表还有节点,移动到下一个节点\n · 这样可以继续处理后续位\n8. 返回结果:\n · 返回虚拟头节点的下一个节点,即结果链表的头节点\n · 虚拟头节点简化了链表操作,避免处理空链表的情况\n\n示例验证\n\n以示例1为例:l1 = [2,4,3] (表示342),l2 = [5,6,4] (表示465)\n\n1. 个位:2 + 5 = 7,进位0 → 结果个位7\n2. 十位:4 + 6 = 10,进位1 → 结果十位0\n3. 百位:3 + 4 + 1 = 8,进位0 → 结果百位8\n\n最终结果为[7,0,8] (表示807),符合预期。\n\n这种方法高效地处理了链表相加的问题,考虑了所有边界情况,包括链表长度不同和最后有进位的情况。", + "LeetCode/力扣2-两数之和.md": "两数之和问题\n\n问题描述\n\n给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。\n\n你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。你可以按任意顺序返回答案。\n\n示例 1:\n\n```\n输入:nums = [2,7,11,15], target = 9\n输出:[0,1]\n解释:因为 nums[0] + nums[1] == 9,返回 [0, 1]。\n```\n\n示例 2:\n\n```\n输入:nums = [3,2,4], target = 6\n输出:[1,2]\n```\n\n示例 3:\n\n```\n输入:nums = [3,3], target = 6\n输出:[0,1]\n```\n\n提示:\n\n· 2 <= nums.length <= 10^4\n· -10^9 <= nums[i] <= 10^9\n· -10^9 <= target <= 10^9\n· 只会存在一个有效答案\n\n方法思路\n\n1. 问题分析\n\n我们需要在数组中找到两个不同的元素,它们的和等于目标值。由于数组可能很大,暴力解法(双重循环)的时间复杂度为O(n²),效率太低。\n\n2. 算法选择\n\n使用哈希表来存储每个元素及其索引,这样可以在O(1)时间内检查目标值与当前元素的差值是否存在于哈希表中。\n\n3. 算法步骤\n\n1. 初始化一个空哈希表(字典)\n2. 遍历数组中的每个元素及其索引\n3. 对于每个元素,计算目标值与当前元素的差值(补数)\n4. 检查该差值是否已存在于哈希表中\n5. 如果存在,返回当前索引和差值的索引\n6. 如果不存在,将当前元素及其索引存入哈希表\n\n4. 复杂度分析\n\n· 时间复杂度:O(n),只需遍历数组一次\n· 空间复杂度:O(n),用于存储哈希表\n\n解决代码\n\n```python\ndef twoSum(nums, target):\n \"\"\"\n 在给定数组中找出和为目标值的两个整数的索引\n \n 参数:\n nums: List[int] - 整数数组\n target: int - 目标值\n \n 返回:\n List[int] - 两个整数的索引列表\n \"\"\"\n num_map = {} # 创建空字典存储数字和索引的映射\n for i, num in enumerate(nums): # 遍历数组,获取索引和数值\n complement = target - num # 计算补数\n if complement in num_map: # 检查补数是否在字典中\n return [num_map[complement], i] # 如果在,返回两个索引\n num_map[num] = i # 如果不在,将当前数字和索引存入字典\n return [] # 如果没有找到,返回空列表(但题目保证有解,所以不会执行到这里)\n```\n\n代码解释\n\n1. 初始化哈希表:num_map 用于存储元素值到索引的映射\n2. 遍历数组:使用 enumerate 函数同时获取元素的索引 i 和数值 num\n3. 计算补数:对于每个 num,计算 complement = target - num\n4. 检查补数是否存在:如果补数存在于哈希表中,说明找到了两个数,返回它们的索引\n5. 存储当前元素:如果补数不存在,将当前元素及其索引存入哈希表,以便后续查找\n6. 返回结果:如果遍历结束仍未找到,返回空列表(但题目保证有解,所以不会执行到此)\n\n这种方法确保了高效查找,适用于大规模数据输入,是解决此类问题的标准方法。", + "Linux/busybox v1.36命令简介.md": "以下是针对 **BusyBox** 中每条命令的简要说明:\r\n\r\n1. **[**:测试表达式的真假。\r\n2. **[[**:增强版的条件测试命令。\r\n3. **acpid**:管理系统的 ACPI 事件。\r\n4. **adjtimex**:调整系统时间。\r\n5. **ar**:创建、修改、提取归档文件。\r\n6. **arch**:显示机器架构类型。\r\n7. **arp**:显示或修改 ARP 缓存。\r\n8. **arping**:向网络发送 ARP 请求。\r\n9. **ascii**:显示 ASCII 表。\r\n10. **ash**:一个轻量级的 shell。\r\n11. **awk**:强大的文本处理工具。\r\n12. **base32**:以 Base32 编码格式进行数据转换。\r\n13. **base64**:以 Base64 编码格式进行数据转换。\r\n14. **basename**:从路径中提取文件名。\r\n15. **bbconfig**:配置 BusyBox。\r\n16. **beep**:产生蜂鸣声。\r\n17. **blkdiscard**:丢弃磁盘块。\r\n18. **blkid**:显示块设备的标识。\r\n19. **blockdev**:对块设备进行操作。\r\n20. **brctl**:管理网桥接口。\r\n21. **bunzip2**:解压 `.bz2` 格式文件。\r\n22. **bzcat**:查看 `.bz2` 格式文件内容。\r\n23. **bzip2**:压缩文件为 `.bz2` 格式。\r\n24. **cal**:显示日历。\r\n25. **cat**:连接文件并显示内容。\r\n26. **chat**:发送控制字符以进行调制解调器通信。\r\n27. **chattr**:改变文件的属性。\r\n28. **chcon**:改变文件的 SELinux 上下文。\r\n29. **chgrp**:改变文件的组。\r\n30. **chmod**:改变文件的权限。\r\n31. **chown**:改变文件的拥有者。\r\n32. **chroot**:改变根目录。\r\n33. **chrt**:操作进程的调度策略。\r\n34. **chvt**:切换虚拟终端。\r\n35. **cksum**:计算文件的校验和。\r\n36. **clear**:清除终端屏幕。\r\n37. **cmp**:比较两个文件。\r\n38. **comm**:比较两个已排序文件的内容。\r\n39. **conspy**:查看控制台的输出。\r\n40. **cp**:复制文件。\r\n41. **cpio**:创建、解压 cpio 格式归档。\r\n42. **crc32**:计算 CRC32 校验和。\r\n43. **crond**:周期性执行任务的守护进程。\r\n44. **crontab**:编辑 cron 表。\r\n45. **cttyhack**:改变控制终端。\r\n46. **cut**:按列剪切文本。\r\n47. **date**:显示或设置系统日期和时间。\r\n48. **dc**:计算器程序。\r\n49. **dd**:转换和复制文件。\r\n50. **deallocvt**:释放虚拟终端。\r\n51. **depmod**:生成内核模块依赖关系。\r\n52. **devmem**:访问物理内存。\r\n53. **df**:显示文件系统的磁盘空间使用情况。\r\n54. **dhcprelay**:转发 DHCP 请求。\r\n55. **diff**:比较文件的不同之处。\r\n56. **dirname**:获取路径的目录部分。\r\n57. **dmesg**:显示内核的消息缓冲区内容。\r\n58. **dnsd**:轻量级 DNS 服务器。\r\n59. **dnsdomainname**:显示域名。\r\n60. **dos2unix**:转换 DOS 格式文本为 Unix 格式。\r\n61. **du**:显示磁盘使用情况。\r\n62. **dumpkmap**:转储键盘映射。\r\n63. **dumpleases**:显示 DHCP 租约。\r\n64. **echo**:显示一行文本。\r\n65. **ed**:文本编辑器。\r\n66. **egrep**:扩展正则表达式的 grep 命令。\r\n67. **eject**:弹出光盘。\r\n68. **env**:显示或设置环境变量。\r\n69. **ether-wake**:发送 Wake-on-LAN 魔术包。\r\n70. **expand**:将制表符转换为空格。\r\n71. **expr**:计算表达式的值。\r\n72. **factor**:因数分解。\r\n73. **fakeidentd**:模拟 identd 服务。\r\n74. **false**:返回失败状态。\r\n75. **fatattr**:显示或修改 FAT 文件系统的属性。\r\n76. **fbset**:设置帧缓冲设备的参数。\r\n77. **fbsplash**:管理帧缓冲启动画面。\r\n78. **fdflush**:刷新文件描述符。\r\n79. **fdformat**:格式化软盘。\r\n80. **fdisk**:管理磁盘分区。 \r\n81. **fgconsole**:切换到指定的虚拟终端。\r\n82. **fgrep**:固定字符串搜索工具。\r\n83. **find**:搜索文件。\r\n84. **findfs**:查找文件系统。\r\n85. **flash_eraseall**:擦除闪存设备。\r\n86. **flash_lock**:锁定闪存设备。\r\n87. **flash_unlock**:解锁闪存设备。\r\n88. **flock**:对文件进行锁定。\r\n89. **fold**:折叠文本行。\r\n90. **free**:显示内存使用情况。\r\n91. **freeramdisk**:释放 RAM 磁盘。\r\n92. **fsck**:检查文件系统的完整性。\r\n93. **fsck.minix**:检查 Minix 文件系统。\r\n94. **fsfreeze**:冻结文件系统以进行备份。\r\n95. **fstrim**:修剪未使用的磁盘空间。\r\n96. **fsync**:强制磁盘同步。\r\n97. **ftpd**:启动 FTP 服务器。\r\n98. **ftpget**:下载文件通过 FTP。\r\n99. **ftpput**:上传文件通过 FTP。\r\n100. **fuser**:显示正在使用某个文件的进程。\r\n101. **getenforce**:显示 SELinux 的状态。\r\n102. **getopt**:解析命令行选项。\r\n103. **grep**:搜索文本中的模式。\r\n104. **groups**:显示用户所属的组。\r\n105. **gunzip**:解压 `.gz` 文件。\r\n106. **gzip**:压缩文件为 `.gz` 格式。\r\n107. **hd**:显示硬盘的分区信息。\r\n108. **hdparm**:设置硬盘参数。\r\n109. **head**:显示文件的开头部分。\r\n110. **hexdump**:以十六进制格式显示文件内容。\r\n111. **hexedit**:编辑十六进制文件。\r\n112. **hostname**:显示或设置主机名。\r\n113. **httpd**:启动 HTTP 服务器。\r\n114. **hush**:一个小型 shell。\r\n115. **hwclock**:访问硬件时钟。\r\n116. **id**:显示用户和组信息。\r\n117. **ifconfig**:配置网络接口。\r\n118. **ifdown**:关闭网络接口。\r\n119. **ifenslave**:配置链路聚合。\r\n120. **ifplugd**:监控网络接口的连接状态。\r\n121. **ifup**:启用网络接口。\r\n122. **inetd**:启动网络服务守护进程。\r\n123. **inotifyd**:启动文件系统事件监控。\r\n124. **insmod**:加载内核模块。\r\n125. **install**:复制文件并设置权限。\r\n126. **ionice**:设置进程的 I/O 优先级。\r\n127. **iostat**:显示 CPU 和 I/O 统计信息。\r\n128. **ip**:配置网络接口和路由。\r\n129. **ipaddr**:显示或设置 IP 地址。\r\n130. **ipcalc**:计算和显示 IP 地址信息。\r\n131. **ipcrm**:删除共享内存、消息队列、信号量。\r\n132. **ipcs**:显示进程间通信的状态。\r\n133. **iplink**:管理网络接口的状态。\r\n134. **ipneigh**:显示邻居表。\r\n135. **iproute**:管理路由表。\r\n136. **iprule**:显示或管理路由规则。\r\n137. **iptunnel**:配置 IP 隧道。\r\n138. **kbd_mode**:设置键盘模式。\r\n139. **kill**:终止进程。\r\n140. **killall**:终止指定名称的所有进程。\r\n141. **killall5**:终止所有进程。\r\n142. **klogd**:内核日志守护进程。\r\n143. **less**:分页显示文件内容。\r\n144. **link**:创建硬链接。\r\n145. **ln**:创建硬链接或符号链接。\r\n146. **loadfont**:加载字体。\r\n147. **loadkmap**:加载键盘映射。\r\n148. **logread**:显示日志文件内容。\r\n149. **losetup**:管理环回设备。\r\n150. **ls**:列出目录内容。\r\n\r\n继续接着之前的命令列表进行总结:\r\n\r\n151. **lsattr**:显示文件的属性。\r\n\r\n152. **lsmod**:显示加载的内核模块。\r\n\r\n153. **lsof**:列出打开的文件。\r\n\r\n154. **lspci**:显示所有 PCI 设备。\r\n\r\n155. **lsscsi**:显示 SCSI 设备信息。\r\n\r\n156. **lsusb**:列出 USB 设备。\r\n\r\n157. **lzcat**:解压 `.lz` 文件并显示内容。\r\n\r\n158. **lzma**:压缩文件为 `.lzma` 格式。\r\n\r\n159. **lzop**:快速的文件压缩工具。\r\n\r\n160. **lzopcat**:查看 `.lzo` 格式文件内容。\r\n\r\n161. **makedevs**:创建设备节点。\r\n\r\n162. **makemime**:生成 MIME 类型文件。\r\n\r\n163. **man**:查看手册页(如果有)。\r\n\r\n164. **md5sum**:计算文件的 MD5 校验和。\r\n\r\n165. **mesg**:控制终端消息的接收。\r\n\r\n166. **microcom**:串行通信工具。\r\n\r\n167. **mim**:提取文件的 MIME 类型。\r\n\r\n168. **mkdir**:创建目录。\r\n\r\n169. **mkdosfs**:创建 FAT 文件系统。\r\n\r\n170. **mke2fs**:创建 ext2 文件系统。\r\n\r\n171. **mkfifo**:创建命名管道。\r\n\r\n172. **mkfs.ext2**:创建 ext2 文件系统。\r\n\r\n173. **mkfs.minix**:创建 Minix 文件系统。\r\n\r\n174. **mkfs.reiser**:创建 Reiser 文件系统。\r\n\r\n175. **mkfs.vfat**:创建 VFAT 文件系统。\r\n\r\n176. **mknod**:创建块设备或字符设备文件。\r\n\r\n177. **mkswap**:创建交换分区。\r\n\r\n178. **mktemp**:创建临时文件。\r\n\r\n179. **modinfo**:显示内核模块的信息。\r\n\r\n180. **modprobe**:加载或卸载内核模块。\r\n\r\n181. **more**:分页显示文件内容。\r\n\r\n182. **mount**:挂载文件系统。\r\n\r\n183. **mountpoint**:检查是否为挂载点。\r\n\r\n184. **mpstat**:显示 CPU 使用统计信息。\r\n\r\n185. **mv**:移动或重命名文件。\r\n\r\n186. **nameif**:根据 MAC 地址设置网络接口名称。\r\n\r\n187. **nanddump**:转储 NAND 闪存的内容。\r\n\r\n188. **nandwrite**:将数据写入 NAND 闪存。\r\n\r\n189. **nbd-client**:连接到网络块设备。\r\n\r\n190. **nc**:Netcat 工具,用于读写网络连接。\r\n\r\n191. **netstat**:显示网络连接状态。\r\n\r\n192. **nice**:调整进程的优先级。\r\n\r\n193. **nl**:显示带有行号的文件内容。\r\n\r\n194. **nmeter**:网络带宽监控工具。\r\n\r\n195. **nohup**:在后台运行命令并忽略挂起信号。\r\n\r\n196. **nologin**:禁止用户登录。\r\n\r\n197. **nsenter**:进入其他命名空间。\r\n\r\n198. **nslookup**:查询 DNS 信息。\r\n\r\n199. **nuke**:终止所有与特定进程相关的网络连接。\r\n\r\n200. **od**:以不同格式显示文件内容(如十六进制)。\r\n\r\n201. **openvt**:在指定的虚拟终端上运行命令。\r\n\r\n202. **partprobe**:通知操作系统重新读取分区表。\r\n\r\n203. **paste**:合并多个文件按列显示。\r\n\r\n204. **patch**:应用补丁文件。\r\n\r\n205. **pgrep**:查找匹配指定模式的进程。\r\n\r\n206. **pidof**:查找指定进程的 PID。\r\n\r\n207. **ping**:向网络主机发送 ICMP 请求。\r\n\r\n208. **ping6**:向网络主机发送 ICMPv6 请求。\r\n\r\n209. **pipe_progress**:显示管道中的数据传输进度。\r\n\r\n210. **pivot_root**:更改文件系统根目录。\r\n\r\n211. **pkill**:根据进程名终止进程。\r\n\r\n212. **pmap**:显示进程的内存映射。\r\n\r\n213. **popmaildir**:从邮件目录中获取邮件。\r\n\r\n214. **poweroff**:关闭计算机。\r\n\r\n215. **powertop**:用于优化电源管理的工具。\r\n\r\n216. **printenv**:显示所有环境变量。\r\n\r\n217. **printf**:格式化并输出文本。\r\n\r\n218. **ps**:显示当前进程信息。\r\n\r\n219. **pscan**:扫描当前进程的状态。\r\n\r\n220. **pstree**:以树形结构显示进程。\r\n\r\n221. **pwd**:显示当前工作目录。\r\n\r\n222. **pwdx**:显示指定进程的工作目录。\r\n\r\n223. **raidautorun**:自动启动 RAID 配置。\r\n\r\n224. **rdate**:同步时间。\r\n\r\n225. **rdev**:显示或设置设备的特殊属性。\r\n\r\n226. **readlink**:显示符号链接的目标。\r\n\r\n227. **readprofile**:读取并显示应用的性能配置。\r\n\r\n228. **realpath**:返回文件的绝对路径。\r\n\r\n229. **reboot**:重启系统。\r\n\r\n230. **reformime**:转换 MIME 格式。\r\n\r\n231. **renice**:改变进程的优先级。\r\n\r\n232. **reset**:重置终端。\r\n\r\n233. **resize**:调整终端大小。\r\n\r\n234. **resume**:恢复挂起的进程。\r\n\r\n235. **rev**:反转每行文本。\r\n\r\n236. **rfkill**:管理无线设备的开关。\r\n\r\n237. **rm**:删除文件。\r\n\r\n238. **rmdir**:删除空目录。\r\n\r\n239. **rmmod**:卸载内核模块。\r\n\r\n240. **route**:显示或修改路由表。\r\n\r\n241. **rtcwake**:设置系统的 RTC 来定时唤醒。\r\n\r\n242. **run-init**:运行初始化程序。\r\n\r\n243. **run-parts**:按顺序运行目录中的脚本。\r\n\r\n244. **runcon**:设置进程的 SELinux 上下文。\r\n\r\n245. **rx**:接收串口数据。\r\n\r\n246. **script**:记录终端会话。\r\n\r\n247. **scriptreplay**:重放记录的终端会话。\r\n\r\n248. **sed**:流编辑器,用于处理文本数据。\r\n\r\n249. **seedrng**:种子随机数生成器。\r\n\r\n250. **selinuxenabled**:检查 SELinux 是否启用。\r\n\r\n251. **sendmail**:发送电子邮件。\r\n\r\n252. **seq**:生成一个数字序列。\r\n\r\n253. **sestatus**:显示 SELinux 状态。\r\n\r\n254. **setconsole**:设置控制台的终端类型。\r\n\r\n255. **setenforce**:启用或禁用 SELinux 强制模式。\r\n\r\n256. **setfattr**:设置文件的扩展属性。\r\n\r\n257. **setfont**:设置终端的字体。\r\n\r\n258. **setkeycodes**:设置键盘扫描码到键值的映射。\r\n\r\n259. **setlogcons**:设置日志控制台。\r\n\r\n260. **setpriv**:设置进程的特权级别。\r\n\r\n261. **setserial**:设置串口设备的参数。\r\n\r\n262. **setsid**:创建新的会话并运行命令。\r\n\r\n263. **setuidgid**:设置进程的用户和组标识。\r\n\r\n264. **sh**:启动一个新的 shell。\r\n\r\n265. **sha1sum**:计算文件的 SHA-1 校验和。\r\n\r\n266. **sha256sum**:计算文件的 SHA-256 校验和。\r\n\r\n267. **sha3sum**:计算文件的 SHA-3 校验和。\r\n\r\n268. **sha512sum**:计算文件的 SHA-512 校验和。\r\n\r\n269. **showkey**:显示键盘输入的键值。\r\n\r\n270. **shred**:擦除文件,防止数据恢复。\r\n\r\n271. **shuf**:随机排列输入行。\r\n\r\n272. **slattach**:设置串行连接。\r\n\r\n273. **sleep**:暂停一段时间。\r\n\r\n274. **smemcap**:设置进程内存使用限制。\r\n\r\n275. **sort**:按行排序文本文件。\r\n\r\n276. **split**:将文件分割成多个小文件。\r\n\r\n277. **ssl_client**:通过 SSL 连接远程主机。\r\n\r\n278. **start-stop-daemon**:启动或停止后台守护进程。\r\n\r\n279. **stat**:显示文件或文件系统的状态。\r\n\r\n280. **strings**:显示文件中的可打印字符串。\r\n\r\n281. **stty**:设置终端行属性。\r\n\r\n282. **sum**:计算文件的校验和。\r\n\r\n283. **svc**:启动、停止或重启服务。\r\n\r\n284. **svok**:检查服务的状态。\r\n\r\n285. **swapoff**:禁用交换空间。\r\n\r\n286. **swapon**:启用交换空间。\r\n\r\n287. **switch_root**:切换到新的根文件系统。\r\n\r\n288. **sync**:同步文件系统。\r\n\r\n289. **sysctl**:显示或设置内核参数。\r\n\r\n290. **syslogd**:启动系统日志守护进程。\r\n\r\n291. **tac**:反向显示文件内容。\r\n\r\n292. **tail**:显示文件的最后部分。\r\n\r\n293. **tar**:创建和解压 tar 归档。\r\n\r\n294. **tc**:配置网络流量控制。\r\n295. **tcpsvd**:TCP 服务守护进程。\r\n296. **tee**:将输入内容输出到多个文件。\r\n297. **telnet**:远程登录到另一个计算机。\r\n298. **telnetd**:启动 Telnet 服务器。\r\n299. **test**:检查条件的真假。\r\n300. **tftp**:简易的文件传输协议客户端。\r\n301. **tftpd**:TFTP 服务器。\r\n302. **time**:测量命令执行时间。\r\n303. **timeout**:设置命令的超时时间。\r\n304. **top**:显示系统进程信息。\r\n305. **touch**:创建空文件或更新文件的时间戳。\r\n306. **tr**:替换或删除字符。\r\n307. **traceroute**:追踪数据包在网络中的路由。\r\n308. **traceroute6**:追踪 IPv6 数据包的路由。\r\n309. **tree**:以树形结构显示目录内容。\r\n310. **true**:始终返回成功状态。\r\n311. **truncate**:截断文件到指定长度。\r\n312. **ts**:为每行添加时间戳。\r\n313. **tsort**:排序文件中的时间戳。\r\n314. **tty**:显示终端设备名称。\r\n315. **ttysize**:显示终端的大小。\r\n316. **tunctl**:管理 TUN/TAP 网络设备。\r\n317. **tune2fs**:调整 ext2/ext3/ext4 文件系统的参数。\r\n318. **ubiattach**:附加 UBI 设备。\r\n319. **ubidetach**:分离 UBI 设备。\r\n320. **ubimkvol**:创建 UBI 卷。\r\n321. **ubirename**:重命名 UBI 卷。\r\n322. **ubirmvol**:删除 UBI 卷。\r\n323. **ubirsvol**:恢复 UBI 卷。\r\n324. **ubiupdatevol**:更新 UBI 卷的数据。\r\n325. **udhcpc**:DHCP 客户端,用于获取网络配置信息。\r\n326. **udhcpc6**:DHCPv6 客户端。\r\n327. **udhcpd**:DHCP 服务器。\r\n328. **udpsvd**:UDP 服务守护进程。\r\n329. **uevent**:显示系统的 udev 事件。\r\n330. **umount**:卸载文件系统。\r\n331. **uname**:显示系统信息。\r\n332. **uncompress**:解压 `.Z` 格式文件。\r\n333. **unexpand**:将空格转换为制表符。\r\n334. **uniq**:删除重复的行。\r\n335. **unix2dos**:转换 Unix 格式文本为 DOS 格式。\r\n336. **unlink**:删除文件。\r\n337. **unlzma**:解压 `.lzma` 格式文件。\r\n338. **unlzop**:解压 `.lzo` 格式文件。\r\n339. **unshare**:在新命名空间中运行命令。\r\n340. **unxz**:解压 `.xz` 格式文件。\r\n341. **unzip**:解压 `.zip` 文件。\r\n342. **uptime**:显示系统的运行时间和负载。\r\n343. **usleep**:暂停指定的微秒数。\r\n344. **uudecode**:解码 `.uu` 格式文件。\r\n345. **uuencode**:编码文件为 `.uu` 格式。\r\n346. **vconfig**:管理 VLAN 网络接口。\r\n347. **vi**:文本编辑器。\r\n348. **volname**:显示文件系统的卷标。\r\n349. **watch**:定期执行并显示命令输出。\r\n350. **watchdog**:监控系统状态并在需要时重启。\r\n351. **wc**:计算文件的行数、字数和字符数。\r\n352. **wget**:下载文件。\r\n353. **which**:显示可执行文件的路径。\r\n354. **whoami**:显示当前用户的用户名。\r\n355. **whois**:查询域名注册信息。\r\n356. **xargs**:将标准输入转换为命令行参数。\r\n357. **xxd**:创建十六进制转储。\r\n358. **xz**:压缩文件为 `.xz` 格式。\r\n359. **xzcat**:查看 `.xz` 格式文件内容。\r\n360. **yes**:输出指定字符串,通常用来测试管道。\r\n361. **zcat**:查看 `.gz` 格式文件内容。\r\n362. **zcip**:配置 ZCIP 地址。\r\n\r\n这些命令覆盖了文件操作、系统管理、网络配置、进程管理等多个方面,是 BusyBox 在资源受限环境中为用户提供常用功能的集合。\r\n", + "Linux/busybox玩法总结.md": "### 一句命令启动busybox的简单http服务器\r\n\r\n```shell\r\nbusybox httpd -f -p 端口 -h 目录\r\n```\r\n\r\n### 使用 `busybox netstat` 查看端口占用情况\r\n\r\n- `-t`:显示 TCP 连接\r\n- `-u`:显示 UDP 连接\r\n- `-l`:只显示正在监听的端口\r\n- `-n`:显示数字形式的地址和端口号,而不进行域名解析\r\n\r\n```shell\r\nbusybox netstat -tuln\r\n```\r\n\r\n### 启动busybox的ftp服务器\r\n\r\n```shell\r\nbusybox ftp -d 目录 -p 端口\r\nbusybox ftp -d 目录 #默认占用21端口\r\n\r\nsudo mkdir -p 目录\r\nsudo chmod 755 目录\r\n\r\n```\r\n\r\n### 启动 `busybox` 的 Telnet 服务器(不安全的ssh)\r\n\r\n```\r\nbusybox telnetd -l /bin/login\r\nbusybox telnetd -p 2323 -l /bin/login\r\n\r\n```\r\n\r\n", + "Linux/crontab的使用.md": "`crontab` 是一个用于在 Unix 和类 Unix 系统(如 Linux)中设置定时任务的工具。它允许用户根据指定的时间间隔安排脚本或命令的执行。以下是关于 `crontab` 使用方法的详细介绍和示例。\r\n\r\n### 基本概念\r\n`crontab` 的配置文件由一系列行组成,每行代表一个定时任务,其基本格式如下:\r\n```plaintext\r\n* * * * * command\r\n```\r\n这五个 `*` 分别代表分钟(0 - 59)、小时(0 - 23)、日期(1 - 31)、月份(1 - 12)和星期(0 - 7,其中 0 和 7 都代表星期日),`command` 是要执行的命令或脚本。\r\n\r\n### 使用步骤\r\n\r\n#### 1. 编辑 `crontab` 文件\r\n可以使用以下命令编辑当前用户的 `crontab` 文件:\r\n```bash\r\ncrontab -e\r\n```\r\n首次使用时,系统会提示选择一个文本编辑器,选择你熟悉的编辑器(如 `nano` 或 `vim`)即可。\r\n\r\n#### 2. 添加定时任务\r\n在打开的 `crontab` 文件中添加定时任务,下面是一些具体的示例:\r\n\r\n##### 示例 1:每分钟执行一次命令\r\n```plaintext\r\n* * * * * /usr/bin/echo \"This is a test\" >> /tmp/test.log\r\n```\r\n这个任务会每分钟执行一次,将 `\"This is a test\"` 追加到 `/tmp/test.log` 文件中。\r\n\r\n##### 示例 2:每小时的第 30 分钟执行一次命令\r\n```plaintext\r\n30 * * * * /usr/bin/backup_script.sh\r\n```\r\n这个任务会在每小时的第 30 分钟执行 `/usr/bin/backup_script.sh` 脚本。\r\n\r\n##### 示例 3:每天凌晨 2 点执行一次命令\r\n```plaintext\r\n0 2 * * * /usr/bin/daily_cleanup.sh\r\n```\r\n这个任务会在每天凌晨 2 点执行 `/usr/bin/daily_cleanup.sh` 脚本。\r\n\r\n##### 示例 4:每月 1 号的 3 点 15 分执行一次命令\r\n```plaintext\r\n15 3 1 * * /usr/bin/monthly_report.sh\r\n```\r\n这个任务会在每月 1 号的 3 点 15 分执行 `/usr/bin/monthly_report.sh` 脚本。\r\n\r\n##### 示例 5:每周日的 18 点执行一次命令\r\n```plaintext\r\n0 18 * * 0 /usr/bin/weekly_backup.sh\r\n```\r\n这个任务会在每周日的 18 点执行 `/usr/bin/weekly_backup.sh` 脚本。\r\n\r\n##### 示例 6:指定时间范围执行命令\r\n```plaintext\r\n0 9-17 * * 1-5 /usr/bin/workday_check.sh\r\n```\r\n这个任务会在周一至周五的 9 点到 17 点之间,每小时的整点执行 `/usr/bin/workday_check.sh` 脚本。\r\n\r\n##### 示例 7:每隔一段时间执行命令\r\n```plaintext\r\n*/15 * * * * /usr/bin/check_status.sh\r\n```\r\n这个任务会每隔 15 分钟执行一次 `/usr/bin/check_status.sh` 脚本。\r\n\r\n#### 3. 保存并退出\r\n编辑完成后,保存并退出文本编辑器。如果使用 `nano` 编辑器,按 `Ctrl + X`,然后按 `Y` 确认保存,最后按 `Enter` 键退出。如果使用 `vim` 编辑器,按 `Esc` 键,输入 `:wq` 并按 `Enter` 键保存并退出。\r\n\r\n#### 4. 查看 `crontab` 文件内容\r\n可以使用以下命令查看当前用户的 `crontab` 文件内容:\r\n```bash\r\ncrontab -l\r\n```\r\n\r\n#### 5. 删除 `crontab` 文件\r\n如果需要删除当前用户的所有定时任务,可以使用以下命令:\r\n```bash\r\ncrontab -r\r\n```\r\n\r\n### 注意事项\r\n- **环境变量**:`crontab` 任务在执行时使用的环境变量可能与用户登录时不同。如果脚本依赖特定的环境变量,需要在脚本中明确设置。\r\n- **日志记录**:建议将定时任务的输出重定向到日志文件,以便后续排查问题。\r\n- **权限问题**:确保执行的命令或脚本具有足够的权限。\r\n", + "Linux/docker,LXC,qemu,k8s,chroot等的特点.md": "\r\n以下从技术定义、核心原理、特点、区别及相互关系等方面,详细解析 **LXC、Docker、chroot、虚拟机、QEMU、K8s** 的概念及关联:\r\n\r\n\r\n### **一、核心技术定义与原理**\r\n#### 1. **chroot**\r\n- **本质**:Linux 系统调用,用于修改进程的“根目录”(`/`),创建一个隔离的文件系统视图。\r\n- **原理**:通过 `chroot` 命令,指定一个新的根目录,进程只能访问该目录下的文件(类似“伪根”),但不隔离 CPU、内存、网络等资源。\r\n- **特点**:\r\n - 最轻量的隔离,仅文件系统隔离,无资源限制。\r\n - 进程仍共享宿主机内核、进程空间、网络栈等。\r\n - 非完整容器,常用于调试、环境隔离(如构建跨平台程序)。\r\n\r\n#### 2. **LXC(Linux Containers)**\r\n- **本质**:基于 Linux 内核特性(`namespace` 命名空间 + `cgroups` 资源控制)的操作系统级容器。\r\n- **原理**:\r\n - `namespace`:隔离进程、网络、文件系统、用户等资源(如 `PID namespace` 使容器内进程号独立)。\r\n - `cgroups`:限制容器的 CPU、内存、磁盘 I/O 资源使用。\r\n- **特点**:\r\n - 共享宿主机内核,启动快(秒级),资源占用低。\r\n - 提供接近虚拟机的隔离性,但轻量高效。\r\n - 需要手动配置,侧重系统级隔离(如运行完整的 Linux 发行版)。\r\n\r\n#### 3. **Docker**\r\n- **本质**:基于容器技术的应用打包与部署平台,核心是容器运行时(`runc`,基于 Open Container Initiative 标准)。\r\n- **原理**:\r\n - 继承 LXC 的 `namespace` 和 `cgroups`,但更上层,封装了镜像(`Image`)、容器(`Container`)、仓库(`Registry`)流程。\r\n - 通过镜像分层技术(UnionFS)实现快速打包,通过 `Docker Engine` 管理容器生命周期。\r\n- **特点**:\r\n - 聚焦“应用容器化”,强调“一次构建,到处运行”。\r\n - 比 LXC 更易用(标准化 API、自动化部署),适合微服务、CI/CD。\r\n - 镜像生态丰富(Docker Hub),但隔离性略弱于 LXC(共享内核,依赖宿主机内核版本)。\r\n\r\n#### 4. **虚拟机(Virtual Machine, VM)**\r\n- **本质**:通过虚拟化技术模拟完整硬件环境,运行独立操作系统。\r\n- **分类与原理**:\r\n - **全虚拟化**(如 VMware Workstation):Hypervisor 完全模拟硬件,Guest OS 无需修改。\r\n - **半虚拟化**(如 Xen):Guest OS 知道自己运行在虚拟机中,通过 Hypercall 与 Hypervisor 交互。\r\n - **硬件辅助虚拟化**(如 Intel VT-x):CPU 直接支持虚拟化,提升性能。\r\n- **特点**:\r\n - 隔离性最强(独立内核、硬件资源),支持不同操作系统(如 Windows 跑在 Linux 宿主机上)。\r\n - 资源开销大(需模拟硬件,启动慢,内存/CPU 占用高)。\r\n - 适合需要完整 OS 环境的场景(如测试不同系统、遗留应用迁移)。\r\n\r\n#### 5. **QEMU**\r\n- **本质**:开源的通用模拟器和虚拟机监视器(Virtual Machine Monitor, VMM)。\r\n- **原理**:\r\n - 单独使用时,通过软件模拟目标硬件(如在 x86 上运行 ARM 程序),性能较低。\r\n - 与 **KVM**(Kernel-based Virtual Machine,Linux 内核模块)结合时,利用硬件虚拟化技术(如 VT-x),成为高效的虚拟机引擎(QEMU-KVM)。\r\n- **特点**:\r\n - 跨平台兼容性强,支持多种架构(x86、ARM、RISC-V 等)。\r\n - 是虚拟机技术的具体实现之一,常作为 KVM 的用户空间工具。\r\n\r\n#### 6. **K8s(Kubernetes)**\r\n- **本质**:容器编排平台,用于自动化部署、扩展和管理容器化应用。\r\n- **核心功能**:\r\n - 调度容器到节点(Node),支持负载均衡、服务发现。\r\n - 处理容器的生命周期(重启、扩缩容、滚动更新)。\r\n - 提供资源配额、健康检查、故障恢复等机制。\r\n- **特点**:\r\n - 不绑定特定容器运行时(支持 Docker、containerd、runc 等)。\r\n - 解决“大规模容器集群管理”问题,适合微服务架构、云原生应用。\r\n\r\n\r\n### **二、核心区别对比**\r\n| **维度** | **chroot** | **LXC/Docker(容器)** | **虚拟机(含 QEMU-KVM)** | **K8s** |\r\n|-------------------|------------------|------------------------|---------------------------|------------------------|\r\n| **隔离级别** | 文件系统隔离 | 操作系统级隔离(内核共享) | 硬件级隔离(独立内核) | 编排管理层(不涉及底层隔离) |\r\n| **资源共享** | 完全共享 | 共享宿主机内核 | 独立内核,硬件资源模拟 | 管理多个容器/节点的资源 |\r\n| **启动时间** | 瞬间 | 秒级 | 分钟级(需启动 Guest OS) | 不涉及启动,管理已有容器 |\r\n| **资源开销** | 极低 | 低(仅用户空间隔离) | 高(硬件模拟 + 完整 OS) | 额外控制平面开销 |\r\n| **支持的 OS** | 同宿主机内核 | 同宿主机内核 | 任意 OS(如 Windows/Linux) | 不限制,管理容器化应用 |\r\n| **核心目标** | 文件系统隔离 | 轻量应用隔离/部署 | 完整 OS 环境模拟 | 容器集群管理 |\r\n| **典型用途** | 环境调试 | 应用打包、轻量部署 | 多系统测试、遗留应用兼容 | 大规模容器调度、微服务 |\r\n\r\n\r\n### **三、相互关系**\r\n#### 1. **技术栈分层**\r\n```\r\n应用层(K8s)\r\n├─ 容器运行时(Docker/LXC/containerd)\r\n│ ├─ 内核特性(namespace/cgroups)\r\n│ └─ chroot(基础文件系统隔离)\r\n└─ 虚拟化层(虚拟机/QEMU-KVM)\r\n └─ 硬件(CPU/内存/存储,支持 VT-x 等虚拟化技术)\r\n```\r\n\r\n#### 2. **具体关联**\r\n- **chroot 与容器**: \r\n chroot 是容器实现文件系统隔离的基础(如 Docker 镜像的根文件系统通过 chroot 挂载),但容器在此之上增加了 `namespace` 和 `cgroups` 实现完整隔离。\r\n\r\n- **LXC 与 Docker**: \r\n Docker 早期基于 LXC 开发,后转向自有运行时(`libcontainer`,现 `runc`),二者同属容器技术,但定位不同: \r\n - LXC 偏向“系统级容器”(运行完整 Linux 发行版,如 Ubuntu 容器); \r\n - Docker 偏向“应用级容器”(打包单个应用及其依赖,如 Node.js 服务)。\r\n\r\n- **虚拟机与 QEMU**: \r\n QEMU 是虚拟机的一种实现方式,单独使用时模拟硬件(慢),与 KVM 结合时利用硬件虚拟化(高效),属于虚拟机技术的底层引擎之一(类似 VirtualBox、VMware 的技术定位)。\r\n\r\n- **K8s 与容器/虚拟机**: \r\n - K8s 主要管理容器(如 Docker 容器),但也可通过虚拟机节点(Node)部署(每个 Node 可以是物理机或虚拟机)。 \r\n - 容器运行在宿主机(物理机或虚拟机)上,K8s 不关心底层是物理机还是虚拟机,只调度容器到节点。\r\n\r\n\r\n### **四、应用场景总结**\r\n- **chroot**:简单文件系统隔离(如构建跨版本软件、修复系统)。 \r\n- **Docker/LXC**:轻量应用部署(微服务、Web 服务),追求资源效率和快速启动。 \r\n- **虚拟机/QEMU-KVM**:需要完整 OS 隔离(如运行 Windows 应用、多租户隔离、硬件兼容性测试)。 \r\n- **K8s**:大规模容器集群管理(微服务架构、弹性扩缩容、高可用部署)。\r\n\r\n\r\n### **五、核心总结**\r\n- **隔离性**:虚拟机(强隔离,独立内核)> 容器(共享内核,OS 级隔离)> chroot(仅文件系统)。 \r\n- **效率**:chroot/容器(高效)> 虚拟机(低效,因硬件模拟)。 \r\n- **关系**: \r\n - 容器技术(LXC/Docker)基于内核特性(namespace/cgroups),chroot 是其文件系统隔离的基础。 \r\n - 虚拟机(如 QEMU-KVM)通过硬件虚拟化实现强隔离,与容器形成互补(容器适合同一 OS 下的应用隔离,虚拟机适合跨 OS 隔离)。 \r\n - K8s 是容器的“上层管理工具”,不依赖特定容器运行时,聚焦集群调度与自动化。\r\n\r\n理解这些技术的核心是明确其“隔离目标”和“资源模型”:容器追求轻量高效,虚拟机追求强隔离,K8s 解决规模化管理问题,而 chroot 是最基础的工具。根据需求选择合适的技术(如部署单个应用用 Docker,多 OS 环境用虚拟机,大规模集群用 K8s 编排容器)。", + "Linux/docker配置.md": "QQ机器人(napcat)\r\ndocker run -d \\\r\n-e NAPCAT_GID=$(id -g) \\\r\n-e NAPCAT_UID=$(id -u) \\\r\n-p 3000:3000 \\\r\n-p 3001:3001 \\\r\n-p 3002:6099 \\\r\n--name napcat \\\r\n--restart=always \\\r\nmlikiowa/napcat-docker:latest\r\n\r\n微信机器人(gewe)\r\ndocker run -itd -v /shumengya/bin/wechatbot:/root/temp -p 2531:2531 -p 2532:2532 --privileged=true --name=gewe gewe /usr/sbin/init\r\n\r\n\r\n\r\n", + "Linux/frp配置.md": "### 使用 yum 安装 systemd(CentOS/RHEL)\r\n```\r\nyum install systemd\r\n```\r\n\r\n\r\n\r\n### 使用 apt 安装 systemd(Debian/Ubuntu)\r\n```\r\napt install systemd\r\nsudo vim /etc/systemd/system/frps.service\r\n```\r\n\r\n\r\n\r\n### 服务名称,可自定义\r\n```\r\nDescription = frp server\r\nAfter = network.target syslog.target\r\nWants = network.target\r\n\r\n[Service]\r\nType = simple\r\n```\r\n\r\n\r\n### 启动frps的命令,需修改为您的frps的安装路径\r\n```\r\nExecStart = /path/to/frps -c /path/to/frps.toml\r\n\r\n[Install]\r\nWantedBy = multi-user.target\r\n```\r\n\r\n\r\n\r\n### 启动frp\r\n```\r\nsudo systemctl start frps\r\n```\r\n\r\n\r\n### 停止frp\r\n```\r\nsudo systemctl stop frps\r\n```\r\n\r\n\r\n### 重启frp\r\n```\r\nsudo systemctl restart frps\r\n```\r\n\r\n\r\n### 查看frp状态\r\n```\r\nsudo systemctl status frps\r\nsudo systemctl enable frps\r\n```\r\n\r\n", + "Linux/Git常用命令.md": "```shell\r\ngit remote add origin \r\ngit remote add origin https://github.com/shumengya6666666/Pixel-plane-wars.git\r\ngit remote add origin git@github.com:shumengya6666666/Pixel-plane-wars.git\r\ngit remote set-url origin git@github.com:shumengya6666666/Pixel-plane-wars.git\r\ngit clone git@github.com:shumengya6666666/Pixel-plane-wars.git\r\ngit remote add origin git@github.com:shumengya6666666/Pixel-Odyssey.git\r\ngit push -u origin main\r\ngit remote add origin git@github.com:shumengya6666666/Sprout-Farm.git\r\ngit remote set-url origin git@github.com:shumengya6666666/Sprout-Farm.git\r\ngit push -u origin master\r\ngit remote add origin git@github.com:shumengya6666666/Pixel-plane-wars.git\r\n```\r\n\r\n", + "Linux/Linux zip 命令总结.md": "\n1. 打包单个文件:\n\n```\nzip 压缩包名称.zip 要打包的文件\n```\n\n2. 打包多个文件:\n\n```\nzip 压缩包名称.zip 文件1 文件2 文件3\n```\n\n3. 打包整个目录(包括子目录):\n\n```\nzip -r 压缩包名称.zip 要打包的目录\n```\n\n4. 打包目录并排除某些文件:\n\n```\nzip -r 压缩包名称.zip 要打包的目录 -x 要排除的文件或目录\n```\n\n5. 带密码打包:\n\n```\nzip -r -e 压缩包名称.zip 要打包的目录\n```\n\n执行后会提示你输入密码\n\n例如,要打包当前目录下的documents文件夹为backup.zip,可以使用:\n\n```\nzip -r backup.zip documents\n```\n\n如果系统中没有zip命令,可以先安装:\n\n- Debian/Ubuntu: sudo apt install zip\n", + "Linux/Linux一些奇奇怪怪的命令.md": "打开终端tmoe面板:\ncurl -LO https://gitee.com/mo2/linux/raw/2/2.awk\nawk -f 2.awk\n\nubuntu和deepin系统安装宝塔面板:\nwget -O install.sh https://download.bt.cn/install/install_lts.sh && sudo bash install.sh ed8484bec\n\n重启宝塔面板:\nbt restart\n\n开启宝塔面板:\nbt default\n\n安装和运行casaos轻量nas系统:\ncurl -fsSL https://get.casaos.io | sudo bash\n\n安装和运行1panel面板:\ncurl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh\n\n连接ssh示例\n\nssh root@192.168.25.151 -p 6003", + "Linux/Linux下的scp命令总结.md": "Linux scp 命令总结\n用途:安全复制文件/目录到本地或远程主机(基于 SSH 协议)。\n \n基本语法\n \nscp [选项] 源文件 目标路径\n \n \n常用选项\n \n选项 说明 \n -r  递归复制目录及子目录 \n -P   指定 SSH 端口(注意大写 P) \n -i   使用指定的私钥文件认证 \n -C  压缩传输数据 \n -p  保留文件属性(时间戳、权限等) \n -v  显示详细传输过程 \n \n典型示例\n \n1. 本地文件 → 远程主机\n \nscp local_file.txt user@remote_host:/path/to/remote_dir/\n \n2. 远程文件 → 本地\n \nscp user@remote_host:/path/to/remote_file.txt ~/local_dir/\n \n3. 复制目录(需加  -r )\n \nscp -r local_dir/ user@remote_host:/path/to/remote_dir/\n \n4. 远程主机间复制(通过本地中转)\n \nscp user1@host1:/file.txt user2@host2:/path/\n \n5. 指定端口(如非默认 22 端口)\n \nscp -P 2222 local_file.txt user@remote_host:/remote_path/\n \n6. 使用私钥认证\n \nscp -i ~/.ssh/id_rsa local_file.txt user@remote_host:/remote_path/\n \n \n注意事项\n \n- 远程路径需以  user@host:  开头。\n- 目标路径不存在时会自动创建(目录需  -r )。\n- 若提示权限问题,检查私钥文件权限(需  chmod 600 )。", + "Linux/Linux不同格式解压命令.md": "在 Linux 中解压不同格式的压缩文件,可使用以下命令:\n \n1. tar.gz 文件\n \ntar -xzf filename.tar.gz\n \n \n- 说明:\n x  表示解压, z  调用 gzip 解压, f  指定文件名。\n \n2. tar.zst 文件\n \ntar --zstd -xf filename.tar.zst\n \n \n- 说明:\n --zstd  明确使用 zstd 解压, x  解压, f  指定文件名。需确保系统已安装  zstd  工具。\n \n3. tar.xz 文件\n \ntar -xJf filename.tar.xz\n \n \n- 说明:\n J  调用 xz 解压, x  解压, f  指定文件名。\n \n补充:若需解压时显示详细过程,可添加  -v  参数(如  tar -xvzf filename.tar.gz )。", + "Linux/Linux后台运行程序.md": "在 Linux 系统中,让服务一直保持在后台运行有多种方法,下面为你详细介绍:\r\n\r\n### 1. 使用 `&` 符号\r\n在命令后面加上 `&` 符号可以让命令在后台运行。\r\n\r\n#### 示例\r\n```bash\r\npython my_script.py &\r\n```\r\n上述命令会让 `my_script.py` 脚本在后台运行。\r\n\r\n#### 注意事项\r\n- 这种方式虽然简单,但当你关闭当前终端会话时,该进程可能会收到 `SIGHUP` 信号而终止。\r\n- 你可以使用 `jobs` 命令查看当前终端中后台运行的作业,使用 `fg` 命令将后台作业调回到前台。\r\n\r\n### 2. 使用 `nohup` 命令\r\n`nohup` 命令可以让程序忽略 `SIGHUP` 信号,从而在你关闭终端后继续运行。\r\n\r\n#### 示例\r\n```bash\r\nnohup python my_script.py > output.log 2>&1 &\r\n```\r\n- `nohup`:用于忽略 `SIGHUP` 信号。\r\n- `> output.log`:将标准输出重定向到 `output.log` 文件。\r\n- `2>&1`:将标准错误输出也重定向到标准输出,即同样写入 `output.log` 文件。\r\n- `&`:让命令在后台运行。\r\n\r\n#### 查看运行状态\r\n使用 `ps` 命令可以查看进程是否还在运行:\r\n```bash\r\nps -ef | grep my_script.py\r\n```\r\n\r\n### 3. 使用 `screen` 工具\r\n`screen` 是一个全屏窗口管理器,它可以创建多个虚拟终端会话,即使你断开连接,会话中的进程仍然会继续运行。\r\n\r\n#### 安装 `screen`\r\n在 Debian 或 Ubuntu 系统上:\r\n```bash\r\nsudo apt-get install screen\r\n```\r\n在 CentOS 或 RHEL 系统上:\r\n```bash\r\nsudo yum install screen\r\n```\r\n\r\n#### 使用步骤\r\n1. 启动一个新的 `screen` 会话:\r\n```bash\r\nscreen\r\n```\r\n2. 在 `screen` 会话中运行你的命令,例如:\r\n```bash\r\npython my_script.py\r\n```\r\n3. 按下 `Ctrl + A` 然后再按下 `D` 组合键,将当前 `screen` 会话分离,此时会话会在后台继续运行。\r\n4. 如果你想重新连接到该会话,可以使用以下命令:\r\n```bash\r\nscreen -r\r\n```\r\n\r\n### 4. 使用 `tmux` 工具\r\n`tmux` 也是一个类似 `screen` 的终端复用工具,功能更强大。\r\n\r\n#### 安装 `tmux`\r\n在 Debian 或 Ubuntu 系统上:\r\n```bash\r\nsudo apt-get install tmux\r\n```\r\n在 CentOS 或 RHEL 系统上:\r\n```bash\r\nsudo yum install tmux\r\n```\r\n\r\n#### 使用步骤\r\n1. 启动一个新的 `tmux` 会话:\r\n```bash\r\ntmux new -s mysession\r\n```\r\n这里的 `mysession` 是会话的名称,你可以自定义。\r\n2. 在 `tmux` 会话中运行你的命令,例如:\r\n```bash\r\npython my_script.py\r\n```\r\n3. 按下 `Ctrl + B` 然后再按下 `D` 组合键,将当前 `tmux` 会话分离。\r\n4. 如果你想重新连接到该会话,可以使用以下命令:\r\n```bash\r\ntmux attach -t mysession\r\n```\r\n\r\n### 5. 使用系统服务管理工具(如 `systemd`)\r\n对于需要长期稳定运行的服务,推荐使用系统服务管理工具,如 `systemd`(大多数现代 Linux 发行版都使用 `systemd`)。\r\n\r\n#### 创建服务文件\r\n创建一个新的服务文件,例如 `/etc/systemd/system/my_script.service`:\r\n```ini\r\n[Unit]\r\nDescription=My Python Script Service\r\nAfter=network.target\r\n\r\n[Service]\r\nExecStart=/usr/bin/python /path/to/my_script.py\r\nWorkingDirectory=/path/to/working/directory\r\nRestart=always\r\nUser=your_username\r\n\r\n[Install]\r\nWantedBy=multi-user.target\r\n```\r\n- `Description`:服务的描述信息。\r\n- `After`:指定服务在网络服务启动后再启动。\r\n- `ExecStart`:指定要执行的命令。\r\n- `WorkingDirectory`:指定工作目录。\r\n- `Restart`:设置为 `always` 表示服务崩溃或停止后会自动重启。\r\n- `User`:指定运行服务的用户。\r\n\r\n#### 启动和管理服务\r\n```bash\r\n# 重新加载 systemd 管理器配置\r\nsudo systemctl daemon-reload\r\n# 启动服务\r\nsudo systemctl start my_script.service\r\n# 设置服务开机自启\r\nsudo systemctl enable my_script.service\r\n# 查看服务状态\r\nsudo systemctl status my_script.service\r\n```", + "Linux/Linux命令风格解析.md": "在Linux命令行中,选项的不同书写形式反映了三种主流风格的设计逻辑,以下是结合历史背景与实际应用场景的深度解析:\n\n### 一、Unix/Posix风格:简洁至上的单字符范式\n这是最古老的选项体系,诞生于Unix电传打字机时代。其核心特征是:\n- **符号标识**:必须以单个短横线`-`开头,如`ls -a`\n- **组合规则**:无参数的选项可自由拼接,如`ls -alh`等价于`ls -a -l -h`\n- **参数绑定**:带参数的选项需紧跟值,如`-w50`或`-w 50`均可\n- **历史局限**:受限于26个字母的容量,复杂工具需依赖组合(如`find -type f -exec`)\n\n典型场景:文件操作(`ls`、`cp`)、权限管理(`chmod`)等基础命令。这种风格的高效性在处理批量文件时尤为突出,例如`rm -rf`的组合操作。\n\n### 二、BSD风格:去符号化的实用主义\nBSD操作系统对Unix传统的突破体现在:\n- **无符号标识**:直接使用字母组合,如`ps aux`\n- **灵活组合**:多个选项可连写且无需分隔符,如`tar zxf archive.tar.gz`\n- **参数兼容**:带参数的选项可空格分隔或直接拼接,如`ps Uroot`与`ps U root`等效\n\n这种设计源于BSD对用户体验的优化,例如`ps aux`的组合能直观展示进程全貌。但需注意,并非所有BSD风格选项都能随意组合,如`ps fx`中的`f`和`x`分别控制显示格式和非终端进程,顺序调换可能影响输出。\n\n### 三、GNU风格:可读性优先的长选项\nGNU项目为解决单字符选项的语义模糊问题,引入了:\n- **双横线标识**:以`--`开头的完整单词,如`gzip --help`\n- **参数传递**:支持`--sort=time`或`--sort time`两种格式\n- **缩写机制**:唯一前缀即可生效,如`--cre`可替代`--create`\n- **功能扩展**:突破字母限制,如`wget --user-agent`可自定义请求头\n\n这种风格在复杂工具(如`git`、`docker`)中广泛应用,例如`git commit --amend`比`-a`更清晰。GNU工具通常同时支持长/短选项,如`ls --all`与`-a`等效。\n\n### 四、混合使用的注意事项\n1. **解析优先级**:旧风格选项需置于最前,如`tar cvf --exclude=*.tmp`中`cvf`为传统选项,`--exclude`为GNU选项\n2. **命令特异性**:并非所有命令都支持混合风格,例如`ps`可接受`ps -ef`(Unix风格)和`ps aux`(BSD风格),但`ps -aux`会被解析为混合模式\n3. **参数歧义**:当选项与文件名冲突时,可用`--`终止选项解析,如`rm -- -file`可强制删除名为`-file`的文件\n\n### 五、典型命令的风格对比\n| 命令 | Unix风格 | BSD风格 | GNU风格 |\n|------------|-------------------|-----------------|------------------|\n| 解压缩 | `tar -zxf file` | `tar zxf file` | `tar --gzip --extract --file=file` |\n| 进程查看 | `ps -ef` | `ps aux` | `ps --forest` |\n| 显示帮助 | `ls -h` | `ls h`(无效) | `ls --help` |\n\n### 六、历史演变与实践建议\n- **工具适配**:GNU工具普遍兼容多种风格,而BSD衍生工具(如`freebsd`的`ps`)可能仅支持特定格式\n- **学习路径**:新手建议从GNU长选项入手(如`--help`),逐步掌握短选项组合\n- **文档依赖**:使用`man`或`--help`查看具体命令的选项说明,例如`tar --help`会列出所有支持的风格\n\n理解这些风格差异,不仅能更高效地使用命令行,还能深入体会不同开发社区的设计哲学。例如,GNU的长选项体现了自由软件运动对可读性的追求,而BSD的简洁风格则延续了Unix“做一件事并做好”的理念。在实际应用中,可根据场景灵活选择:快速操作时用短选项,复杂配置时用长选项,疑难问题则结合`--help`与`man`手册。\n", + "Linux/Linux复制文件命令.md": "在 Linux 中,可以使用 `cp` 命令将某个路径的文件复制到另一个位置。命令格式如下:\r\n\r\n```bash\r\ncp 源文件路径 目标路径\r\n```\r\n\r\n### 示例\r\n假设要将 `/home/user/file.txt` 复制到 `/home/user/documents/`,命令如下:\r\n\r\n```bash\r\ncp /home/user/file.txt /home/user/documents/\r\n```\r\n\r\n### 选项\r\n- **`-r`**:复制目录及其内容。\r\n- **`-i`**:覆盖前提示确认。\r\n- **`-v`**:显示复制进度。\r\n\r\n### 示例\r\n1. **复制目录**:\r\n ```bash\r\n cp -r /home/user/folder /home/user/documents/\r\n ```\r\n\r\n2. **覆盖前提示**:\r\n ```bash\r\n cp -i /home/user/file.txt /home/user/documents/\r\n ```\r\n\r\n3. **显示进度**:\r\n ```bash\r\n cp -v /home/user/file.txt /home/user/documents/\r\n ```\r\n\r\n### 总结\r\n`cp` 命令用于复制文件或目录,常用选项包括 `-r`、`-i` 和 `-v`。", + "Linux/linux安装nodejs22.md": "apt install curl\n\n# Download and install nvm:\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash\n\n# in lieu of restarting the shell\n\\. \"$HOME/.nvm/nvm.sh\"\n\n# Download and install Node.js:\nnvm install 22\n\n# Verify the Node.js version:\nnode -v # Should print \"v22.19.0\".\n\n# Verify npm version:\nnpm -v # Should print \"10.9.3\".\n\n", + "Linux/Linux安装ollama.md": "apt install tur-repo\napt install ollama\nollama serve\n重新开启个会话\n安装各种开源模型\n", + "Linux/Linux常用软件包安装.md": "```bash\nsudo apt install docker-compose -y\n```", + "Linux/Linux查看无线网口.md": "在Debian系统中,可以通过以下几种方法查看使用的无线网卡的名称:\r\n\r\n### 使用命令行工具`ifconfig`\r\n1. 打开终端,输入命令`ifconfig -a`。\r\n2. 该命令会列出系统中所有的网络接口,包括有线网卡、无线网卡等。通常无线网卡的名称会以`wlan`开头,如`wlan0`、`wlan1`等。你可以根据网卡的相关信息(如MAC地址、IP地址等)来确定具体使用的无线网卡。\r\n\r\n### 使用`iwconfig`命令\r\n1. 在终端中输入`iwconfig`。\r\n2. 此命令主要用于配置无线网卡,它会显示出系统中的无线接口信息,包括无线网卡的名称、频率、信号强度等。通过识别无线网卡的相关参数,能找到正在使用的无线网卡名称。\r\n\r\n### 查看`/sys/class/net/`目录\r\n1. 打开终端,输入命令`ls /sys/class/net/`。\r\n2. 该目录下列出了系统中所有的网络设备接口文件,无线网卡的名称通常也以`wlan`开头,通过查看该目录可以找到无线网卡的名称。\r\n\r\n### 使用`nmcli`命令\r\n1. 确保`NetworkManager`服务已安装并运行,然后在终端中输入`nmcli device status`。\r\n2. 该命令会显示系统中网络设备的状态信息,包括设备名称、设备类型、状态等。在设备类型为`wifi`的行中,可以找到无线网卡的名称。", + "Linux/Linux的Proc目录解析.md": " `/proc` 在 Linux 中是一个 **伪文件系统 (procfs)**,它不是存储在磁盘上的真实文件,而是内核在内存中动态生成的接口,主要用于提供 **内核、进程和系统状态** 的信息。几乎所有的监控工具(如 `top`、`htop`、`ps`、`free`、`uptime`、`vmstat`、`iostat`)都是通过读取 `/proc` 下的文件获取数据的。\n \n---\n\n# 🗂 **/proc 能查看的信息汇总**\n\n## 1. **进程相关信息**\n\n每个正在运行的进程在 `/proc` 下都会有一个以 **PID** 命名的目录,例如 `/proc/1234/`。里面的内容主要是该进程的状态:\n\n- `/proc/[pid]/cmdline` → 启动命令行参数\n \n- `/proc/[pid]/cwd` → 当前工作目录 (符号链接)\n \n- `/proc/[pid]/exe` → 可执行文件路径 (符号链接)\n \n- `/proc/[pid]/environ` → 环境变量\n \n- `/proc/[pid]/fd/` → 打开的文件描述符\n \n- `/proc/[pid]/maps` → 内存映射情况\n \n- `/proc/[pid]/stat` → 进程状态、运行时间、优先级等\n \n- `/proc/[pid]/status` → 可读性较好的进程状态信息\n \n- `/proc/[pid]/task/` → 线程信息(子目录为线程 ID)\n \n\n---\n\n## 2. **CPU 相关信息**\n\n- `/proc/cpuinfo` → CPU 型号、核心数、主频、缓存大小、虚拟化支持等\n \n- `/proc/stat` → CPU 使用率、上下文切换、中断次数等\n \n- `/proc/interrupts` → 中断统计\n \n- `/proc/softirqs` → 软中断统计\n \n\n---\n\n## 3. **内存信息**\n\n- `/proc/meminfo` → 总内存、可用内存、缓存、swap 等\n \n- `/proc/kcore` → 内核内存映射(类似物理内存的转储)\n \n- `/proc/vmallocinfo` → 内核虚拟内存使用情况\n \n- `/proc/slabinfo` → 内核对象缓存(slab 分配器)\n \n\n---\n\n## 4. **系统信息**\n\n- `/proc/version` → 内核版本信息\n \n- `/proc/uptime` → 系统运行时间和空闲时间\n \n- `/proc/loadavg` → 系统平均负载\n \n- `/proc/cmdline` → 内核启动参数\n \n- `/proc/modules` → 已加载的内核模块\n \n- `/proc/filesystems` → 支持的文件系统类型\n \n- `/proc/mounts` → 当前挂载的文件系统(和 `mount` 命令一致)\n \n- `/proc/partitions` → 磁盘分区信息\n \n- `/proc/devices` → 已注册的设备\n \n- `/proc/ioports` → I/O 端口使用情况\n \n- `/proc/iomem` → 内存映射的 I/O 信息\n \n- `/proc/diskstats` → 磁盘 I/O 统计\n \n- `/proc/locks` → 当前内核中的文件锁\n \n\n---\n\n## 5. **网络信息**\n\n在 `/proc/net/` 目录下:\n\n- `/proc/net/dev` → 网络接口的流量统计(类似 `ifconfig`、`ip -s link`)\n \n- `/proc/net/tcp`、`/proc/net/udp` → TCP/UDP 连接信息(类似 `ss`、`netstat`)\n \n- `/proc/net/unix` → UNIX 套接字信息\n \n- `/proc/net/route` → 路由表\n \n- `/proc/net/arp` → ARP 缓存表\n \n- `/proc/net/snmp` → 网络协议统计信息(ICMP、TCP、UDP)\n \n\n---\n\n## 6. **内核配置与参数**\n\n- `/proc/sys/` → 内核参数(可读可写,可通过 `sysctl` 修改),例如:\n \n - `/proc/sys/net/ipv4/ip_forward` → 是否启用 IPv4 转发\n \n - `/proc/sys/kernel/hostname` → 主机名\n \n - `/proc/sys/kernel/pid_max` → 最大进程号\n \n - `/proc/sys/vm/swappiness` → 内存换出策略\n \n\n---\n\n## 7. **其他有用的文件**\n\n- `/proc/self/` → 当前进程(即访问 `/proc` 的进程本身)的信息\n \n- `/proc/kmsg` → 内核日志(类似 `dmesg`)\n \n- `/proc/sched_debug` → 调度器的调试信息\n \n- `/proc/zoneinfo` → 内存区域信息\n \n- `/proc/swap` → swap 使用情况\n \n\n---\n\n# 📊 **总结**\n\n通过 `/proc`,你可以获取:\n\n1. **进程级别** → PID、内存、CPU、线程、文件描述符\n \n2. **系统级别** → CPU、内存、负载、启动参数、模块、文件系统\n \n3. **硬件级别** → 设备、中断、I/O 端口、内存映射\n \n4. **网络级别** → 接口流量、TCP/UDP 连接、路由、ARP\n \n5. **内核级别** → 内核参数、调度、日志、虚拟内存\n \n\n---\n", + "Linux/Linux软件包存放地址.md": "在 Linux 系统中,安装的软件包通常会放置在以下几个目录中,具体路径取决于软件包的类型和安装方式。\r\n\r\n### 1. **二进制文件(可执行文件)**\r\n - **`/usr/bin/`**:大多数用户安装的软件的二进制文件都会安装在此目录下。这些是常见的应用程序和命令(例如 `ls`, `cp`, `git` 等)。\r\n - **`/bin/`**:存放一些最基本的系统命令,这些命令在系统的任何时候都需要可用,通常在恢复模式下也能使用。\r\n - **`/usr/local/bin/`**:用户自己安装的软件(通常是通过源代码编译安装的软件)会放在这个目录下。它优先级高于 `/usr/bin/`,因此用户安装的命令会覆盖系统自带的软件。\r\n - **`/sbin/` 和 `/usr/sbin/`**:这些目录通常存放的是系统管理工具,需要管理员权限来使用。比如 `ifconfig`, `mount` 等。\r\n\r\n### 2. **库文件**\r\n - **`/lib/`**:包含了系统启动和运行时所必需的共享库(例如 C 库)。\r\n - **`/usr/lib/`**:用于存放大多数安装的软件包的共享库,支持应用程序的运行。\r\n - **`/usr/local/lib/`**:与 `/usr/local/bin/` 类似,这是存放用户手动安装的程序和库的地方。\r\n\r\n### 3. **配置文件**\r\n - **`/etc/`**:这是系统和应用程序的全局配置文件所在的目录。几乎所有的配置文件都可以在这里找到。例如 `/etc/passwd` 存放用户信息,`/etc/ssh/sshd_config` 存放 SSH 配置等。\r\n - **`/usr/local/etc/`**:对于用户自己安装的软件包,它的配置文件一般会放在此目录下。\r\n\r\n### 4. **文档和帮助文件**\r\n - **`/usr/share/`**:存放共享的数据文件,包括应用程序的文档、帮助文件、图标等。例如 `/usr/share/doc/` 目录存放着已安装软件包的文档和许可证。\r\n - **`/usr/local/share/`**:用户自己安装的软件的共享数据文件通常存放在此目录。\r\n\r\n### 5. **临时文件**\r\n - **`/tmp/`**:这个目录用于存放临时文件,系统或应用程序运行时会使用这个目录来存放临时数据。通常,`/tmp/` 目录中的文件会在系统重启后被删除。\r\n - **`/var/tmp/`**:类似于 `/tmp/`,但 `/var/tmp/` 中的文件不会在系统重启时被清除,适用于需要较长时间存储的临时文件。\r\n\r\n### 6. **日志文件**\r\n - **`/var/log/`**:存放系统和应用程序的日志文件。比如 `/var/log/syslog` 记录了系统日志,`/var/log/auth.log` 记录了认证相关的日志等。\r\n\r\n### 7. **其他相关目录**\r\n - **`/opt/`**:这个目录通常用于存放大型的第三方软件包,特别是那些由供应商提供的独立应用程序(例如 Google Chrome 或 Oracle Java)通常会安装在这个目录。\r\n - **`/home/`**:每个用户的个人目录会在 `/home/` 目录下(例如 `/home/user/`),其中可能包含用户安装的软件或自定义的程序。\r\n\r\n### 总结\r\n- **二进制文件**:`/bin/`、`/usr/bin/`、`/usr/local/bin/`\r\n- **库文件**:`/lib/`、`/usr/lib/`、`/usr/local/lib/`\r\n- **配置文件**:`/etc/`、`/usr/local/etc/`\r\n- **共享数据文件**:`/usr/share/`、`/usr/local/share/`\r\n- **日志文件**:`/var/log/`\r\n- **临时文件**:`/tmp/`、`/var/tmp/`\r\n- **软件包**:`/opt/`(大型第三方应用)\r\n", + "Linux/nodejsmarkdown库.md": "1. **markdown-it**:\r\n \r\n - **简介**: 一个功能强大且可扩展的 Markdown 解析器,支持插件和自定义规则。\r\n - **安装**: 可以通过 npm 安装:`npm install markdown-it`\r\n - **使用示例**:\r\n ```javascript\r\n const MarkdownIt = require('markdown-it');\r\n const md = new MarkdownIt();\r\n const result = md.render('# 你好,Markdown!');\r\n console.log(result);\r\n ```\r\n \r\n2. **marked**:\r\n - **简介**: 一个快速、轻量级的 Markdown 解析器,支持自定义渲染器。\r\n - **安装**: 使用 npm 安装:`npm install marked`\r\n - **使用示例**:\r\n ```javascript\r\n const marked = require('marked');\r\n const result = marked('# 你好,Markdown!');\r\n console.log(result);\r\n ```\r\n\r\n3. **remark**:\r\n - **简介**: 一个强大的 Markdown 处理库,支持解析、检查和转换 Markdown 文档。\r\n - **安装**: 通过 npm 安装:`npm install remark remark-html`\r\n - **使用示例**:\r\n ```javascript\r\n const remark = require('remark');\r\n const html = require('remark-html');\r\n \r\n remark()\r\n .use(html)\r\n .process('# 你好,Markdown!', function (err, file) {\r\n if (err) throw err;\r\n console.log(String(file));\r\n });\r\n ```\r\n\r\n这些库各有优点,选择哪个库取决于您的具体需求,比如性能、可扩展性、支持的特性等。如果你需要简单的解析和渲染,`marked` 和 `markdown-it` 都是不错的选择;如果需要更多的可扩展性和插件支持,`remark` 可能更适合。", + "Linux/QQ机器人napcat命令.md": "输入 xvfb-run -a qq --no-sandbox 命令启动。 \r\n保持后台运行 请输入 screen -dmS napcat bash -c \"xvfb-run -a qq --no-sandbox\" \r\n后台快速登录 请输入 screen -dmS napcat bash -c \"xvfb-run -a qq --no-sandbox -q QQ号码\" \r\nNapcat安装位置 /opt/QQ/resources/app/app_launcher/napcat \r\nWEBUI_TOKEN 请自行查看/opt/QQ/resources/app/app_launcher/napcat/config/webui.json文件获取 \r\n注意, 您可以随时使用 screen -r napcat 来进入后台进程并使用 ctrl + a + d 离开(离开不会关闭后台进程)。 \r\n停止后台运行 \r\n\r\n screen -S napcat -X quit ", + "Linux/screen常用指令.md": "## `screen`命令简介\r\n\r\n`screen` 是一个窗口管理器,允许用户在一个单一的终端窗口中运行多个会话。它特别适用于需要长时间运行的进程,因为即使网络连接断开,进程也会继续运行。\r\n\r\n## 常用命令\r\n\r\n### 启动和使用\r\n\r\n- **启动一个新的screen会话**\r\n ```bash\r\n screen\r\n ```\r\n 或者为会话命名:\r\n ```bash\r\n screen -S session_name\r\n ```\r\n\r\n- **列出所有screen会话**\r\n ```bash\r\n screen -ls\r\n ```\r\n\r\n- **重新连接到一个已存在的screen会话**\r\n ```bash\r\n screen -r session_name\r\n ```\r\n\r\n- **分离当前会话(让会话在后台继续运行)**\r\n 按下 `Ctrl + A` 然后按 `D`。\r\n\r\n- **终止一个screen会话**\r\n 在会话中按下 `Ctrl + D` 或者输入 `exit`。\r\n\r\n### 会话管理\r\n\r\n- **强制连接到一个会话**\r\n 如果有多个会话在运行,使用:\r\n ```bash\r\n screen -r -d session_name\r\n ```\r\n 这将断开该会话的其他连接并连接到它。\r\n\r\n- **多窗口管理**\r\n - 创建新窗口:`Ctrl + A` 然后 `C`\r\n - 切换窗口:`Ctrl + A` 然后 `N`(下一个),`Ctrl + A` 然后 `P`(上一个)\r\n - 列出所有窗口:`Ctrl + A` 然后 `\"`(双引号)\r\n\r\n### 会话命名\r\n\r\n- **重命名当前窗口**\r\n 按下 `Ctrl + A` 然后 `A`,输入新的名称。\r\n\r\n## 配置文件\r\n\r\n- **自定义screen**\r\n 可以通过编辑 `~/.screenrc` 文件进行配置。例如:\r\n ```bash\r\n # 开启多窗口状态栏\r\n hardstatus on\r\n hardstatus alwayslastline\r\n hardstatus string \"%{= kG}%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<\"\r\n ```\r\n\r\n## 提示\r\n\r\n- 使用 `screen` 可以有效防止因网络不稳定导致的会话中断。\r\n- 熟练掌握快捷键可以大大提高效率。\r\n- 对于需要长期运行的任务,如编译或数据处理,`screen` 是一个非常有用的工具。\r\n\r\n", + "Linux/SSH服务端配置.md": "配置 SSH 服务端(`sshd_config`)是确保服务器安全性和功能性的关键步骤。以下是基于您提供的默认配置文件的详细配置指南,包括关键选项的解释和安全建议。\n\n### 1. 基本配置\n\n#### 端口设置\n默认情况下,SSH 使用端口 22。为了提高安全性,您可以更改为其他端口。\n\n```bash\nPort 22\n```\n\n**建议**:修改为非标准端口(如 `Port 2222`)可以减少被自动扫描攻击的风险。\n\n```bash\nPort 2222\n```\n\n#### 监听地址\n默认配置监听所有 IPv4 地址。\n\n```bash\nListenAddress 0.0.0.0\n#ListenAddress ::\n```\n\n**建议**:如果服务器有多个网络接口,您可以指定特定的 IP 地址来监听。例如,仅监听内部网络:\n\n```bash\nListenAddress 192.168.1.100\n```\n\n### 2. 主机密钥\n\n主机密钥用于验证服务器的身份。确保这些密钥存在并且安全。\n\n```bash\n#HostKey /etc/ssh/ssh_host_rsa_key\n#HostKey /etc/ssh/ssh_host_ecdsa_key\n#HostKey /etc/ssh/ssh_host_ed25519_key\n```\n\n**建议**:取消注释需要的密钥类型,确保至少启用一种强加密算法(如 Ed25519)。\n\n```bash\nHostKey /etc/ssh/ssh_host_ed25519_key\n```\n\n### 3. 身份验证\n\n#### 禁止 root 登录\n出于安全考虑,建议禁止 root 用户通过 SSH 登录。\n\n```bash\n#PermitRootLogin prohibit-password\n```\n\n**建议**:将其设置为 `no` 或 `prohibit-password`,推荐使用密钥认证。\n\n```bash\nPermitRootLogin no\n```\n\n#### 密码认证\n启用或禁用密码认证。为了更高的安全性,建议使用密钥认证并禁用密码认证。\n\n```bash\n#PasswordAuthentication yes\nPasswordAuthentication no\n```\n\n#### 公钥认证\n确保启用公钥认证,并配置 `AuthorizedKeysFile`。\n\n```bash\nPubkeyAuthentication yes\nAuthorizedKeysFile .ssh/authorized_keys\n```\n\n**建议**:保持默认配置,确保每个用户的 `~/.ssh/authorized_keys` 文件中包含正确的公钥。\n\n#### 键盘交互认证\n如果只使用密钥认证,禁用键盘交互认证。\n\n```bash\nKbdInteractiveAuthentication no\n```\n\n### 4. 使用 PAM\n\nPAM(可插拔认证模块)用于增强认证机制。\n\n```bash\nUsePAM yes\n```\n\n**建议**:保持启用,但确保其他认证方法(如密码认证)根据需要进行配置。\n\n### 5. 限制用户和组\n\n通过 `AllowUsers` 或 `AllowGroups` 限制可以通过 SSH 登录的用户或组。\n\n```bash\n# Allow only specific users\n#AllowUsers user1 user2\n\n# Allow only specific groups\n#AllowGroups sshusers\n```\n\n**建议**:根据需要取消注释并配置,限制访问范围。\n\n```bash\nAllowUsers alice bob\n```\n\n### 6. 其他安全设置\n\n#### 禁用空密码登录\n\n```bash\n#PermitEmptyPasswords no\nPermitEmptyPasswords no\n```\n\n**确保**:禁止使用空密码登录。\n\n#### 启用防火墙和限制连接数\n\n配置防火墙(如 `ufw` 或 `iptables`)仅允许必要的端口和 IP 地址访问。同时,可以设置 `MaxAuthTries` 和 `MaxSessions` 来限制尝试次数和并发会话数。\n\n```bash\nMaxAuthTries 3\nMaxSessions 2\n```\n\n### 7. 日志和监控\n\n设置合适的日志级别以监控 SSH 活动。\n\n```bash\nLogLevel VERBOSE\n```\n\n**建议**:根据需要设置日志级别,如 `INFO` 或 `VERBOSE`,并定期检查日志文件(通常位于 `/var/log/auth.log` 或 `/var/log/secure`)。\n\n### 8. 重启 SSH 服务\n\n在完成配置后,重新启动 SSH 服务以应用更改。\n\n```bash\nsudo systemctl restart sshd\n```\n\n**检查配置是否正确**:\n\n在重新启动之前,最好检查配置文件是否有语法错误:\n\n```bash\nsudo sshd -t\n```\n\n如果没有输出,说明配置语法正确。否则,按照错误提示进行修正。\n\n### 9. 其他推荐配置\n\n- **启用双因素认证(2FA)**:增加登录的安全性。\n- **限制 SSH 登录时间**:通过 `sshd_config` 或使用其他工具限制用户的登录时间。\n- **使用 Fail2Ban**:防止暴力破解攻击,通过监控日志文件并动态更新防火墙规则。\n\n### 示例优化后的 `sshd_config`\n\n以下是根据上述建议优化后的配置示例:\n\n```bash\nPort 2222\nListenAddress 0.0.0.0\nHostKey /etc/ssh/ssh_host_ed25519_key\n\nPubkeyAuthentication yes\nAuthorizedKeysFile .ssh/authorized_keys\n\nPermitRootLogin no\nPasswordAuthentication no\nKbdInteractiveAuthentication no\n\nUsePAM yes\n\nAllowUsers alice bob\n\nLogLevel VERBOSE\n\nMaxAuthTries 3\nMaxSessions 2\n\nAcceptEnv LANG LC_*\n\nSubsystem\tsftp\t/usr/lib/openssh/sftp-server\n```\n\n### 总结\n\n正确配置 SSH 服务端对于保障服务器的安全至关重要。请根据您的具体需求和环境,结合上述指南进行配置。同时,定期审查和更新配置,以应对潜在的安全威胁。", + "Linux/systemctl命令详细总结-豆包.md": "\r\n### Linux `systemctl` 命令常用用法总结\r\n\r\n\r\n#### **一、服务管理(核心功能)**\r\n`systemctl` 主要用于管理系统服务(`.service` 文件),支持启动、停止、重启、查看状态、设置开机启动等操作。\r\n\r\n##### 1. 服务状态操作\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 启动服务 | `systemctl start <服务名>` | 启动指定服务(仅临时生效,重启后不保留) |\r\n| 停止服务 | `systemctl stop <服务名>` | 停止指定服务 |\r\n| 重启服务 | `systemctl restart <服务名>` | 重启服务(若服务未运行则启动) |\r\n| 重新加载配置 | `systemctl reload <服务名>` | 重新加载服务配置文件(不重启服务,适用于支持此功能的服务,如 Nginx) |\r\n| 平滑重启(优雅重启)| `systemctl try-restart <服务名>` | 仅在服务运行时重启,避免报错 |\r\n\r\n##### 2. 服务状态查询\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 查看状态 | `systemctl status <服务名>` | 显示服务运行状态、日志及依赖关系(按 `Q` 退出) |\r\n| 简洁状态 | `systemctl is-active <服务名>` | 仅显示服务是否激活(active/running) |\r\n| 查看是否启用开机启动| `systemctl is-enabled <服务名>` | 显示服务是否设置为开机启动(enabled/disabled) |\r\n| 列出所有服务 | `systemctl list-units --type=service` | 列出所有运行中的服务 |\r\n| 列出所有服务(含未激活)| `systemctl list-units --type=service --all` | 显示所有服务,包括未激活的(状态为 inactive/failed 等) |\r\n| 列出失败的服务 | `systemctl --failed --type=service` | 查看启动失败的服务 |\r\n\r\n##### 3. 开机启动管理\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 启用开机启动 | `systemctl enable <服务名>` | 设置服务开机自动启动(永久生效,关联到默认运行目标) |\r\n| 禁用开机启动 | `systemctl disable <服务名>` | 取消服务开机启动 |\r\n| 临时启用(仅本次启动)| `systemctl enable --now <服务名>` | 立即启动服务并设置开机启动 |\r\n| 临时禁用(停止并取消启动)| `systemctl disable --now <服务名>` | 立即停止服务并取消开机启动 |\r\n\r\n##### 4. 服务依赖与依赖关系\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 查看依赖关系 | `systemctl list-dependencies <服务名>` | 显示服务的依赖项(依赖它的服务 + 它依赖的服务) |\r\n| 查看直接依赖 | `systemctl list-dependencies --reverse <服务名>` | 仅显示依赖该服务的其他服务 |\r\n\r\n\r\n#### **二、系统状态与控制**\r\n##### 1. 系统基本状态\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 查看系统运行时间 | `systemctl uptime` | 显示系统已运行时间(类似 `uptime` 命令) |\r\n| 查看启动耗时 | `systemctl time` | 显示系统启动总耗时及各阶段(内核、用户空间、服务)耗时 |\r\n| 查看登录会话 | `systemctl list-sessions` | 列出当前登录的用户会话 |\r\n\r\n##### 2. 电源管理(需管理员权限)\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 关机 | `systemctl poweroff` | 立即关机 |\r\n| 重启 | `systemctl reboot` | 立即重启 |\r\n| 休眠(挂起到硬盘) | `systemctl hibernate` | 系统进入休眠状态 |\r\n| 睡眠(挂起到内存) | `systemctl suspend` | 系统进入睡眠状态(低功耗,断电数据丢失) |\r\n| 混合休眠 | `systemctl hybrid-sleep` | 同时休眠到内存和硬盘,结合两者优势 |\r\n| 取消挂起/休眠 | `systemctl wakeup` | 唤醒系统(需配合定时器使用) |\r\n\r\n##### 3. 运行目标(替代传统运行级别)\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 查看当前目标 | `systemctl get-default` | 显示默认运行目标(如 `graphical.target` 对应图形界面) |\r\n| 切换目标 | `systemctl isolate <目标名>` | 切换到指定目标(如 `multi-user.target` 为无图形多用户模式) |\r\n| 设置默认目标 | `systemctl set-default <目标名>` | 设置开机默认目标(需管理员权限) |\r\n\r\n**常用目标对应关系**: \r\n- `graphical.target`:图形界面(对应传统运行级别 5) \r\n- `multi-user.target`:无图形多用户模式(对应级别 3) \r\n- `rescue.target`:单用户救援模式(对应级别 1) \r\n- `emergency.target`:紧急模式(无文件系统挂载,仅基本命令) \r\n\r\n\r\n#### **三、定时器管理(systemd.timer)**\r\n`systemctl` 可管理定时任务(替代传统 `cron`),需配合 `.timer` 文件使用。\r\n\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 列出所有定时器 | `systemctl list-timers` | 显示激活的定时器及其下一次触发时间 |\r\n| 查看定时器状态 | `systemctl status <定时器名>` | 显示定时器详细状态及日志 |\r\n| 启用/禁用定时器 | `systemctl enable/disable <定时器名>` | 控制定时器是否开机启动 |\r\n| 立即触发定时器任务 | `systemctl start <定时器名>` | 强制立即执行定时器关联的服务 |\r\n\r\n\r\n#### **四、资源控制与限制(高级功能)**\r\n可对服务设置 CPU、内存、IO 等资源限制(需在服务文件中配置,或临时生效)。\r\n\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 设置 CPU 核心限制 | `systemctl set-property <服务名> CPUAffinity=0,1` | 限制服务仅运行在 CPU 0 和 1 核心 |\r\n| 设置内存上限 | `systemctl set-property <服务名> MemoryMax=1G` | 限制服务最大内存使用量为 1GB |\r\n| 恢复默认资源配置 | `systemctl unset-property <服务名> CPUAffinity MemoryMax` | 清除已设置的资源限制 |\r\n\r\n\r\n#### **五、日志相关(结合 journalctl)**\r\n| 操作 | 命令 | 说明 |\r\n|---------------------|---------------------------------------|----------------------------------------------------------------------|\r\n| 查看服务日志 | `systemctl status <服务名> -l` | 显示服务状态并附带日志(`-l` 展开完整日志) |\r\n| 实时监控日志 | `journalctl -u <服务名> -f` | 实时追踪服务日志(需结合 `journalctl` 命令) |\r\n| 查看历史日志 | `journalctl -u <服务名> --since \"2025-05-01\"` | 查看指定时间后的服务日志 |\r\n\r\n\r\n#### **六、常用选项与技巧**\r\n- **通配符匹配**: \r\n 可使用通配符管理同类服务,例如: \r\n ```bash\r\n systemctl start nginx*.service # 启动所有以 nginx 开头的服务\r\n systemctl stop *.timer # 停止所有定时器服务\r\n ```\r\n\r\n- **强制操作**: \r\n `--force` 用于强制停止/重启服务(可能终止进程): \r\n ```bash\r\n systemctl --force stop <服务名>\r\n ```\r\n\r\n- **临时生效(不修改配置)**: \r\n 使用 `--now` 可立即执行操作并关联开机启动(或取消): \r\n ```bash\r\n systemctl enable --now <服务名> # 启动并启用开机启动\r\n systemctl disable --now <服务名> # 停止并禁用开机启动\r\n ```\r\n\r\n- **查看帮助**: \r\n ```bash\r\n systemctl --help # 查看全局帮助\r\n systemctl help <子命令> # 查看子命令详细用法(如 systemctl help start)\r\n ```\r\n\r\n\r\n#### **七、示例场景**\r\n1. **管理 Nginx 服务**: \r\n ```bash\r\n systemctl start nginx # 启动 Nginx\r\n systemctl enable nginx # 设置开机启动\r\n systemctl status nginx # 查看运行状态\r\n systemctl reload nginx # 重新加载配置\r\n ```\r\n\r\n2. **系统关机与重启**: \r\n ```bash\r\n systemctl reboot # 立即重启\r\n systemctl poweroff # 立即关机\r\n systemctl suspend # 进入睡眠\r\n ```\r\n\r\n3. **设置默认运行目标**: \r\n ```bash\r\n systemctl set-default multi-user.target # 设为无图形多用户模式\r\n systemctl isolate rescue.target # 进入单用户救援模式\r\n ```\r\n\r\n\r\n### 总结\r\n`systemctl` 是 systemd 生态的核心工具,覆盖服务管理、系统控制、定时任务、资源限制等功能。熟练掌握其常用命令可高效管理 Linux 系统服务与状态,替代传统 SysVinit 的 `service`、`chkconfig` 等工具。建议结合 `journalctl` 分析服务日志,通过服务文件(`/etc/systemd/system/`)自定义复杂配置。`systemctl` 是 Linux 系统中用于控制 `systemd` 系统和服务管理器的命令。以下是 `systemctl` 命令的一些常用用法总结:\r\n\r\n### 1. 服务管理\r\n#### 启动服务\r\n```bash\r\nsystemctl start <服务名>\r\n```\r\n例如,启动 `httpd` 服务:\r\n```bash\r\nsystemctl start httpd\r\n```\r\n\r\n#### 停止服务\r\n```bash\r\nsystemctl stop <服务名>\r\n```\r\n例如,停止 `httpd` 服务:\r\n```bash\r\nsystemctl stop httpd\r\n```\r\n\r\n#### 重启服务\r\n```bash\r\nsystemctl restart <服务名>\r\n```\r\n例如,重启 `httpd` 服务:\r\n```bash\r\nsystemctl restart httpd\r\n```\r\n\r\n#### 重新加载服务配置\r\n```bash\r\nsystemctl reload <服务名>\r\n```\r\n例如,重新加载 `nginx` 服务配置:\r\n```bash\r\nsystemctl reload nginx\r\n```\r\n\r\n#### 查看服务状态\r\n```bash\r\nsystemctl status <服务名>\r\n```\r\n例如,查看 `httpd` 服务状态:\r\n```bash\r\nsystemctl status httpd\r\n```\r\n\r\n### 2. 服务的开机自启管理\r\n#### 设置服务开机自启\r\n```bash\r\nsystemctl enable <服务名>\r\n```\r\n例如,设置 `httpd` 服务开机自启:\r\n```bash\r\nsystemctl enable httpd\r\n```\r\n\r\n#### 禁止服务开机自启\r\n```bash\r\nsystemctl disable <服务名>\r\n```\r\n例如,禁止 `httpd` 服务开机自启:\r\n```bash\r\nsystemctl disable httpd\r\n```\r\n\r\n#### 查看服务是否开机自启\r\n```bash\r\nsystemctl is-enabled <服务名>\r\n```\r\n例如,查看 `httpd` 服务是否开机自启:\r\n```bash\r\nsystemctl is-enabled httpd\r\n```\r\n\r\n### 3. 系统管理\r\n#### 重启系统\r\n```bash\r\nsystemctl reboot\r\n```\r\n\r\n#### 关机\r\n```bash\r\nsystemctl poweroff\r\n```\r\n\r\n#### 挂起系统\r\n```bash\r\nsystemctl suspend\r\n```\r\n\r\n#### 休眠系统\r\n```bash\r\nsystemctl hibernate\r\n```\r\n\r\n#### 混合休眠(挂起并休眠)\r\n```bash\r\nsystemctl hybrid-sleep\r\n```\r\n\r\n### 4. 查看系统状态\r\n#### 查看系统当前运行级别\r\n```bash\r\nsystemctl get-default\r\n```\r\n\r\n#### 设置系统默认运行级别\r\n```bash\r\nsystemctl set-default <目标运行级别>\r\n```\r\n例如,设置系统默认运行级别为多用户模式:\r\n```bash\r\nsystemctl set-default multi-user.target\r\n```\r\n\r\n### 5. 查看服务列表\r\n#### 查看所有已激活的服务\r\n```bash\r\nsystemctl list-units --type=service --state=active\r\n```\r\n\r\n#### 查看所有服务(包括未激活的)\r\n```bash\r\nsystemctl list-units --type=service --all\r\n```\r\n\r\n这些是 `systemctl` 命令的一些常用用法,掌握这些用法可以帮助你有效地管理 Linux 系统中的服务和系统状态。 ", + "Linux/Termux/shell2http举例.md": "`shell2http` 的灵活性和轻量级特性让它能玩出许多有趣的花样!以下是一些创意使用案例,涵盖实用场景和趣味玩法:\n\n---\n\n### **一、智能家居 & 自动化**\n1. **远程控制智能插座** \n ```bash\n shell2http -basic-auth=\"admin:密码\" POST:/灯控 'curl -X POST http://智能插座IP/开关 -d \"state=on\"'\n ```\n - 用途:用手机浏览器一键开关灯,配合 Siri 快捷指令还能语音控制。\n\n2. **树莓派摄像头拍照** \n ```bash\n shell2http /拍照 'raspistill -o /tmp/snapshot.jpg && base64 /tmp/snapshot.jpg'\n ```\n - 用途:远程拍照并返回 Base64 图片,可嵌入网页实时查看。\n\n3. **温湿度监控** \n ```bash\n shell2http /温湿度 'python3 读取传感器脚本.py'\n ```\n - 用途:连接 DHT11/DHT22 传感器,通过 HTTP 返回 JSON 格式温湿度数据。\n\n---\n\n### **二、实用工具**\n4. **临时文件共享** \n ```bash\n shell2http -form /upload 'mv $filepath_file1 ./共享文件夹/$filename_file1 && echo 上传成功'\n ```\n - 用途:在局域网内快速共享文件,上传后生成直链供他人下载。\n\n5. **二维码生成器** \n ```bash\n shell2http /qrcode \"qrencode -t ANSIUTF8 '$v_text'\"\n ```\n - 用法:访问 `http://IP:8080/qrcode?text=HelloWorld`,终端直接显示二维码。\n\n6. **DDNS 动态域名更新** \n ```bash\n shell2http /update_ddns 'curl \"https://ddns服务商API?ip=$(curl ifconfig.me)\"'\n ```\n - 用途:外网触发更新 DDNS 记录,解决家庭宽带 IP 变化问题。\n\n---\n\n### **三、趣味玩法**\n7. **语音播报远程控制** \n ```bash\n shell2http POST:/说话 'echo \"$v_text\" | espeak -v zh' # Linux 文本转语音\n ```\n - 用途:用手机输入文字,让电脑念出来(比如捉弄同事)。\n\n8. **在线抽奖/随机选择** \n ```bash\n shell2http /抽奖 'shuf -n1 名单.txt'\n ```\n - 用途:年会时打开网页点击按钮,大屏幕显示中奖者。\n\n9. **生成梗图** \n ```bash\n shell2http -form /生成表情包 'convert 模板.jpg -pointsize 30 -fill white -annotate +100+200 \"$v_text\" -' \n ```\n - 用途:上传文字生成表情包,可集成到微信群机器人。\n\n---\n\n### **四、开发调试**\n10. **模拟慢速 API** \n ```bash\n shell2http /slow 'sleep ${v_time:-5} && echo 响应完成'\n ```\n - 用途:测试前端 Loading 效果,访问 `/slow?time=10` 模拟 10 秒延迟。\n\n11. **Mock 测试接口** \n ```bash\n shell2http /api/user 'echo \"{\\\"name\\\":\\\"张三\\\",\\\"age\\\":$(shuf -i 20-60 -n1)}\"'\n ```\n - 用途:快速生成随机 JSON 数据,替代未完成的真实接口。\n\n12. **代理请求记录器** \n ```bash\n shell2http -cgi /proxy 'echo \"URL: $REQUEST_URI\" >> log.txt; curl -s \"$v_url\"'\n ```\n - 用途:记录所有经过的请求参数,调试第三方回调。\n\n---\n\n### **五、系统管理**\n13. **服务器监控面板** \n ```bash\n shell2http /cpu \"top -bn1 | grep 'Cpu(s)'\" /内存 \"free -h\" /磁盘 \"df -h\"\n ```\n - 用途:手机浏览器快速查看服务器状态。\n\n14. **远程重启服务** \n ```bash\n shell2http -500 POST:/reboot_nginx 'systemctl restart nginx && echo 成功'\n ```\n - 用途:内网安全重启服务(务必设置 Basic 认证!)。\n\n15. **日志实时查看** \n ```bash\n shell2http /tail_log 'tail -n20 /var/log/syslog'\n ```\n - 用途:快速检查日志,无需 SSH 登录。\n\n---\n\n### **注意事项**\n- **安全第一**:暴露在公网时务必启用 `-basic-auth` 和 HTTPS。\n- **权限控制**:敏感操作(如重启服务)建议结合 IP 白名单。\n- **临时用途**:适合原型设计或内部工具,不建议替代专业 API 网关。\n\n这些案例只需简单修改即可运行,试试用 `shell2http` 把你身边的硬件和脚本变成「物联网设备」吧!", + "Linux/Termux/shell2HTTP软件简单总结.md": "以下是 `shell2http` 项目的详细中文总结:\n\n---\n\n### **项目概述**\n`shell2http` 是一个用 Go 编写的轻量级 HTTP 服务器,核心功能是通过 HTTP 请求触发执行预定义的 Shell 命令,并将结果返回给客户端。它适用于开发调试、原型设计、远程控制等场景,支持快速将 Shell 脚本暴露为 HTTP 接口。\n\n---\n\n### **核心功能**\n1. **简单易用** \n - 通过命令行参数直接绑定 URL 路径与 Shell 命令,例如: \n ```shell\n shell2http /date \"date\" /ps \"ps aux\"\n ```\n - 支持 GET、POST 等多种 HTTP 方法(通过 `METHOD:/path` 语法指定)。\n\n2. **请求处理模式** \n - **普通模式**:直接执行命令,返回标准输出(stdout)。\n - **表单模式(`-form`)**:解析查询参数和上传文件,生成环境变量供脚本使用:\n - `$v_参数名`:来自 URL 查询参数的值(如 `?id=123` → `$v_id`)。\n - `$filepath_字段名`:上传文件的临时路径。\n - `$filename_字段名`:上传文件的原始文件名。\n - **CGI 模式(`-cgi`)**:模拟 CGI 环境,设置 HTTP 请求相关环境变量,处理请求体数据。\n\n3. **安全与认证** \n - **Basic 认证**:通过 `-basic-auth` 设置用户名密码,支持多用户。\n - **SSL/TLS**:使用 `-cert` 和 `-key` 选项启动 HTTPS 服务器。\n - **表单字段过滤**:通过 `-form-check` 限制参数名格式(如仅允许数字)。\n\n4. **高级特性** \n - **缓存**:`-cache=N` 缓存命令输出 N 秒。\n - **超时控制**:`-timeout` 设置命令执行超时时间。\n - **错误处理**:`-500` 在命令非零退出时返回 500 错误;`-show-errors` 显示错误输出。\n - **环境变量**:支持导出特定或全部环境变量(`-export-vars`/`-export-all-vars`)。\n\n5. **日志与调试** \n - 自定义日志文件(`-log`)、禁用时间戳(`-no-log-timestamp`)。\n\n---\n\n### **安装方式**\n1. **MacOS** \n ```shell\n brew install msoap/tools/shell2http\n ```\n2. **Docker** \n ```shell\n docker pull msoap/shell2http\n docker run -p 8080:8080 msoap/shell2http /date \"date\"\n ```\n - 使用 `--init` 防止僵尸进程。\n\n3. **Snap(Linux)** \n ```shell\n sudo snap install shell2http\n ```\n - 注意沙箱环境可能导致路径问题。\n\n4. **源码编译** \n ```shell\n go install github.com/msoap/shell2http@latest\n ```\n\n5. **预编译二进制** \n 从 [GitHub Releases](https://github.com/msoap/shell2http/releases) 下载(支持 Windows、Linux、MacOS、树莓派)。\n\n---\n\n### **使用示例**\n1. **基础命令** \n ```shell\n shell2http /top \"top -l 1 | head -10\" /date \"date\"\n ```\n - 访问 `http://localhost:8080/date` 返回当前时间。\n\n2. **环境变量** \n ```shell\n shell2http -export-vars=GOPATH /gopath 'echo $GOPATH'\n ```\n\n3. **表单处理** \n ```shell\n shell2http -form /upload 'cp $filepath_file1 ./uploads/$filename_file1'\n ```\n - 上传文件并保存到 `uploads` 目录。\n\n4. **CGI 模式** \n ```shell\n shell2http -cgi /cgi-script './script.sh'\n ```\n - 脚本可读取请求头、请求体,设置响应头。\n\n5. **HTTPS 服务器** \n ```shell\n shell2http -cert=cert.pem -key=key.pem /date \"date\"\n ```\n - 生成自签名证书: \n ```shell\n go run $(go env GOROOT)/src/crypto/tls/generate_cert.go -host localhost\n ```\n\n---\n\n### **应用场景**\n- **系统监控**:暴露 `top`、`ps`、`df` 等命令的 HTTP 接口。\n- **文件操作**:上传/下载文件、目录列表。\n- **远程控制**:调节音量、控制媒体播放器(如 MacOS 的 Vox.app)。\n- **API 模拟**:返回静态 JSON 或动态生成数据。\n- **调试工具**:模拟慢速响应、记录请求日志。\n\n---\n\n### **相关工具**\n- **shell2telegram**:将 Shell 命令绑定到 Telegram 机器人。\n- **websocketd**:将 STDIN/STDOUT 程序转换为 WebSocket 服务。\n- **devd**:本地开发的轻量级 HTTP 守护进程。\n\n---\n\n### **注意事项**\n- **安全性**:避免在生产环境暴露敏感命令,使用防火墙和认证机制。\n- **性能**:默认多线程处理请求,可通过 `-one-thread` 限制为单线程。\n- **路径问题**:Docker 或 Snap 环境需注意命令的可访问性。\n\n通过灵活配置,`shell2http` 可快速搭建功能丰富的 HTTP 服务,适合开发者和运维人员简化工作流程。", + "Linux/Termux/Termux-api用法总结/弹窗.md": "`termux-toast` 命令用于在 Android 设备上显示一个短暂的消息(Toast)。这个消息会在屏幕上弹出,并在几秒钟后自动消失。它的基本用法如下:\n\n### 基本用法\n\n```bash\ntermux-toast [选项] <消息文本>\n```\n\n### 常用选项\n\n- `-s` 或 `--short`:使用短时间显示消息(默认选项)。\n- `-l` 或 `--long`:使用较长时间显示消息。\n- `-g` 或 `--gravity`:设置消息显示的位置。可选值为 `top`、`middle` 和 `bottom`(默认是 `bottom`)。\n- `-b` 或 `--background`:设置背景颜色,使用十六进制颜色代码。\n- `-c` 或 `--color`:设置文本颜色,使用十六进制颜色代码.\n\n### 示例\n\n1. **显示一个默认的短消息**:\n\n ```bash\n termux-toast \"Hello, World!\"\n ```\n\n3. **在屏幕顶部显示消息**:\n\n ```bash\n termux-toast -g top \"This message is at the top.\"\n ```\n\n4. **设置背景和文本颜色**:\n\n ```bash\n termux-toast -b \"#FF0000\" -c \"#FFFFFF\" \"Red background with white text.\"\n ```\n\n这些命令可以在脚本中使用,以便在某些事件发生时通知用户。请注意,由于 Toast 本质上是短暂的通知类型,它们不适合显示需要用户交互或长时间关注的重要信息。", + "Linux/Termux/Termux-api用法总结/录音.md": "当然!以下是一些使用 `termux-microphone-record` 命令的示例,展示了如何利用不同的参数来满足不同的录音需求:\n\n1. **使用默认设置开始录音**:\n ```bash\n termux-microphone-record -d\n ```\n 这将使用默认设置开始录音,并保存到默认文件。\n\n2. **录制到指定文件**:\n ```bash\n termux-microphone-record -f /sdcard/my_recording.wav\n ```\n 这会将录音保存到 `/sdcard/my_recording.wav` 文件中。\n\n3. **限制录音时间为 30 秒**:\n ```bash\n termux-microphone-record -f /sdcard/my_recording.wav -l 30\n ```\n 这将录制 30 秒的音频,并保存到指定文件。\n\n4. **使用特定编码器(例如 AAC)录音**:\n ```bash\n termux-microphone-record -f /sdcard/my_recording.aac -e aac\n ```\n 这会使用 AAC 编码器进行录音。\n\n5. **指定比特率为 128 kbps**:\n ```bash\n termux-microphone-record -f /sdcard/my_recording.wav -b 128\n ```\n 这将以 128 kbps 的比特率进行录音。\n\n6. **使用特定采样率(例如 44100 Hz)录音**:\n ```bash\n termux-microphone-record -f /sdcard/my_recording.wav -r 44100\n ```\n 这会以 44100 Hz 的采样率录音。\n\n7. **使用双声道录音**:\n ```bash\n termux-microphone-record -f /sdcard/my_recording.wav -c 2\n ```\n 这会以双声道(立体声)进行录音。\n\n8. **获取当前录音的信息**:\n ```bash\n termux-microphone-record -i\n ```\n 这将显示有关当前录音的详细信息。\n\n9. **停止当前录音**:\n ```bash\n termux-microphone-record -q\n ```\n 这会停止当前正在进行的录音。\n\n这些示例展示了如何使用 `termux-microphone-record` 的不同参数来调整录音的输出。你可以根据需要组合这些参数来实现更复杂的录音配置。", + "Linux/Termux/Termux-api用法总结/所有支持的api.md": "Termux API 是一个提供设备功能访问的工具,允许在 Termux 环境中通过命令行接口访问 Android 设备的各种硬件和系统功能。以下是这些 Termux API 的简单介绍:\n\n1. **termux-api-start/stop**:启动或停止 Termux API 服务。\n2. **termux-audio-info**:获取设备的音频信息。\n3. **termux-battery-status**:获取设备的电池状态信息。\n4. **termux-brightness**:设置或获取屏幕亮度。\n5. **termux-call-log**:访问设备的通话记录。\n6. **termux-camera-info**:获取设备相机信息。\n7. **termux-camera-photo**:使用设备相机拍照。\n8. **termux-clipboard-get/set**:获取或设置设备的剪贴板内容。\n9. **termux-contact-list**:获取设备的联系人列表。\n10. **termux-dialog**:显示对话框。\n11. **termux-download**:下载文件。\n12. **termux-fingerprint**:使用指纹传感器进行身份验证。\n13. **termux-infrared-frequencies/transmit**:获取红外频率信息或发送红外信号。\n14. **termux-job-scheduler**:安排一个任务在特定时间运行。\n15. **termux-keystore**:访问或管理密钥存储。\n16. **termux-location**:获取设备的地理位置信息。\n17. **termux-media-player**:播放媒体文件。\n18. **termux-media-scan**:扫描媒体文件。\n19. **termux-microphone-record**:录制音频。\n20. **termux-nfc**:访问 NFC 功能。\n21. **termux-notification/channel/list/remove**:管理通知,包括创建、列出和移除通知。\n22. **termux-saf-create/dirs/ls/managedir/mkdir/read/rm/stat/write**:通过 Storage Access Framework (SAF) 访问和管理文件系统。\n23. **termux-sensor**:访问设备的传感器数据。\n24. **termux-share**:共享文件或文本。\n25. **termux-sms-inbox/list/send**:访问和管理短信,包括查看收件箱和发送短信。\n26. **termux-speech-to-text**:将语音转换为文本。\n27. **termux-storage-get**:从设备存储中获取文件。\n28. **termux-telephony-call/cellinfo/deviceinfo**:拨打电话或获取设备的电话信息。\n29. **termux-toast**:显示一个短暂的消息。\n30. **termux-torch**:控制设备的手电筒。\n31. **termux-tts-engines/speak**:获取 TTS 引擎信息或合成语音。\n32. **termux-usb**:访问 USB 设备。\n33. **termux-vibrate**:控制设备的振动。\n34. **termux-volume**:获取或设置音量。\n35. **termux-wallpaper**:设置设备的壁纸。\n36. **termux-wifi-connectioninfo/enable/scaninfo**:管理 Wi-Fi 连接,获取连接信息或扫描 Wi-Fi 网络。\n\n这些 API 提供了丰富的功能,可以让用户通过脚本自动化许多任务或访问设备的硬件功能。", + "Linux/Termux/Termux-api用法总结/闪光灯.md": "`termux-torch` 命令用于控制 Android 设备的手电筒(通常是相机闪光灯)。可以通过此命令打开或关闭手电筒。它的基本用法如下:\n\n### 基本用法\n\n```bash\ntermux-torch <状态>\n```\n\n### 参数\n\n- `<状态>`:指定手电筒的状态,可以是 `on` 或 `off`。\n - `on`:打开手电筒。\n - `off`:关闭手电筒。\n\n### 示例\n\n1. **打开手电筒**:\n\n ```bash\n termux-torch on\n ```\n\n2. **关闭手电筒**:\n\n ```bash\n termux-torch off\n ```\n\n这些命令可以在脚本中使用,以便在特定情况下自动打开或关闭手电筒,比如在黑暗环境中需要光源时。使用这些命令时,请确保授予 Termux 应用程序相应的权限,以便访问设备的相机闪光灯功能。", + "Linux/Termux/termux的pkg命令总结.md": "pkg  是用于管理 apt 软件包的工具,用法为  pkg [--check-mirror] command [arguments] , --check-mirror  强制重新检查镜像可用性。其命令包括:\n \n autoclean :从 apt 缓存中删除所有过时软件包。\n \n clean :从 apt 缓存中删除所有软件包。\n \n files  :显示指定软件包安装的所有文件。\n \n install  :安装指定软件包。\n \n list-all :列出仓库中所有可用软件包。\n \n list-installed :列出已安装的软件包。\n \n reinstall  :以最新版本重新安装指定已安装软件包。\n \n search  :按名称或描述等查询搜索软件包。\n \n show  :显示软件包基本元数据,如依赖项。\n \n uninstall  :卸载指定软件包,保留配置文件。\n \n upgrade :将所有已安装软件包升级到最新版本。\n \n update :从配置的仓库更新 apt 数据库。", + "Linux/Termux-SSH相关.md": "Termux更改终端密码:\r\n\r\n```\r\npasswd\r\n```\r\n\r\n重启SSH服务\r\n\r\n```\r\npkill sshd \r\nsshd\r\n```\r\n\r\n查看本机IP\r\n\r\n```\r\nifconfig\r\n```\r\n\r\n生成SSH主机密钥\r\n\r\n```\r\nssh-keygen -A\r\n```\r\n\r\n更新Termux包\r\n\r\n```\r\npkg update && pkg upgrade\r\n```\r\n\r\nTermux退出chroot容器\r\n\r\n```\r\nexit\r\n```\r\n\r\nTermux安装软件\r\n\r\n```\r\npkg install \r\n```\r\n\r\n查看终端用户名\r\n\r\n```\r\nwhoami\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n妈的旧手机termux终端用户名\r\n\r\nu0_a143\r\n\r\n爸的旧手机termux终端用户名\r\n\r\nu0_a135\r\n\r\nTermux执行sh脚本\r\n\r\n```\r\nbash 脚本名.sh\r\n```\r\n\r\n\r\n\r\n", + "Linux/ubuntu设置root登陆.md": "在 Ubuntu GNOME 22.04 中,默认情况下是禁用 root 用户的登录,以提高系统安全性。如果你需要启用 root 用户并允许其通过图形界面登录,可以按照以下步骤操作:\n\n### 1. 启用 Root 用户\n\nUbuntu 默认情况下禁用了 root 用户账户,因此我们需要为 root 设置密码才能启用它。\n\n1. 打开终端,使用以下命令设置 root 用户密码:\n\n ```bash\n sudo passwd root\n ```\n\n 然后根据提示输入并确认 root 用户密码。\n\n### 2. 允许 Root 用户登录图形界面\n\nUbuntu 默认不允许 root 用户直接登录 GNOME 图形界面。如果你希望启用 root 登录图形界面,需要修改 GDM(GNOME Display Manager)的配置文件。\n\n1. 编辑 GDM 配置文件:\n\n ```bash\n sudo nano /etc/gdm3/custom.conf\n ```\n\n2. 找到 `[security]` 部分,并确保以下行没有被注释掉(没有 `#`):\n\n ```plaintext\n AllowRoot=true\n ```\n\n3. 保存并退出(按 `Ctrl + O` 保存,`Ctrl + X` 退出)。\n\n### 3. 重启 GDM\n\n配置更改后,重启 GDM 或重新启动计算机以使更改生效。你可以使用以下命令重启 GDM:\n\n```bash\nsudo systemctl restart gdm3\n```\n\n### 4. 使用 root 登录\n\n现在,你应该能够在登录屏幕选择 root 用户进行登录了。只需要输入你为 root 设置的密码即可。\n\n### 5. 注意安全\n\n启用 root 用户图形界面登录可能会增加系统的安全风险,因为 root 用户具有系统的完全控制权限。为了保护系统的安全性,建议仅在必要时启用 root 登录,并使用强密码以及定期检查系统的安全性。\n\n如果你不需要 root 图形界面登录,建议使用 `sudo` 命令来执行管理员操作,这样可以减少潜在的安全风险。\n\n", + "Linux/Windows文件一键上传到Linux.md": "\n**萌芽农场**\n```powershell\nscp -r D:\\Godot\\Godot项目\\比较完成的作品\\萌芽农场\\Server\\* root@192.168.31.233:/shumengya/docker/mengyafarmserver/\n\nscp -r D:\\Godot\\Godot项目\\比较完成的作品\\萌芽农场\\Server\\* root@192.168.1.233:/shumengya/docker/mengyafarmserver/\n```\n\n一个人的服务器(我的世界基岩版1.1.xPocketMine服务器)\n```powershell\nscp -r C:\\Users\\BigTang\\Desktop\\一个人的服务器\\* root@192.168.31.233:/shumengya/docker/OnePersonServer/\n```", + "Linux/wlan0简单介绍.md": "### 1. 网络接口类型及其作用\n- **lo(回环接口)**:\n - 用于系统内部通信,IP地址通常为 `127.0.0.1`,子网掩码为 `255.0.0.0`。\n - 主要用于本地测试,如运行本地服务器(如HTTPD)时,只能在本机访问。\n\n- **eth0(以太网接口)**:\n - 代表第一块物理网卡,`HWaddr` 表示网卡的MAC地址,`inet addr` 表示IP地址。\n - 支持IPv4和IPv6,通常用于有线网络连接。\n - 可以通过 `ifconfig` 查看网卡的接收和发送数据包的情况。\n\n- **br0(网桥接口)**:\n - 用于在链路层连接多个网络接口(如eth0),实现帧的转发。\n - 常用于虚拟化环境中,连接多个虚拟网络接口。\n\n- **wlan0(无线接口)**:\n - 代表无线网卡,类似于eth0,但用于无线网络连接。\n - 需要驱动程序支持,配置方式与以太网接口类似。\n\n### 2. `ifconfig` 命令的常见操作\nWindows命令为:ipconfig\n\n- **启动/关闭网卡**:\n - `ifconfig eth0 up`:启动网卡。\n - `ifconfig eth0 down`:关闭网卡。\n\n- **配置/删除IPv6地址**:\n - `ifconfig eth0 add `:为网卡添加IPv6地址。\n - `ifconfig eth0 del `:删除网卡的IPv6地址。\n\n- **修改MAC地址**:\n - `ifconfig eth0 hw ether `:修改网卡的MAC地址。\n\n- **修改IP地址**:\n - `ifconfig eth0 `:修改网卡的IP地址。\n - `ifconfig eth0 netmask <子网掩码>`:修改IP地址并设置子网掩码。\n - `ifconfig eth0 netmask <子网掩码> broadcast <广播地址>`:同时设置IP地址、子网掩码和广播地址。\n\n- **设置最大传输单元(MTU)**:\n - `ifconfig eth0 mtu <字节数>`:设置网卡的最大传输单元大小。\n\n### 3. 注意事项\n- 使用 `ifconfig` 命令时,尤其是在远程服务器上操作时,需谨慎关闭网卡,否则可能导致无法远程连接。\n- 虚拟网卡和物理网卡的区别在于虚拟网卡由系统或应用程序创建,不依赖于物理硬件。\n\n这篇文章详细介绍了 `ifconfig` 命令的使用方法以及常见网络接口的配置和功能,适合需要管理和调试网络接口的用户参考。", + "Linux/我想全局执行某个sh脚本,该放在Linux哪个目录.md": "要使得某个 `.sh` 脚本能够在系统中全局执行,你可以将该脚本放在 **系统的 `PATH` 路径中**,使其在任何地方都能被执行。常见的目录有:\r\n\r\n### 1. **`/usr/local/bin/`**\r\n这是推荐的目录,因为它是用来放置系统管理员手动安装或编译的软件及脚本的。脚本放在这个目录中,可以确保它对所有用户可用,并且不会与系统自带的命令冲突。\r\n\r\n步骤:\r\n1. 将你的 `.sh` 脚本复制到 `/usr/local/bin/` 目录下。\r\n \r\n ```bash\r\n sudo cp your_script.sh /usr/local/bin/\r\n ```\r\n\r\n2. 赋予脚本执行权限:\r\n\r\n ```bash\r\n sudo chmod +x /usr/local/bin/your_script.sh\r\n ```\r\n\r\n3. 确保脚本能被执行,可以通过命令行直接调用(例如 `your_script.sh`),无需指定路径。\r\n\r\n### 2. **`/usr/bin/`**\r\n这个目录通常用于系统范围内的二进制文件,和 `/usr/local/bin/` 类似。但是,建议将自定义脚本放在 `/usr/local/bin/` 目录下,因为 `/usr/bin/` 通常用于通过包管理器安装的系统级命令。\r\n\r\n步骤:\r\n1. 将脚本复制到 `/usr/bin/` 目录:\r\n\r\n ```bash\r\n sudo cp your_script.sh /usr/bin/\r\n ```\r\n\r\n2. 赋予执行权限:\r\n\r\n ```bash\r\n sudo chmod +x /usr/bin/your_script.sh\r\n ```\r\n\r\n### 3. **`/bin/`**(不推荐)\r\n`/bin/` 目录通常用于存放系统核心命令和工具,普通用户通常不建议将自定义脚本放在这个目录中,除非它们确实是系统必需的命令。通常会将脚本放置在 `/usr/local/bin/` 或 `/usr/bin/` 中。\r\n\r\n### 4. **用户特定的目录(例如 `/home/username/bin/`)**\r\n如果你只想为某个特定用户设置全局脚本,而不是所有用户可以访问的脚本,你可以将脚本放在该用户的 `~/bin/` 目录下(如果该目录不存在,可以自己创建)。确保将 `~/bin/` 添加到用户的 `PATH` 环境变量中。\r\n\r\n步骤:\r\n1. 创建 `~/bin/` 目录(如果没有的话):\r\n\r\n ```bash\r\n mkdir -p ~/bin\r\n ```\r\n\r\n2. 将脚本复制到 `~/bin/` 目录:\r\n\r\n ```bash\r\n cp your_script.sh ~/bin/\r\n ```\r\n\r\n3. 赋予执行权限:\r\n\r\n ```bash\r\n chmod +x ~/bin/your_script.sh\r\n ```\r\n\r\n4. 编辑 `~/.bashrc` 或 `~/.profile`,将 `~/bin/` 添加到 `PATH`:\r\n\r\n ```bash\r\n export PATH=$PATH:~/bin\r\n ```\r\n\r\n5. 使 `~/.bashrc` 变更生效:\r\n\r\n ```bash\r\n source ~/.bashrc\r\n ```\r\n\r\n### 总结\r\n- **最推荐的目录:** `/usr/local/bin/`,适用于系统范围内的自定义脚本。\r\n- **其他可选目录:** `/usr/bin/`(不推荐),如果需要放系统级命令可以选择该目录。\r\n- **特定用户的脚本:** 用户自己的 `~/bin/` 目录。\r\n\r\n将脚本放入上述目录,并设置执行权限后,你就可以在系统中的任何地方执行该脚本了。如果有任何问题,请随时告知!", + "Linux/手动配置alist.md": "```shell\r\n# 解压下载的文件,得到可执行文件:\r\ntar -zxvf alist-xxxx.tar.gz\r\n# 授予程序执行权限:\r\nchmod +x alist\r\n# 运行程序\r\n./alist server\r\n\r\n# 获得管理员信息 以下两个不同版本,新版本也有随机生成和手动设置\r\n# 低于v3.25.0版本\r\n./alist admin\r\n\r\n# 高于v3.25.0版本\r\n# 随机生成一个密码\r\n./alist admin random\r\n# 手动设置一个密码 `NEW_PASSWORD`是指你需要设置的密码\r\n./alist admin set NEW_PASSWORD\r\n\r\n```\r\n\r\n\r\n\r\n使用任意方式编辑 `/usr/lib/systemd/system/alist.service` 并添加如下内容,其中 path_alist 为 AList 所在的路径\r\n\r\n```shell\r\n[Unit]\r\nDescription=alist\r\nAfter=network.target\r\n \r\n[Service]\r\nType=simple\r\nWorkingDirectory=path_alist\r\nExecStart=path_alist/alist server\r\nRestart=on-failure\r\n \r\n[Install]\r\nWantedBy=multi-user.target\r\n\r\n```\r\n\r\n然后,执行 systemctl daemon-reload 重载配置,现在你可以使用这些命令来管理程序:\r\n**• 启动: systemctl start alist**\r\n**• 关闭: systemctl stop alist**\r\n**• 配置开机自启: systemctl enable alist**\r\n**• 取消开机自启: systemctl disable alist**\r\n**• 状态: systemctl status alist**\r\n**• 重启: systemctl restart alist**", + "Linux/把Ubuntu镜像源切换到阿里云.md": "要将 Ubuntu 22.04 (AMD64) 的软件源更换为阿里云的镜像源,可以按照以下步骤操作:\n\n### 1. 备份当前的源列表\n\n在更改源之前,先备份原有的 `sources.list` 文件:\n\n```bash\nsudo cp /etc/apt/sources.list /etc/apt/sources.list.bak\n```\n\n### 2. 修改 `sources.list` 文件\n\n打开 `/etc/apt/sources.list` 文件,编辑并替换为阿里云的源地址:\n\n```bash\nsudo nano /etc/apt/sources.list\n```\n\n将文件内容替换为以下内容(适用于 Ubuntu 22.04):\n\n```plaintext\n# 阿里云 Ubuntu 22.04 镜像源\ndeb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse\n\ndeb http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse\n\ndeb http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse\n\ndeb http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse\n```\n\n### 3. 更新软件包列表\n\n替换源后,更新 apt 包索引:\n\n```bash\nsudo apt update\n```\n\n### 4. 升级已安装的软件包\n\n为了确保一切顺利运行,你可以运行以下命令来升级现有的软件包:\n\n```bash\nsudo apt upgrade\n```\n\n完成这些步骤后,你的 Ubuntu 系统应该就会使用阿里云的镜像源了,下载速度会更加快速稳定。\n\n", + "Linux/构建最小Linux系统.md": "以下是手动构建一个极简Linux系统(约10MB)的完整步骤,包含内核和基础用户空间:\r\n\r\n### 1. 准备环境(Ubuntu/Debian示例)\r\n```bash\r\nsudo apt install -y build-essential libncurses-dev bison flex qemu-system-x86\r\nmkdir tiny_linux && cd tiny_linux\r\n```\r\n\r\n### 2. 编译定制化内核(5MB)\r\n```bash\r\n# 下载最新稳定版内核\r\nwget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.8.tar.xz\r\ntar xf linux-6.9.8.tar.xz && cd linux-6.9.8\r\n\r\n# 最小化配置\r\nmake defconfig\r\nmake menuconfig # 手动调整以下选项:\r\n# General setup\r\n# [ ] Configure standard kernel features (expert users)\r\n# Device Drivers\r\n# [*] Block devices > RAM block device support (16MB)\r\n# [*] Network device support > Ethernet driver support > Intel(R) PRO/1000\r\n# File systems\r\n# [*] Ext2\r\n# [ ] Btrfs\r\n# [ ] XFS\r\n# [*] Enable loadable module support # 禁用\r\n\r\n# 编译内核\r\nmake -j$(nproc) bzImage\r\n```\r\n\r\n### 3. 创建最小根文件系统(5MB)\r\n```bash\r\ncd ..\r\nmkdir rootfs && cd rootfs\r\n\r\n# 使用BusyBox构建基础工具\r\nwget https://busybox.net/downloads/busybox-1.36.1.tar.bz2\r\ntar xf busybox-1.36.1.tar.bz2 && cd busybox-1.36.1\r\nmake defconfig\r\nmake menuconfig # 选择静态编译:\r\n# Settings -> Build Options -> [*] Build static binary\r\n\r\nmake -j$(nproc) && make install\r\ncd _install\r\n\r\n# 创建必要目录\r\nmkdir -p proc sys dev etc/init.d\r\n\r\n# 创建启动脚本\r\ncat > etc/init.d/rcS <<EOF\r\n#!/bin/sh\r\nmount -t proc none /proc\r\nmount -t sysfs none /sys\r\n/sbin/mdev -s\r\nEOF\r\nchmod +x etc/init.d/rcS\r\n\r\n# 创建文件系统镜像\r\ndd if=/dev/zero of=rootfs.img bs=1M count=16\r\nmkfs.ext2 -F rootfs.img\r\nsudo mount -o loop rootfs.img /mnt\r\nsudo cp -r ./* /mnt\r\nsudo umount /mnt\r\n```\r\n\r\n### 4. 使用QEMU启动测试\r\n```bash\r\nqemu-system-x86_64 \\\r\n -kernel ../linux-6.9.8/arch/x86/boot/bzImage \\\r\n -hda rootfs.img \\\r\n -append "root=/dev/ram0 console=ttyS0" \\\r\n -nographic\r\n```\r\n\r\n### 5. 可选优化(缩减体积)\r\n```bash\r\n# 使用UPX压缩可执行文件\r\nsudo apt install upx\r\nfind . -type f -executable | xargs upx --best\r\n\r\n# 移除调试符号\r\nstrip --strip-all busybox\r\n\r\n# 使用musl libc替代glibc\r\nwget https://musl.libc.org/releases/musl-1.2.4.tar.gz\r\ntar xzf musl-1.2.4.tar.gz && cd musl-1.2.4\r\n./configure --prefix=/usr/local/musl && make && sudo make install\r\n```\r\n\r\n### 6. 构建结果\r\n```\r\n├── linux-6.9.8\r\n│ └── arch/x86/boot/bzImage # 内核文件\r\n├── rootfs\r\n│ ├── bin # 基础命令\r\n│ ├── rootfs.img # 根文件系统镜像\r\n│ └── etc # 配置文件\r\n```\r\n\r\n### 替代方案:使用Buildroot快速构建\r\n```bash\r\ngit clone https://github.com/buildroot/buildroot\r\ncd buildroot\r\nmake menuconfig # 选择:\r\n# Target options -> Target Architecture = x86_64\r\n# System configuration -> Root filesystem overlay = ../rootfs\r\n# Kernel -> Linux Kernel = 6.9.8\r\nmake -j$(nrep)\r\n```\r\n\r\n### 系统特性对比\r\n\r\n| 组件 | 手动构建 | Buildroot构建 |\r\n| ------------ | -------- | ------------- |\r\n| 启动时间 | <1s | <1.5s |\r\n| 内存占用 | 8MB | 12MB |\r\n| 可执行文件数 | 12个 | 25个 |\r\n| 支持网络 | 否 | 是 |\r\n| 支持动态库 | 否 | 可选 |\r\n\r\n建议从手动构建开始学习原理,实际项目使用Buildroot可节省90%时间。后续可添加OpenSSH(+1.2MB)或Web服务器(+0.8MB)等组件扩展功能。", + "Linux/某安卓板子不知名初始化脚本.md": "adb push busybox /tmp\r\nadb shell\r\ncd /tmp\r\nchmod 777 *\r\n./busybox ifconfig wlan0 up", + "Linux/树萌芽常用Linux命令集合.md": "tar.gz文件解压:\ntar -zxvf 文件名\n\nlinux 重命名文件/文件夹:\nmv 原文件名 新文件名\n\n注意:/etc/systemd/system/ 这里放置systemctl服务\n\n重新加载systemctl服务:\nsystemctl daemon-reload\n\nsystemctl start 服务名\nsystemctl stop 服务名\nsystemctl enable 服务名\nsystemctl status 服务名\n", + "Linux/树萌芽的局域网中网IP分配.md": "# IP分段:192.168.31.1-192.168.31.255\r\n\r\n## ------------------------------------------------------------\r\n\r\n## 10 20 30 40 50 60 70\r\n\r\n## 66 99 88 11 22 33 44 55\r\n\r\n## 110 120 119 \r\n\r\n## 111 222\r\n\r\n## 233\r\n\r\n## ------------------------------------------------------------\r\n\r\n## x86电脑系列\r\n\r\n#### Windows11\r\n\r\n#### Linux Mint\r\n\r\n#### 树萌芽NAS(大萌芽):233\r\n\r\n\r\n\r\n## 安卓手机系列\r\n\r\n#### 红萌芽盘 :222\r\n\r\n#### 黑萌芽盘 :111\r\n\r\n#### 小萌芽盘: \r\n\r\n\r\n\r\n#### vivo平板\r\n\r\n#### OPPO手机\r\n\r\n\r\n\r\n## 随身WiFi系列\r\n\r\n#### UFI1003 \r\n\r\n#### UZ801\r\n\r\n#### UZ901\r\n\r\n#### UFI100C 目前有9个\r\n\r\n### IP:11 - 99\r\n\r\n\r\n\r\n#### \r\n\r\n#### \r\n\r\n#### \r\n\r\n#### \r\n\r\n\r\n\r\n", + "Linux/编译alist.md": "以下是编译 Alist 前后端的详细步骤:\r\n\r\n---\r\n\r\n### **1. 准备工作**\r\n#### 环境要求:\r\n- **Go 1.16+** (后端依赖)\r\n- **Node.js 14+** (前端依赖)\r\n- **Git** (代码管理)\r\n- **Yarn** 或 **npm** (前端包管理)\r\n\r\n#### 安装依赖:\r\n```bash\r\n# 安装 Go (以 Linux 为例)\r\nwget https://golang.org/dl/go1.20.linux-amd64.tar.gz\r\nsudo tar -C /usr/local -xzf go1.20.linux-amd64.tar.gz\r\nexport PATH=$PATH:/usr/local/go/bin\r\n\r\n# 安装 Node.js (推荐使用 nvm)\r\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash\r\nnvm install 16\r\nnvm use 16\r\n\r\n# 安装 Yarn\r\nnpm install -g yarn\r\n```\r\n\r\n---\r\n\r\n### **2. 后端编译**\r\n#### 获取源码:\r\n```bash\r\ngit clone https://github.com/alist-org/alist.git\r\ncd alist\r\n```\r\n\r\n#### 安装依赖并编译:\r\n```bash\r\n# 进入后端目录\r\ncd alist\r\n\r\n# 下载 Go 依赖\r\ngo mod download\r\n\r\n# 编译(默认生成当前系统的可执行文件)\r\ngo build -o alist main.go\r\n\r\n# 交叉编译(示例:编译 Linux AMD64)\r\nCGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o alist-linux-amd64 main.go\r\n```\r\n\r\n编译完成后,会在当前目录生成可执行文件 `alist`(或指定名称)。\r\n\r\n---\r\n\r\n### **3. 前端编译**\r\n#### 进入前端目录:\r\n```bash\r\ncd ../web # 假设源码根目录为 alist/\r\n```\r\n\r\n#### 安装依赖并构建:\r\n```bash\r\nyarn install # 或使用 npm install\r\nyarn build # 或使用 npm run build\r\n```\r\n\r\n构建完成后,静态文件会生成在 `dist` 目录中。\r\n\r\n---\r\n\r\n### **4. 整合前后端**\r\n将前端构建的静态文件复制到后端目录的 `public` 文件夹中:\r\n```bash\r\n# 创建 public 目录(如果不存在)\r\nmkdir -p ../alist/public\r\n\r\n# 复制前端文件\r\ncp -r dist/* ../alist/public/\r\n```\r\n\r\n---\r\n\r\n### **5. 运行 Alist**\r\n```bash\r\n# 进入后端目录\r\ncd ../alist\r\n\r\n# 赋予执行权限(Linux/macOS)\r\nchmod +x alist\r\n\r\n# 启动服务\r\n./alist server\r\n```\r\n\r\n默认访问地址:`http://localhost:5244`\r\n\r\n---\r\n\r\n### **6. 高级配置**\r\n1. **修改配置文件** \r\n 首次运行后会在程序目录生成 `data/config.json`,可按需修改端口、存储驱动等。\r\n\r\n2. **自定义前端变量** \r\n 在 `web/.env` 文件中修改环境变量(如 API 地址):\r\n ```env\r\n VITE_API_URL=http://your-domain.com:5244\r\n ```\r\n\r\n3. **Docker 编译(可选)** \r\n Alist 官方提供 Docker 镜像,也可自行构建:\r\n ```bash\r\n docker build -t alist .\r\n ```\r\n\r\n---\r\n\r\n### **常见问题**\r\n1. **依赖安装失败** \r\n - 检查网络是否通畅(尤其是 Go 依赖可能需要代理)。\r\n - 确保 Node.js 和 Go 版本符合要求。\r\n\r\n2. **前端构建报错** \r\n - 清理缓存:`yarn cache clean` 或 `rm -rf node_modules`。\r\n - 检查 `web/package.json` 中的依赖版本是否冲突。\r\n\r\n3. **启动后无法访问** \r\n - 检查防火墙是否开放端口(默认 `5244`)。\r\n - 确认 `config.json` 中 `address` 设置为 `0.0.0.0`(允许外部访问)。\r\n\r\n---\r\n\r\n通过以上步骤,你可以成功编译并运行 Alist 的完整服务。如需更多定制化配置,建议参考 [Alist 官方文档](https://alist.nn.ci/)。", + "Linux/编译busybox步骤.md": "```shell\r\npkg update && pkg upgrade\r\npkg install git make clang\r\napt install gcc\r\nexport CC=clang\r\napt install build-essential\r\npkg install ncurses-dev\r\ngit clone https://git.busybox.net/busybox\r\ncd busybox\r\nmake menuconfig\r\n#make -j$(nproc) \r\nmake -j4\r\nmake install\r\n\r\n\r\n```\r\n\r\n```shell\r\n#可选创建符号链接\r\nPREFIX=$HOME/.local\r\nmkdir -p $PREFIX/bin\r\nfor applet in $(./busybox --list); do\r\n ln -s $PREFIX/bin/busybox $PREFIX/bin/$applet\r\ndone\r\n\r\n```\r\n\r\n", + "Linux/飞牛os切换root.md": "1.打开飞牛ssh\r\n2.ssh软件连接上飞牛(飞牛账号)\r\n3.给root新建密码:sudo passwd root 回车\r\n再次输入飞牛密码\r\n再输入密码(root密码)两次(不回显,每次输完回车)\r\n4.配置权限文件:sudo nano /etc/ssh/sshd_config 回车\r\n5.光标移动到:permitrootlogin no 把no 改为yes \r\n6.ctrl+o(写入文本)回车 ctrl+x(退出) 重启服务器:sudo reboot\r\n7.重启ssh服务:sudo service sshd restart\r\n8.用命令切换root账号:su -(或者sudo su -)还要输入一次目前飞牛密码回车就切换root了。", + "Minecraft/Minecraft常用命令.md": "***/kill @e[type=mutant:mskeleton_bones]*** \n清除掉突变骷髅模组的骷髅骨头实体\n\n***/kill @e[type=item]*** \n清除所有掉落物\n\n***/gamerule mobGriefing true*** \n设置生物破坏开启或者禁用 (禁用后村民不会繁殖,雪傀儡不会产雪)", + "Obsidion/Obsidion美化.md": "```json\n{\n \"Appearance-light@@theme-light-style-select\": \"theme-light-background-adapt\",\n \"Appearance-light@@mod-left-split-background-select-light\": \"mod-left-split-background-CSS-light\",\n \"Appearance-light@@background-mod-left-CSS-light\": \"radial-gradient(100% 50% at 100% 50%, rgba(90, 109, 237, 0.1) 0%, rgba(255, 255, 255, 0) 100%)\",\n \"Appearance-light@@background-mod-left-CSS-backdrop-filter-light\": \"blur(0px)\",\n \"Appearance-light@@mod-right-split-background-select-light\": \"mod-right-split-background-CSS-light\",\n \"Appearance-light@@background-mod-right-CSS-light\": \"radial-gradient(100% 50% at 0% 50%, rgba(90, 109, 237, 0.1) 0%, rgba(255, 255, 255, 0) 100%)\",\n \"Appearance-light@@background-mod-right-CSS-backdrop-filter-light\": \"blur(0px)\",\n \"Appearance-light@@mod-root-split-background-select-light\": \"mod-root-split-background-CSS-light\",\n \"Appearance-light@@background-mod-root-CSS-light\": \"transparent\",\n \"Appearance-light@@background-mod-root-CSS-backdrop-filter-light\": \"blur(0px)\",\n \"Appearance-light@@background-underlying-select-light\": \"background-underlying-CSS-light\",\n \"Appearance-light@@background-underlying-CSS-light\": \"linear-gradient(168.44deg, #D7DAEA 1.62%, #F2F2F8 95.72%)\",\n \"Appearance-light@@background-underlying-CSS-blend-mode-light\": \"normal\",\n \"Appearance-light@@card-border-radius-light\": \"0px\",\n \"Appearance-light@@card-shadow-light\": \"none\",\n \"Appearance-light@@background-activated-tab-header-light\": \"radial-gradient(50% 150% at 50% 150%, #F8F9FF 0%, rgba(97, 54, 144, 0) 100%)\",\n \"Appearance-light@@shadow-activated-tab-header-light\": \"none\",\n \"Appearance-light@@indicator-remove-light\": true,\n \"Appearance-light@@Active-states-file-explorer-select-light\": \"activated-file-tab-style-light\",\n \"Appearance-light@@workspace-divider-transparent-light\": true,\n \"Components@@CTA-BTN-enable\": true,\n \"Components@@file-names-untrim\": true,\n \"Components@@folder-font-bold\": true,\n \"Components@@colorful-folder\": true,\n \"Components@@file-icon-remove\": false,\n \"Components@@outline-enhanced\": true,\n \"Components@@new-tab-btn-select\": \"new-tab-btn-default\",\n \"Components@@immersive-canvas\": true,\n \"Components@@scrollbar-hide\": true,\n \"Appearance-light@@card-layout-open-light\": true,\n \"Appearance-light@@accent-color-override-light\": false,\n \"Appearance-light@@card-highlight-light\": true,\n \"Editor@@line-hover-indicator\": true,\n \"Editor@@focus-indicator-codeblock-line-number\": true,\n \"Editor@@focus-indicator-list-level\": true,\n \"Editor@@editor-grid-background-pattren\": true,\n \"Editor@@inline-title-divider-remove\": true,\n \"Editor@@h1-divider-on\": true,\n \"Editor@@h2-divider-on\": true,\n \"Editor@@h3-divider-on\": true,\n \"Editor@@h4-divider-on\": true,\n \"Editor@@h5-divider-on\": true,\n \"Editor@@h6-divider-on\": true,\n \"Editor@@text-align-justify\": true,\n \"Editor@@bold-color@@light\": \"#4781EC\",\n \"Editor@@italic-color@@light\": \"#FF4BFE\",\n \"Editor@@img-center-align\": true,\n \"Mobile@@drawer-phone-full-width\": true,\n \"Mobile@@card-layout-pad-open\": true,\n \"Plugin@@colorful-checkbox\": true\n}\n```", + "嵌入式/USB拓展坞接口数量决定因素.md": "一个USB拓展坞(或集线器)能拓展多少个USB接口,主要由以下几个因素决定:\n \n1. USB协议规范与层级限制\n \n- USB主机控制器的能力:电脑本身的USB主机控制器(如主板上的控制器)决定了初始可连接的设备数量。根据USB规范,一个主机控制器理论上最多可连接 127个设备,但这是通过多级集线器级联实现的(例如主机→一级集线器→二级集线器→……)。\n- 单级集线器的端口数:单个集线器(如拓展坞)的直接端口数通常为 4、7、10个 等,这是由集线器芯片的设计决定的。例如,常见的4口集线器是单芯片直接支持的标准配置。\n \n2. 集线器芯片的硬件设计\n \n- 主控芯片的能力:不同型号的集线器芯片(如瑞萨、德州仪器等品牌)支持的端口数量不同。芯片内部集成的物理接口数量和信号处理能力直接限制了拓展坞的端口数。\n- 信号分配与带宽共享:USB接口共享总线带宽(如USB 3.0的5Gbps),过多端口可能导致带宽不足。因此,芯片设计时会平衡端口数与性能,避免过多端口导致速度下降。\n \n3. 电源供应能力\n \n- 主机供电 vs 外接电源:\n- 无外接电源(总线供电):依赖电脑USB端口的功率(USB 2.0约500mA,USB 3.0约900mA)。若拓展坞无外接电源,总功率需低于主机端口上限,否则可能因供电不足导致设备无法工作(例如连接多个移动硬盘时易出现问题)。\n- 有外接电源(自供电):通过适配器供电,可支持更多高功耗设备,端口数主要受芯片和设计限制。\n- 单端口功率限制:每个USB端口需符合规范(如USB 2.0单端口最大500mA,USB 3.0最大900mA),总功率需在集线器设计的安全范围内。\n \n4. 信号传输与物理限制\n \n- 信号衰减与稳定性:USB信号在长距离或多端口分支中会衰减,尤其是高速率信号(如USB 3.0以上)。拓展坞的电路设计需保证信号完整性,过多端口可能增加干扰风险,因此实际端口数会受限于硬件可靠性。\n- 物理空间与布局:拓展坞的体积和接口排列也会影响端口数量,例如小型便携拓展坞通常设计为4口,而桌面级集线器可能有7-10个端口。\n \n5. 厂商设计与市场需求\n \n- 用户场景导向:厂商会根据目标用户(如普通办公、专业外设连接)设计端口数。例如,针对轻薄本的拓展坞可能集成4-6个端口(兼顾便携性和实用性),而工业级集线器可能支持更多端口。\n- 成本与性价比:更多端口意味着更高的芯片和制造成本,厂商需在功能与价格间平衡。\n \n总结\n \n核心决定因素:\n \n- USB协议的层级与单集线器端口限制\n- 集线器芯片的硬件设计(端口数、带宽分配)\n- 电源供应能力(是否外接电源及总功率)\n- 信号传输的稳定性与物理空间限制\n \n实际中,常见的USB拓展坞多为 4-7个端口,高端或专用集线器可能支持更多(如10口以上),但需结合外接电源和高效的芯片方案来保证性能。", + "数据库/json文件储存和MongoDB储存优缺点.md": "游戏玩家数据储存在普通JSON文件和MongoDB中各有其适用场景,二者的优缺点对比可结合游戏数据的特性(如数据量、读写频率、结构灵活性、并发需求等)展开分析:\n \n一、普通JSON文件储存\n \n普通JSON文件储存指将玩家数据以JSON格式写入本地文件(单文件或多文件,如按玩家ID分文件),依赖文件系统直接读写。\n \n优点\n \n1. 简单轻量,开发成本低\n无需部署数据库服务,直接通过编程语言的文件操作API(如Python的 json 模块、Node.js的 fs 模块)即可读写,适合小型团队或开发初期快速验证功能,学习成本几乎为0。\n2. 资源占用少\n仅依赖文件系统,不消耗额外的数据库进程资源(如内存、CPU),适合设备性能有限的场景(如单机小游戏、轻量网页游戏)。\n3. 数据直观可见\nJSON文件为文本格式,可直接用编辑器打开查看或修改,便于开发调试(如临时修改玩家数据测试功能)。\n \n缺点\n \n1. 读写效率低,不适合大数据量\n- 每次读写需加载整个JSON文件到内存解析(或写入时覆盖整个文件),当玩家数据量增大(如10万+玩家),单文件体积膨胀,读写耗时会急剧增加(例如加载100MB的JSON文件可能需要数百毫秒)。\n- 若按玩家ID分文件,虽能缓解单文件压力,但批量查询(如排行榜、全服统计)需遍历所有文件,效率极低。\n2. 并发安全问题突出\n多玩家同时操作时(如多人在线游戏的并发读写),文件系统缺乏原生锁机制,易出现“写覆盖”(如A玩家写入时B玩家同时写入,导致其中一方数据丢失)或数据损坏(如写入中断导致JSON格式错误)。\n3. 结构扩展性差\n若玩家数据结构迭代(如新增“宠物属性”“公会信息”),需手动处理旧JSON文件的格式兼容(如遍历所有文件添加新字段),操作繁琐且易出错。\n4. 缺乏数据一致性保障\n无事务支持,例如玩家“扣金币+加道具”的原子操作,若中途程序崩溃,可能导致金币已扣但道具未加,数据不一致。\n \n二、MongoDB储存\n \nMongoDB是文档型NoSQL数据库,以BSON(JSON的二进制扩展)格式存储数据,天然适配半结构化的玩家数据。\n \n优点\n \n1. 高效读写与查询能力\n- 支持索引(如按玩家ID、等级建索引),可快速定位单玩家数据(毫秒级),解决JSON文件全量解析的性能问题。\n- 支持复杂查询(如“等级>50且在线的玩家”“道具列表包含某物品的玩家”),适合游戏中的排行榜、好友列表、任务统计等场景。\n2. 良好的并发与一致性\n- 内置多版本并发控制(MVCC),支持高并发读写( thousands of TPS),避免JSON文件的并发冲突。\n- 支持事务(MongoDB 4.0+),可保证“扣钱+加道具”“升级+解锁技能”等操作的原子性,防止数据不一致。\n3. 灵活扩展,适配数据增长\n- 玩家数据量随用户增长时,可通过“分片”横向扩展(将数据分布到多台服务器),支持百万级甚至亿级玩家数据。\n- 文档结构动态灵活,新增字段无需修改表结构,旧数据可兼容(查询时自动忽略不存在的字段),适配游戏版本迭代。\n4. 完善的数据管理能力\n提供备份( mongodump )、恢复( mongorestore )、监控(MongoDB Atlas)等工具,支持数据压缩、过期索引(如清理离线玩家缓存),适合长期运行的在线游戏。\n \n缺点\n \n1. 运维与学习成本高\n需要部署、维护数据库服务(如集群配置、索引优化、故障排查),对小型团队可能增加运维压力;开发人员需学习MongoDB的查询语法(如 find 、 aggregate )、索引设计等,门槛高于JSON文件。\n2. 资源占用较高\n相比JSON文件,MongoDB需要额外的内存(缓存索引和热数据)、CPU(处理查询)和磁盘空间(数据文件+日志),不适合资源受限的极简场景(如嵌入式小游戏)。\n3. 过度设计风险\n对于单机游戏、玩家数极少(如几百人)且无复杂查询的场景,MongoDB的优势无法体现,反而因配置复杂降低开发效率。\n \n总结:适用场景\n \n- 普通JSON文件:适合单人游戏、小型休闲游戏、开发测试阶段,或数据量极小(<1万玩家)、读写频率低、无复杂查询的场景。\n- MongoDB:适合多人在线游戏(MMO、MOBA等)、中大型游戏,或玩家数多(>1万)、需高频读写、复杂查询、结构迭代频繁的场景。\n \n实际开发中,也可根据规模过渡:初期用JSON文件快速上线,待用户增长后迁移至MongoDB,利用其扩展性支撑业务。", + "数据库/MongoDB数据库优化方式一览.md": "除了索引之外,MongoDB 在 CRUD 操作优化上还有多种有效策略,尤其在处理海量数据时更为关键。以下是综合各技术文档和实践总结的核心优化方法:\n\n---\n\n### 🔄 一、批量操作优化\n1. **使用 `bulkWrite` 替代单条操作** \n 通过批量写入减少网络开销和事务开销。基于 `ReplaceOneModel` 启用 `upsert`,实现存在更新、不存在插入的高效操作:\n ```java\n public void batchSave(List dataList) {\n List> bulkOps = dataList.stream()\n .map(item -> {\n Document doc = convertToDocument(item); // 转换为Document\n return new ReplaceOneModel<>(\n Filters.eq(\"_id\", doc.get(\"_id\")), \n doc, \n new UpdateOptions().upsert(true)\n );\n }).collect(Collectors.toList());\n collection.bulkWrite(bulkOps); // 批量执行\n }\n ```\n 此方法将多条操作合并为一次请求,写入性能提升显著。\n\n---\n\n### 📖 二、分页查询优化\n1. **避免精确 `count`** \n 当数据量超大时,`count` 可能极慢。采用阈值法:若跳过 `MAX_PAGE_COUNT`(如1万条)后仍有数据,则返回阈值提示“数据超过1万条”,避免全表扫描:\n ```java\n private long approxCount(MongoTemplate mongoTemplate, Query query) {\n query = query.with(PageRequest.of(MAX_PAGE_COUNT, 1));\n return mongoTemplate.find(query, Entity.class).isEmpty() \n ? mongoTemplate.count(query) \n : MAX_PAGE_COUNT;\n }\n 。\n ```\n\n2. **用条件替代 `skip`** \n 深度分页时(如第100页),避免 `skip(9900)`。改为记录上一页末尾的排序字段值(如时间戳),作为下一页查询条件:\n ```sql\n -- 原查询:db.collection.find().sort({time:-1}).skip(9900).limit(100)\n -- 优化后:\n db.collection.find({ time: { $lt: lastPageEndTime } })\n .sort({ time: -1 })\n .limit(100);\n ```\n 此方法将 **O(N)** 的跳过操作转为 **O(1)** 的条件过滤。\n\n---\n\n### 📤 三、全量导出优化\n1. **字段投影减少数据传输** \n 仅查询必要字段,降低网络与内存开销:\n ```java\n Query query = new Query();\n query.fields().include(\"_id\").include(\"name\"); // 只返回_id和name。\n ```\n\n2. **流式处理替代全量加载** \n 使用 `stream()` 逐条处理数据,避免 `findAll` 导致内存溢出:\n ```java\n try (CloseableIterator iter = mongoTemplate.stream(query, Entity.class)) {\n while (iter.hasNext()) {\n process(iter.next()); // 单条处理\n }\n }\n ```\n 相比分页查询,流式处理无 `skip` 开销,且内存占用恒定。\n\n---\n\n### 🧩 四、文档设计优化\n1. **打破第三范式** \n - **冗余字段**:将高频查询的关联字段(如部门名称)冗余到主文档,避免联表查询。\n - **内嵌设计**:一对多关系直接嵌套子文档(如订单内嵌商品列表),提升读取效率。但需注意文档大小限制(16MB)。\n - **引用设计**:多对多关系使用ID数组而非完整嵌套,避免文档膨胀:\n ```json\n // 学生文档\n {\n \"_id\": \"s001\",\n \"name\": \"Alice\",\n \"teachers\": [\"t01\", \"t02\"] // 仅存储ID\n }\n ```\n\n---\n\n### ⚙️ 五、分片集群优化\n1. **碎片整理(MongoDB <7.0)** \n 在早期版本中,分片集合可能因频繁写入产生碎片化小数据块,导致CRUD延迟。通过 `configureCollectionBalancing` 命令合并数据块,但需注意:\n - 整理期间可能短暂阻塞元数据更新。\n - MongoDB 7.0+ 已支持自动合并,通常无需手动操作。\n\n2. **负载均衡窗口设置** \n 在业务低峰期触发负载均衡器迁移数据块,减少对CRUD的影响。\n\n---\n\n### 💎 六、其他关键技巧\n1. **合理控制事务范围**:短事务减少锁竞争。\n2. **写入确认级别调整**:对非关键数据使用 `w:0`(无确认),提升写入速度(牺牲一致性)。\n3. **TTL索引自动清理**:为临时数据(如日志)设置过期时间,减少存储压力。\n\n---\n\n### 💎 优化方法效果对比表\n| **优化方向** | **适用场景** | **性能提升效果** | **实现复杂度** |\n|--------------------|--------------------------|----------------------|--------------|\n| **批量写入** | 数据导入、批量更新 | ⭐⭐⭐⭐⭐ (极高) | ⭐⭐ (中等) |\n| **流式导出** | 大数据量导出 | ⭐⭐⭐⭐ (避免OOM) | ⭐ (简单) |\n| **条件分页** | 深度分页(>100页) | ⭐⭐⭐⭐ (O(1) 跳转) | ⭐⭐ (中等) |\n| **冗余字段** | 高频关联查询 | ⭐⭐⭐ (减少联表) | ⭐⭐⭐ (较高) |\n| **分片碎片整理** | MongoDB 6.0以下分片集群 | ⭐⭐ (减少延迟) | ⭐⭐⭐⭐ (复杂) |\n\n---\n\n> 💡 **实践建议**:优先从**批量操作**和**分页策略**入手,这两类优化代码改动小且收益显著。海量数据场景下,**流式处理+字段投影**是导出标配方案。分片集群升级到 MongoDB 7.0+ 可减少运维负担。", + "数据库/MongoDB的索引一览.md": "\n**索引的核心作用:**\n\n1. **大幅减少查询需要扫描的文档数量:** 没有索引时,MongoDB 必须执行集合扫描(`COLLSCAN`),即检查集合中的*每一个*文档。有了合适的索引,MongoDB 可以使用索引扫描(`IXSCAN`)快速定位到包含所需数据的文档位置。\n2. **加速排序:** 如果排序字段包含在索引中,MongoDB 可以直接利用索引中已经排好的顺序返回结果,避免昂贵的在内存中排序。\n3. **支持高效的数据去重:** `$group` 聚合阶段的分组操作可以利用索引。\n4. **实现覆盖查询:** 如果查询只需要返回索引中包含的字段,MongoDB 可以*完全*从索引中获取结果,无需去读取实际的文档数据,速度极快。\n\n**MongoDB 支持的索引类型:**\n\n1. **单字段索引:**\n * 最基本的索引类型,在单个字段上创建。\n * 示例:`db.collection.createIndex({ name: 1 })` (1 表示升序,-1 表示降序。对于纯等值查询,顺序通常不重要;对于排序查询,顺序很重要)。\n\n2. **复合索引:**\n * 在多个字段上创建的索引。\n * 字段的顺序**极其重要**。它决定了索引如何组织和哪些查询模式可以利用该索引(最左前缀原则)。\n * 示例:`db.collection.createIndex({ status: 1, order_date: -1 })`。这个索引可以高效支持:\n * 只查询 `status` 的查询\n * 同时查询 `status` 和 `order_date` 的查询\n * 查询 `status` 并按 `order_date` 排序的查询\n * 但不支持只查询 `order_date` 的查询(不符合最左前缀)。\n\n3. **多键索引:**\n * 当索引字段是数组时,MongoDB 会自动为数组中的每个元素创建索引条目。\n * 用于高效查询数组字段中的元素。\n * 示例:索引 `db.collection.createIndex({ tags: 1 })` 可以高效支持查询 `db.collection.find({ tags: \"mongodb\" })`。\n\n4. **地理空间索引:**\n * **2dsphere:** 用于查询存储为 GeoJSON 对象或传统坐标对的地理空间数据(地球球面几何)。支持邻近查询(`$near`)、包含查询(`$geoWithin`)、相交查询(`$geoIntersects`)等。\n * **2d:** 用于在二维平面上(如地图游戏)查询存储为传统坐标对的数据。主要用于平面几何计算。\n\n5. **文本索引:**\n * 支持对字符串或字符串数组字段的内容进行文本搜索。\n * 支持词干提取、停用词过滤等基本文本处理功能。\n * 示例:`db.collection.createIndex({ description: \"text\" })`,然后使用 `$text` 操作符进行搜索。\n\n6. **哈希索引:**\n * 对字段值进行哈希运算,并在哈希值上建立索引。\n * 主要用途是为**分片键**提供更均匀的数据分布(使用`hashed`分片策略时)。\n * 只支持等值匹配查询,不支持范围查询、排序或其他操作。\n * 示例:`db.collection.createIndex({ _id: \"hashed\" })`。\n\n7. **通配符索引:**\n * 可以索引文档中未知或任意字段。适用于模式动态变化的场景。\n * 示例:\n * `db.collection.createIndex({ \"userMetadata.$**\": 1 })` 索引 `userMetadata` 子文档中的所有字段。\n * `db.collection.createIndex({ \"$**\": 1 })` 索引文档中的所有字段(谨慎使用,开销大)。\n\n8. **唯一索引:**\n * 强制索引字段的值在整个集合中是唯一的(`_id` 字段默认就有唯一索引)。\n * 可以用于单字段或复合字段。\n * 示例:`db.collection.createIndex({ email: 1 }, { unique: true })`。\n\n9. **TTL 索引:**\n * 一种特殊的单字段索引,用于在指定时间后或在指定时间点自动从集合中删除文档。字段必须是日期类型或包含日期元素的数组。\n * 适用于会话数据、日志、临时数据等。\n * 示例:`db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })` (文档在 `createdAt` 时间之后 3600 秒/1 小时被删除)。\n\n10. **稀疏索引:**\n * 只包含具有索引字段的文档的条目。即使索引字段值为 `null`,也会包含在内;但如果文档*完全缺失*该索引字段,则不会被索引。\n * 节省空间,提高索引效率(当字段在大部分文档中缺失时)。\n * 示例:`db.collection.createIndex({ optionalField: 1 }, { sparse: true })`。\n\n**如何管理和使用索引:**\n\n1. **创建索引:** 使用 `db.collection.createIndex()` 方法。\n * 示例:`db.products.createIndex({ category: 1, price: -1 })`\n2. **查看索引:** 使用 `db.collection.getIndexes()` 方法。\n3. **删除索引:** 使用 `db.collection.dropIndex()` 或 `db.collection.dropIndexes()` 方法。\n4. **分析查询性能:** 使用 `explain()` 方法查看查询的执行计划,确认是否使用了索引(`IXSCAN`)以及使用了哪个索引。这是优化查询的关键步骤。\n * 示例:`db.orders.find({ status: \"A\", amount: { $gt: 100 } }).sort({ order_date: -1 }).explain(\"executionStats\")`\n5. **索引管理最佳实践:**\n * **为常用查询模式创建索引:** 分析你的应用最常见的查询(`find`, `sort`, `aggregate`中的`$match`, `$group`, `$sort`等阶段),为这些查询涉及的字段创建合适的索引(通常是复合索引)。\n * **遵循最左前缀原则:** 设计复合索引时,将最常用于过滤或排序的字段放在左边。\n * **考虑选择性:** 选择性高的字段(如唯一值多的字段)放在复合索引的前面通常更有效。\n * **使用覆盖查询:** 尽量让查询只返回索引中包含的字段。\n * **监控索引使用率:** MongoDB Profiler 或 Atlas 性能监控可以查看索引的使用情况。使用率低的索引应考虑删除,因为它们会消耗写性能和存储空间。\n * **权衡读写性能:** 索引会加速读操作,但会减慢写操作(插入、更新、删除),因为写操作需要维护索引。不要过度索引。\n * **后台创建大索引:** 在大型集合上创建索引可能耗时很长并阻塞操作。使用 `{ background: true }` 选项可以在后台创建索引(虽然仍可能有性能影响,但不会完全阻塞读写)。\n * **合理使用内存:** 确保有足够的内存将常用索引(或其活跃部分)保存在内存中,避免频繁的磁盘 I/O。\n\n**总结:**\n\nMongoDB 提供了极其丰富和强大的索引类型(单字段、复合、多键、地理空间、文本、哈希、通配符、唯一、TTL、稀疏)来满足各种查询场景的优化需求。**创建和管理合适的索引是提升 MongoDB 查询性能最关键的手段。** 务必结合你的具体查询模式,使用 `explain()` 分析执行计划,遵循索引设计的最佳实践(特别是复合索引的最左前缀原则),并持续监控和调整索引策略。", + "数据库/MySQL数据库支持的数据类型.md": " \n\n## 1️⃣ 数值类型(Numeric)\n\n| 类型分类 | 数据类型 | 说明 |\n| ---- | --------------------------------------------------------- | ------------- |\n| 整数型 | `TINYINT`、`SMALLINT`、`MEDIUMINT`、`INT`/`INTEGER`、`BIGINT` | 存储不同范围的整数 |\n| 精确小数 | `DECIMAL(M,D)`、`NUMERIC` | 高精度定点数(常用于金额) |\n| 浮点数 | `FLOAT`、`DOUBLE`/`REAL` | 近似数值(科学计算) |\n| 位类型 | `BIT(M)` | 存储二进制位 |\n| | | |\n| | | |\n\n---\n\n## 2️⃣ 日期与时间类型(Date & Time)\n\n|数据类型|格式|说明|\n|---|---|---|\n|`DATE`|YYYY-MM-DD|日期|\n|`DATETIME(fsp)`|YYYY-MM-DD HH:MM:SS|日期 + 时间|\n|`TIMESTAMP(fsp)`|YYYY-MM-DD HH:MM:SS|时间戳(支持自动更新)|\n|`TIME`|HH:MM:SS|时间或时间间隔|\n|`YEAR`|YYYY|年份(2 位或 4 位)|\n\n---\n\n## 3️⃣ 字符串与二进制类型(String & Binary)\n\n|类型分类|数据类型|说明|\n|---|---|---|\n|定长字符串|`CHAR(M)`|定长,最大 255|\n|变长字符串|`VARCHAR(M)`|可变长度,最大 65535(受行大小限制)|\n|定长二进制|`BINARY(M)`|定长二进制|\n|变长二进制|`VARBINARY(M)`|变长二进制|\n|文本|`TINYTEXT`、`TEXT`、`MEDIUMTEXT`、`LONGTEXT`|存储大文本|\n|二进制大对象|`TINYBLOB`、`BLOB`、`MEDIUMBLOB`、`LONGBLOB`|存储二进制数据|\n|枚举|`ENUM('a','b',...)`|单选固定集合|\n|集合|`SET('a','b',...)`|多选固定集合|\n\n---\n\n## 4️⃣ 空间数据类型(Spatial)\n\n|数据类型|说明|\n|---|---|\n|`GEOMETRY`|任意几何对象|\n|`POINT`|点|\n|`LINESTRING`|线|\n|`POLYGON`|多边形|\n|`MULTIPOINT`、`MULTILINESTRING`、`MULTIPOLYGON`、`GEOMETRYCOLLECTION`|组合空间对象|\n\n---\n\n## 5️⃣ JSON 类型\n\n|数据类型|说明|\n|---|---|\n|`JSON`|存储 JSON 文档,支持索引与函数操作|\n\n---\n", + "数据结构与算法/二分查找右侧边界算法总结.md": "# 二分查找右侧边界算法总结\r\n\r\n\r\n\r\n## 题目描述\r\n\r\n\r\n\r\n在一个有序不递减的数组中(可能包含重复元素),使用二分查找找到某个值 `x` 最后一次出现的位置。如果该值不存在,则返回 -1。\r\n\r\n\r\n\r\n## 输入格式\r\n\r\n\r\n\r\n1. 第一行:一个整数 `n`,表示数组元素个数(`n <= 10^5`)。\r\n2. 第二行:`n` 个整数,代表数组元素(`1 <= 数组元素的值 <= 10^8`)。\r\n3. 第三行:一个整数 `q`,表示查询的数个数(`q <= 10^5`)。\r\n4. 第四行:`q` 个整数,代表要查找的值(`1 <= 要查找的数 <= 10^8`)。\r\n\r\n\r\n\r\n## 输出格式\r\n\r\n\r\n\r\n输出每个查询对应的最后一次出现的位置,若不存在则输出 -1。\r\n\r\n\r\n\r\n## 算法思路\r\n\r\n\r\n\r\n1. **初始化**:\r\n - 设置左右指针 `l` 和 `r`,分别指向数组的开始和结束。\r\n - 初始化结果 `res` 为 -1。\r\n2. **二分查找**:\r\n - 当l小于等于r时,执行以下步骤:\r\n - 计算中间索引 `m`。\r\n - 如果 `a[m]` 等于 `x`,更新 `res` 为 `m + 1`,并将 `l` 移动到 `m + 1` 继续向右查找。\r\n - 如果 `a[m]` 小于 `x`,将 `l` 移动到 `m + 1`。\r\n - 如果 `a[m]` 大于 `x`,将 `r` 移动到 `m - 1`。\r\n3. **输出结果**:\r\n - 返回结果 `res`。\r\n\r\n\r\n\r\n## 时间复杂度\r\n\r\n\r\n\r\n- 每次查找的时间复杂度为 O(log n),因此总时间复杂度为 O(q log n)。\r\n\r\n\r\n\r\n## 示例代码\r\n\r\n\r\n\r\n```c\r\nc#include \r\n\r\nint findRB(int a[], int n, int x) {\r\n int l = 0, r = n - 1, res = -1;\r\n\r\n while (l <= r) {\r\n int m = l + (r - l) / 2;\r\n\r\n if (a[m] == x) {\r\n res = m + 1;\r\n l = m + 1;\r\n } else if (a[m] < x) {\r\n l = m + 1;\r\n } else {\r\n r = m - 1;\r\n }\r\n }\r\n\r\n return res;\r\n}\r\n\r\nint main() {\r\n int n, q;\r\n\r\n scanf(\"%d\", &n);\r\n int a[n];\r\n\r\n for (int i = 0; i < n; i++) {\r\n scanf(\"%d\", &a[i]);\r\n }\r\n\r\n scanf(\"%d\", &q);\r\n int qry[q];\r\n\r\n for (int i = 0; i < q; i++) {\r\n scanf(\"%d\", &qry[i]);\r\n }\r\n\r\n for (int i = 0; i < q; i++) {\r\n int pos = findRB(a, n, qry[i]);\r\n printf(\"%d \", pos);\r\n }\r\n printf(\"\\n\");\r\n\r\n return 0;\r\n}\r\nc\r\n```\r\n\r\n\r\n\r\n## 总结\r\n\r\n\r\n\r\n该算法有效地使用二分查找来找到数组中元素的右侧边界,适合处理较大规模的输入数据。", + "数据结构与算法/二分查找图书馆算法总结.md": "谢谢你的反馈。我们来修正代码。编译错误主要有两个原因:\r\n\r\n\r\n\r\n1. **变量大小问题**:在 C 语言中,数组的大小必须是固定的声明。我们使用 `#define` 或 `const` 来定义常量。\r\n2. **缺少比较函数**:`cmp` 函数必须在调用之前声明,或者将比较逻辑嵌入到 `main` 函数之前。\r\n\r\n\r\n\r\n我们可以做以下改变:\r\n\r\n\r\n\r\n- 使用 `#define` 来定义常量。\r\n- 在 `main` 函数之前声明比较函数。\r\n\r\n\r\n\r\n以下是经过修正的 C 语言代码:\r\n\r\n\r\n\r\n```c\r\n#include \r\n#include \r\n\r\n#define MAXN 1000010\r\nint nums[MAXN];\r\nint key, n;\r\n\r\nint left_bound() {\r\n if (n == 0) return -1;\r\n int left = 0;\r\n int right = n - 1;\r\n\r\n while (left <= right) { \r\n int mid = left + ((right - left) >> 1);\r\n if (nums[mid] == key) {\r\n right = mid - 1;\r\n } else if (nums[mid] < key) {\r\n left = mid + 1;\r\n } else {\r\n right = mid - 1; \r\n }\r\n }\r\n if (left == n || nums[left] != key) return -1;\r\n return left;\r\n}\r\n\r\nint right_bound() {\r\n if (n == 0) return -1;\r\n int left = 0;\r\n int right = n - 1;\r\n\r\n while (left <= right) { \r\n int mid = left + ((right - left) >> 1);\r\n\r\n if (nums[mid] == key) {\r\n left = mid + 1;\r\n } else if (nums[mid] < key) {\r\n left = mid + 1;\r\n } else {\r\n right = mid - 1; \r\n }\r\n }\r\n if (left == 0 || nums[left - 1] != key) return -1;\r\n return left - 1;\r\n}\r\n\r\n// Compare function for qsort\r\nint cmp(const void *a, const void *b) {\r\n return (*(int*)a - *(int*)b);\r\n}\r\n\r\nint main() {\r\n scanf(\"%d %d\", &n, &key);\r\n for (int i = 0; i < n; i++) {\r\n scanf(\"%d\", &nums[i]); \r\n }\r\n qsort(nums, n, sizeof(int), cmp);\r\n \r\n if (left_bound() == -1) {\r\n printf(\"Not Found\\n\");\r\n return 0; \r\n }\r\n int ans = (left_bound() + right_bound()) / 2 + 1;\r\n printf(\"%d\\n\", ans);\r\n return 0;\r\n}\r\n```\r\n\r\n\r\n\r\n### 关键点说明\r\n\r\n\r\n\r\n1. **常量定义**:使用 `#define MAXN 1000010` 来定义数组的最大长度。\r\n2. **比较函数**:在 `main` 函数之前定义 `cmp` 函数,以便在使用 `qsort` 时可以调用。\r\n3. **错误处理**:添加了换行符 `\\n` 在 \"Not Found\" 输出中,以确保输出格式正确。\r\n\r\n\r\n\r\n### 总结\r\n\r\n\r\n\r\n这个版本应该能够成功编译并正常工作。如果还有问题,请继续反馈!", + "数据结构与算法/二分查找左侧边界算法总结.md": "# 二分查找左侧边界算法总结\r\n\r\n\r\n\r\n## 题目描述\r\n\r\n\r\n\r\n在一个有序不递减的数组中(可能包含重复元素),使用二分查找找到某个值 `x` 第一次出现的位置。如果该值不存在,则返回 -1。\r\n\r\n\r\n\r\n## 输入格式\r\n\r\n\r\n\r\n1. **第一行**:一个整数 `n`,表示数组元素个数(`n <= 10^5`)。\r\n2. **第二行**:`n` 个整数,代表数组元素(`1 <= 数组元素的值 <= 10^8`)。\r\n3. **第三行**:一个整数 `q`,表示查询的数个数(`q <= 10^5`)。\r\n4. **第四行**:`q` 个整数,代表要查找的值(`1 <= 要查找的数 <= 10^8`)。\r\n\r\n\r\n\r\n## 输出格式\r\n\r\n\r\n\r\n输出每个查询对应的第一次出现的位置,若不存在则输出 -1。\r\n\r\n\r\n\r\n## 算法思路\r\n\r\n\r\n\r\n1. **初始化**:\r\n - 设置左右指针 `l` 和 `r`,分别指向数组的开始和结束。\r\n - 初始化结果 `res` 为 -1。\r\n2. **二分查找**:\r\n - 当`l`小于等于`r`时,执行以下步骤:\r\n - 计算中间索引 `m`。\r\n - 如果 `a[m]` 等于 `x`,更新 `res` 为 `m + 1`,并将 `r` 移动到 `m - 1` 继续向左查找。\r\n - 如果 `a[m]` 小于 `x`,将 `l` 移动到 `m + 1`。\r\n - 如果 `a[m]` 大于 `x`,将 `r` 移动到 `m - 1`。\r\n3. **输出结果**:\r\n - 返回结果 `res`。\r\n\r\n\r\n\r\n## 时间复杂度\r\n\r\n\r\n\r\n- 每次查找的时间复杂度为 O(log n),因此总时间复杂度为 O(q log n)。\r\n\r\n\r\n\r\n## 示例代码\r\n\r\n\r\n\r\n```c\r\nc#include \r\n\r\nint findLB(int a[], int n, int x) {\r\n int l = 0, r = n - 1, res = -1;\r\n\r\n while (l <= r) {\r\n int m = l + (r - l) / 2;\r\n\r\n if (a[m] == x) {\r\n res = m + 1;\r\n r = m - 1;\r\n } else if (a[m] < x) {\r\n l = m + 1;\r\n } else {\r\n r = m - 1;\r\n }\r\n }\r\n\r\n return res;\r\n}\r\n\r\nint main() {\r\n int n, q;\r\n\r\n scanf(\"%d\", &n);\r\n int a[n];\r\n\r\n for (int i = 0; i < n; i++) {\r\n scanf(\"%d\", &a[i]);\r\n }\r\n\r\n scanf(\"%d\", &q);\r\n int qry[q];\r\n\r\n for (int i = 0; i < q; i++) {\r\n scanf(\"%d\", &qry[i]);\r\n }\r\n\r\n for (int i = 0; i < q; i++) {\r\n int pos = findLB(a, n, qry[i]);\r\n printf(\"%d \", pos);\r\n }\r\n printf(\"\\n\");\r\n\r\n return 0;\r\n}\r\nc\r\n```\r\n\r\n\r\n\r\n## 示例\r\n\r\n\r\n\r\n### 输入\r\n\r\n\r\n\r\n```\r\n6\r\n1 2 2 2 3 3\r\n3\r\n3 2 5\r\n```\r\n\r\n\r\n\r\n### 输出\r\n\r\n\r\n\r\n```\r\n5 2 -1 \r\n```\r\n\r\n\r\n\r\n## 总结\r\n\r\n\r\n\r\n该算法有效地使用二分查找来找到数组中元素的左侧边界,适合处理较大规模的输入数据。", + "数据结构与算法/判断素数.md": "```c\r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\n#define N 100005\r\n\r\nint prime[N];\r\nint c;\r\nbool isVisit[N];\r\n\r\nvoid tell(int n) {\r\n for (int i = 2; i <= n; ++i) {\r\n if (isVisit[i] == false)\r\n prime[++c] = i;\r\n for (int j = 1; j <= c && i * prime[j] <= n; ++j) {\r\n isVisit[i * prime[j]] = true;\r\n if (i % prime[j] == 0)\r\n break;\r\n }\r\n }\r\n}\r\n\r\nint main(void) {\r\n isVisit[0] = true;\r\n isVisit[1] = true;\r\n tell(N);\r\n int n;\r\n while (scanf(\"%d\", &n)!= EOF) {\r\n if (!isVisit[n])\r\n printf(\"Yes\\n\");\r\n else\r\n printf(\"No\\n\");\r\n }\r\n return 0;\r\n}\r\n```\r\n\r\n```c\r\n#include \r\n#include \r\n#include \r\n\r\n#define N 1000007\r\n\r\nint vis[N], prime[N];\r\n\r\nvoid sieve(int n) {\r\n int k = 0;\r\n memset(vis, 0, sizeof(vis));\r\n vis[0] = vis[1] = 1;\r\n for (int i = 2; i <= n; i++) {\r\n if (vis[i] == 0)\r\n prime[k++] = i;\r\n for (int j = 0; j < k; j++) {\r\n if (i * prime[j] > n)\r\n break;\r\n vis[i * prime[j]] = 1;\r\n if (i % prime[j] == 0)\r\n break;\r\n }\r\n }\r\n}\r\n\r\nint main() {\r\n sieve(N);\r\n int n;\r\n while (scanf(\"%d\", &n)!= EOF) {\r\n if (vis[n] == 0)\r\n printf(\"Yes\\n\");\r\n else\r\n printf(\"No\\n\");\r\n }\r\n return 0;\r\n}\r\n```\r\n\r\n```c\r\n#include \r\n#include \r\n\r\n#define MAXN 100001\r\n\r\nbool is_prime[MAXN];\r\n\r\nvoid sieve() {\r\n for (int i = 2; i < MAXN; i++) {\r\n is_prime[i] = true; // 初始化所有数为素数\r\n }\r\n is_prime[0] = is_prime[1] = false; // 0和1不是素数\r\n\r\n for (int i = 2; i * i < MAXN; i++) {\r\n if (is_prime[i]) {\r\n for (int j = i * i; j < MAXN; j += i) {\r\n is_prime[j] = false; // 标记合数\r\n }\r\n }\r\n }\r\n}//用空间换时间\r\n\r\nint main() {\r\n sieve(); // 进行素数筛选\r\n\r\n int n;\r\n while (scanf(\"%d\", &n) != EOF) {\r\n if (is_prime[n]) {\r\n printf(\"Yes\\n\");\r\n } else {\r\n printf(\"No\\n\");\r\n }\r\n }\r\n\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n", + "数据结构与算法/十大排序算法简介.md": "十大排序算法是计算机科学领域中常用的排序算法,根据其时间复杂度和实现方式大致可分为比较类排序和非比较类排序,以下为你详细介绍:\r\n\r\n### 比较类排序\r\n这类排序算法通过比较元素间的大小关系来确定元素的最终位置。\r\n1. **冒泡排序(Bubble Sort)**\r\n - **原理**:重复遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来,直到整个数列都被排序好,就像气泡从水底逐渐升到水面一样。\r\n - **时间复杂度**:$O(n^2)$ \r\n - **空间复杂度**:$O(1)$\r\n - **稳定性**:稳定 \r\n - **适用场景**:数据量较小且基本有序的情况。\r\n2. **选择排序(Selection Sort)**\r\n - **原理**:在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾,以此类推,直到所有元素均排序完毕。\r\n - **时间复杂度**:$O(n^2)$ \r\n - **空间复杂度**:$O(1)$\r\n - **稳定性**:不稳定\r\n - **适用场景**:数据量较小且对稳定性要求不高的情况。\r\n3. **插入排序(Insertion Sort)**\r\n - **原理**:将未排序数据插入到已排序序列的合适位置,就像玩扑克牌时整理手牌一样。\r\n - **时间复杂度**:$O(n^2)$ \r\n - **空间复杂度**:$O(1)$\r\n - **稳定性**:稳定\r\n - **适用场景**:数据量较小且基本有序的情况。\r\n4. **希尔排序(Shell Sort)**\r\n - **原理**:它是插入排序的一种改进版本,也称为缩小增量排序。通过将原始数据分成多个子序列来改善插入排序的性能,先比较距离较远的元素,而不是像插入排序那样比较相邻元素。\r\n - **时间复杂度**:与增量序列的选择有关,平均约为 $O(n^{1.3})$ \r\n - **空间复杂度**:$O(1)$\r\n - **稳定性**:不稳定\r\n - **适用场景**:中等规模的数据排序。\r\n5. **归并排序(Merge Sort)**\r\n - **原理**:采用分治法,将一个数组分成两个子数组,分别对这两个子数组进行排序,然后将排好序的子数组合并成一个最终的有序数组。\r\n - **时间复杂度**:$O(n log n)$ \r\n - **空间复杂度**:$O(n)$\r\n - **稳定性**:稳定\r\n - **适用场景**:数据量大且对稳定性有要求的情况。\r\n6. **快速排序(Quick Sort)**\r\n - **原理**:同样采用分治法,选择一个基准值,将数组分为两部分,使得左边部分的元素都小于等于基准值,右边部分的元素都大于等于基准值,然后递归地对左右两部分进行排序。\r\n - **时间复杂度**:平均 $O(n log n)$,最坏 $O(n^2)$ \r\n - **空间复杂度**:平均 $O(log n)$,最坏 $O(n)$\r\n - **稳定性**:不稳定\r\n - **适用场景**:数据量大且分布较为随机的情况。\r\n7. **堆排序(Heap Sort)**\r\n - **原理**:利用堆这种数据结构,通常是最大堆(每个节点的值都大于或等于其子节点的值)或最小堆,将待排序序列构造成一个堆,然后依次取出堆顶元素,调整堆结构,直到整个序列有序。\r\n - **时间复杂度**:$O(n log n)$ \r\n - **空间复杂度**:$O(1)$\r\n - **稳定性**:不稳定\r\n - **适用场景**:数据量大且对空间复杂度有要求的情况。\r\n\r\n### 非比较类排序\r\n这类排序算法不通过比较元素间的大小关系来确定元素的最终位置。\r\n8. **计数排序(Counting Sort)**\r\n - **原理**:通过统计每个元素出现的次数,然后根据统计结果将元素依次输出。它要求输入的数据必须是有确定范围的整数。\r\n - **时间复杂度**:$O(n + k)$,其中 $k$ 是数据范围。 \r\n - **空间复杂度**:$O(k)$\r\n - **稳定性**:稳定\r\n - **适用场景**:数据范围较小且数据值为整数的情况。\r\n9. **桶排序(Bucket Sort)**\r\n - **原理**:将数据分到有限数量的桶里,每个桶再分别进行排序(可以使用其他排序算法),最后将各个桶中的数据合并成一个有序序列。\r\n - **时间复杂度**:平均 $O(n + k)$,其中 $k$ 是桶的数量。 \r\n - **空间复杂度**:$O(n + k)$\r\n - **稳定性**:取决于桶内排序算法\r\n - **适用场景**:数据均匀分布在某个范围内的情况。\r\n10. **基数排序(Radix Sort)**\r\n - **原理**:按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。\r\n - **时间复杂度**:$O(d(n + k))$,其中 $d$ 是最大数字的位数,$k$ 是基数(如十进制中 $k = 10$)。 \r\n - **空间复杂度**:$O(n + k)$\r\n - **稳定性**:稳定\r\n - **适用场景**:数据位数固定且范围较大的整数排序。 ", + "数据结构与算法/快速幂算法(一).md": "要在C语言中实现快速幂算法,可以利用递归的方法或者迭代的方法来计算 *a**b*mod*c*。这里提供一个较为简单的实现,使用迭代的方法来避免栈溢出问题。\r\n\r\n\r\n\r\n以下是实现代码:\r\n\r\n\r\n\r\n```c\r\nc#include \r\n\r\n// 快速幂函数\r\nlong long quick_pow(int a, int b, int c) {\r\n long long result = 1;\r\n long long base = a % c; // 对c取模,避免基数过大\r\n\r\n while (b > 0) {\r\n if (b % 2 == 1) { // 如果b是奇数\r\n result = (result * base) % c;\r\n }\r\n base = (base * base) % c; // 基数平方\r\n b /= 2; // b除以2\r\n }\r\n\r\n return result;\r\n}\r\n\r\nint main() {\r\n int a, b, c;\r\n \r\n // 输入 a, b, c\r\n while (scanf(\"%d %d %d\", &a, &b, &c) != EOF) {\r\n printf(\"%lld\\n\", quick_pow(a, b, c));\r\n }\r\n \r\n return 0;\r\n}\r\nc\r\n```\r\n\r\n\r\n\r\n### 代码解释\r\n\r\n\r\n\r\n- **quick_pow 函数**:\r\n - 使用迭代的方法计算 *a**b*mod*c*。\r\n - `base` 是 *a*mod*c* ,用于在计算时减少数值范围。\r\n - 当 `b` 为奇数时,乘以当前的 `base` 并对 `c` 取模。\r\n - 将 `base` 平方并更新为 `(base * base) % c`。\r\n - `b` 每循环将除以2。\r\n- **main 函数**:\r\n - 使用 `scanf` 读取输入三元组(*a*,*b*,*c*)。\r\n - 使用 `printf` 输出结果。\r\n\r\n\r\n\r\n### 使用示例\r\n\r\n\r\n\r\n如果输入值为:\r\n\r\n\r\n\r\n```\r\n6 2 8\r\n```\r\n\r\n\r\n\r\n程序的输出将是:\r\n\r\n\r\n\r\n```\r\n4\r\n```\r\n\r\n\r\n\r\n### 注意事项\r\n\r\n\r\n\r\n- 输入的值需在限制范围内(1 < a, b, c < 2^30)。\r\n- 快速幂算法的时间复杂度为 *O*(log*b*),适合大范围的指数计算。\r\n\r\n\r\n\r\n这个程序应可在1秒内快速处理多组数据。", + "数据结构与算法/跳石头二分算法总结.md": "# 跳石头二分算法总结\r\n\r\n\r\n\r\n## 题目描述\r\n\r\n\r\n\r\n在给定的长度 `L` 和 `N` 个书的位置 `a` 中,要求在这些书的位置之间放置 `M` 个分隔符,使得每两个相邻分隔符之间的最小距离最大化。需要找出这个最大最小距离。\r\n\r\n\r\n\r\n## 输入格式\r\n\r\n\r\n\r\n1. 第一行:三个整数 `L`(长度)、`N`(书的数量)、`M`(分隔符的数量)。\r\n2. 第二行:`N` 个整数,表示书的位置。\r\n\r\n\r\n\r\n## 输出格式\r\n\r\n\r\n\r\n- 输出一个整数,表示最大化的最小距离。\r\n\r\n\r\n\r\n## 算法思路\r\n\r\n\r\n\r\n1. **初始化**:定义数组 `a` 存储书的位置,使用二分查找来确定最大最小距离。\r\n2. **检查函数 `check`**:判断在给定的最小距离 `x` 的情况下,能否放置 `M` 个分隔符。\r\n3. **二分查找**:在区间 `[0, L + 1]` 中进行二分查找,逐步逼近最大最小距离。\r\n\r\n\r\n\r\n## C语言实现\r\n\r\n\r\n\r\n以下是转换后的 C 语言代码:\r\n\r\n\r\n\r\n```c\r\nc#include \r\n\r\nconst int N1 = 1e5 + 5;\r\nint L, N, M;\r\nint a[N1];\r\n\r\nint check(int x) {\r\n int cnt = 0, now = 0;\r\n for (int i = 1; i <= N; ++i) {\r\n if (a[i] - now < x) {\r\n cnt++;\r\n } else {\r\n now = a[i];\r\n }\r\n }\r\n return cnt <= M;\r\n}\r\n\r\nint main() {\r\n scanf(\"%d %d %d\", &L, &N, &M);\r\n for (int i = 1; i <= N; ++i) {\r\n scanf(\"%d\", &a[i]);\r\n }\r\n int l = 0, r = L + 1, mid;\r\n while (l < r) {\r\n mid = (l + r) >> 1;\r\n if (check(mid)) {\r\n l = mid + 1;\r\n } else {\r\n r = mid;\r\n }\r\n }\r\n printf(\"%d\\n\", r - 1);\r\n return 0;\r\n}\r\nc\r\n```\r\n\r\n\r\n\r\n## 逻辑解析\r\n\r\n\r\n\r\n- **数组声明**:`int a[N1];` 用于存储书籍位置。\r\n- **检查函数**:`check(int x)` 用于判断当前最小距离 `x` 是否可行,计算需要的分隔符数量。\r\n- **二分查找**:\r\n - 初始化左右边界 `l` 和 `r`。\r\n - 通过 `mid` 值来逐步查找最大最小距离,更新边界 `l` 或 `r` 以收敛到解。\r\n- **结果输出**:最终输出最大最小距离 `r - 1`。\r\n\r\n\r\n\r\n## 总结\r\n\r\n\r\n\r\n该算法通过二分查找高效地确定在给定条件下的最大最小距离,适合大规模数据的处理,时间复杂度为 `O(N log L)`。", + "数据结构与算法/递增序列查询算法总结.md": "# 递增序列查询算法总结\r\n\r\n\r\n\r\n## 题目描述\r\n\r\n\r\n\r\n给定一个递增的正整数序列,针对不同的查询输出对应结果。查询类型包括查找最大下标、最小下标、数字范围计数、比某个数大的最小数字、比某个数小的最大数字等。\r\n\r\n\r\n\r\n## 输入格式\r\n\r\n\r\n\r\n1. 第一行:一个整数 `n`,代表序列的长度(下标从0开始到 `n-1`)。\r\n2. 第二行:`n` 个整数,代表序列对应位置上的数。\r\n3. 第三行:一个整数 `m`,代表查询次数。\r\n4. 接下来的`m`行,每行是以下五种类型之一:\r\n - `0 x`:查询数字 `x` 出现的最大下标,若不存在则输出 -1。\r\n - `1 x`:查询数字 `x` 出现的最小下标,若不存在则输出 -1。\r\n - `2 x y`:查询大于等于 `x` 且小于等于 `y` 的数字的个数(保证 `x <= y`)。\r\n - `3 x`:查询比 `x` 大且下标最小的数字的大小,若不存在则输出 -1。\r\n - `4 x`:查询比 `x` 小且下标最大的数字的大小,若不存在则输出 -1。\r\n\r\n\r\n\r\n## 输出格式\r\n\r\n\r\n\r\n输出每个查询的结果,每个结果占一行。\r\n\r\n\r\n\r\n## 算法思路\r\n\r\n\r\n\r\n1. **初始化**:读取输入的序列和查询数。\r\n2. **二分查找**:\r\n - **类型 0**:使用二分查找找到 `x` 的最大下标。\r\n - **类型 1**:使用二分查找找到 `x` 的最小下标。\r\n - **类型 2**:使用二分查找找到 `x` 和 `y` 的范围,计算范围内的元素个数。\r\n - **类型 3**:使用二分查找找到第一个比 `x` 大的元素。\r\n - **类型 4**:使用二分查找找到最后一个比 `x` 小的元素。\r\n3. **输出结果**:将所有查询结果依次输出。\r\n\r\n\r\n\r\n## 示例代码\r\n\r\n\r\n\r\n```c\r\nc#include \r\n\r\nint findMaxIndex(int a[], int n, int x) {\r\n int l = 0, r = n - 1, res = -1;\r\n while (l <= r) {\r\n int m = l + (r - l) / 2;\r\n if (a[m] == x) {\r\n res = m; \r\n l = m + 1; \r\n } else if (a[m] < x) {\r\n l = m + 1; \r\n } else {\r\n r = m - 1; \r\n }\r\n }\r\n return res;\r\n}\r\n\r\nint findMinIndex(int a[], int n, int x) {\r\n int l = 0, r = n - 1, res = -1;\r\n while (l <= r) {\r\n int m = l + (r - l) / 2;\r\n if (a[m] == x) {\r\n res = m; \r\n r = m - 1; \r\n } else if (a[m] < x) {\r\n l = m + 1; \r\n } else {\r\n r = m - 1; \r\n }\r\n }\r\n return res;\r\n}\r\n\r\nint countInRange(int a[], int n, int x, int y) {\r\n int leftIndex = findMinIndex(a, n, x);\r\n int rightIndex = findMaxIndex(a, n, y);\r\n if (leftIndex == -1 || rightIndex == -1) return 0;\r\n return rightIndex - leftIndex + 1;\r\n}\r\n\r\nint findFirstGreater(int a[], int n, int x) {\r\n int l = 0, r = n - 1, res = -1;\r\n while (l <= r) {\r\n int m = l + (r - l) / 2;\r\n if (a[m] > x) {\r\n res = a[m]; \r\n r = m - 1; \r\n } else {\r\n l = m + 1; \r\n }\r\n }\r\n return res;\r\n}\r\n\r\nint findLastSmaller(int a[], int n, int x) {\r\n int l = 0, r = n - 1, res = -1;\r\n while (l <= r) {\r\n int m = l + (r - l) / 2;\r\n if (a[m] < x) {\r\n res = a[m]; \r\n l = m + 1; \r\n } else {\r\n r = m - 1; \r\n }\r\n }\r\n return res;\r\n}\r\n\r\nint main() {\r\n int n, m;\r\n scanf(\"%d\", &n);\r\n int a[n];\r\n\r\n for (int i = 0; i < n; i++) {\r\n scanf(\"%d\", &a[i]);\r\n }\r\n\r\n scanf(\"%d\", &m);\r\n for (int i = 0; i < m; i++) {\r\n int type, x, y;\r\n scanf(\"%d\", &type);\r\n if (type == 0) {\r\n scanf(\"%d\", &x);\r\n printf(\"%d\\n\", findMaxIndex(a, n, x));\r\n } else if (type == 1) {\r\n scanf(\"%d\", &x);\r\n printf(\"%d\\n\", findMinIndex(a, n, x));\r\n } else if (type == 2) {\r\n scanf(\"%d %d\", &x, &y);\r\n printf(\"%d\\n\", countInRange(a, n, x, y));\r\n } else if (type == 3) {\r\n scanf(\"%d\", &x);\r\n printf(\"%d\\n\", findFirstGreater(a, n, x));\r\n } else if (type == 4) {\r\n scanf(\"%d\", &x);\r\n printf(\"%d\\n\", findLastSmaller(a, n, x));\r\n }\r\n }\r\n\r\n return 0;\r\n}\r\nc\r\n```\r\n\r\n\r\n\r\n## 示例\r\n\r\n\r\n\r\n### 输入\r\n\r\n\r\n\r\n```\r\n10\r\n1 1 1 3 4 5 5 5 5 8\r\n5\r\n0 5\r\n1 5\r\n2 1 5\r\n3 4\r\n4 8\r\n```\r\n\r\n\r\n\r\n### 输出\r\n\r\n\r\n\r\n```\r\n8\r\n5\r\n9\r\n5\r\n5\r\n```\r\n\r\n\r\n\r\n## 总结\r\n\r\n\r\n\r\n该算法使用二分查找处理多种查询类型,适合处理较大规模的输入数据,能够高效地返回查询结果。", + "杂项/10月23日大学英语笔记.md": "以下是你提到的英语词汇及其翻译和音标。我已经为其添加了音标,并将其排版成HTML和CSS格式。\r\n\r\n\r\n\r\n### 英语词汇及翻译\r\n\r\n\r\n\r\n| 英文词汇 | 翻译 | 音标 |\r\n| :------------------------------------------------ | :----------------------- | :------------------------------------------------- |\r\n| hands | 手 | /hændz/ |\r\n| butterflies in the stomach | 肚子里的蝴蝶 | /ˈbʌtərflaɪz ɪn ðə ˈstʌmək/ |\r\n| muscle tension | 肌肉紧张 | /ˈmʌsl ˈtɛnʃən/ |\r\n| credit | 学分 / 信用 | /ˈkrɛdɪt/ |\r\n| major | 主修 / 专业 | /ˈmeɪdʒər/ |\r\n| major in | 主修 | /ˈmeɪdʒər ɪn/ |\r\n| dropout | 辍学 | /ˈdrɔpˌaʊt/ |\r\n| trigger | 诱因 / 扳机 | /ˈtrɪɡər/ |\r\n| resilience | 弹性 | /rɪˈzɪljəns/ |\r\n| cyberlove | 网恋 | /ˈsaɪbərləv/ |\r\n| long-distance relationship | 异地恋 | /lɔŋ ˈdɪstəns rɪˌleɪʃənˈʃɪp/ |\r\n| date | 日期 / 约会 | /deɪt/ |\r\n| lovesick | 恋爱中的病 | /ˈlʌvˌsɪk/ |\r\n| zodiac | 星座 | /ˈzoʊ.dɪ.æk/ |\r\n| aquaman | 水行侠 | /ˈækwəˌmæn/ |\r\n| aquarium | 水族馆 | /əˈkwɛərɪəm/ |\r\n| pilgrim | 朝圣者 | /ˈpɪlɡrɪm/ |\r\n| soul | 灵魂 | /soʊl/ |\r\n| bar | 酒吧 | /bɑr/ |\r\n| soap bar | 香皂 | /soʊp bɑr/ |\r\n| behind the bars | 在监狱里 | /bɪˈhaɪnd ðə bɑrz/ |\r\n| enjoy each other's company | 享受彼此的陪伴 | /ɪnˈdʒɔɪ iʧ ˈʌðərz ˈkʌmpəni/ |\r\n| crush | 暗恋 | /krʌʃ/ |\r\n| have a crush on | 对某人有好感 | /hæv ə krʌʃ ɑn/ |\r\n| idol | 偶像 | /ˈaɪdəl/ |\r\n| icon | 图标 / 偶像 | /ˈaɪˌkɒn/ |\r\n| ideal | 理想 | /aɪˈdɪəl/ |\r\n| idea | 主意 | /aɪˈdɪə/ |\r\n| idiot | 傻瓜 | /ˈɪdiət/ |\r\n| marketing campaign | 营销活动 | /ˈmɑrkɪtɪŋ kæmˈpeɪn/ |\r\n| being in love implies that you can fall out of it | 恋爱意味着你可能会失去爱 | /ˈbiːɪŋ ɪn lʌv ɪmˈplaɪz ðæt juː kæn fɔl aʊt ʌv ɪt/ |\r\n| -wise | 方面的 | /waɪz/ |\r\n| family-wise | 从家庭的角度 | /ˈfæmɪli waɪz/ |\r\n| better off | 过得更好 | /ˈbɛtər ɔf/ |\r\n| big old kiss | 大大的吻 | /bɪɡ oʊld kɪs/ |\r\n| vulnerable | 脆弱的 | /ˈvʌlnərəbəl/ |\r\n\r\n\r\n\r\n### HTML/CSS 排版美化\r\n\r\n\r\n\r\n```html\r\nhtml\r\n\r\n\r\n \r\n \r\n 英语词汇及翻译\r\n \r\n\r\n\r\n

英语词汇及翻译

\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
英文词汇翻译音标
hands/hændz/
butterflies in the stomach肚子里的蝴蝶/ˈbʌtərflaɪz ɪn ðə ˈstʌmək/
muscle tension肌肉紧张/ˈmʌsl ˈtɛnʃən/
\r\n\r\n\r\nhtml\r\n```\r\n\r\n\r\n\r\n你可以将上述HTML代码复制到文本编辑器中,然后另存为`.html`文件,以在浏览器中打开并查看效果。如果有其他需求或需要进一步的帮助,请告知我!", + "杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md": "```c++\r\n#include \r\n#include \r\nusing namespace std;\r\n\r\nint countSubstrings(const string& str, const string& sub) {\r\n int count = 0;\r\n size_t pos = 0;\r\n\r\n // 循环直到找不到子字符串\r\n while ((pos = str.find(sub, pos)) != string::npos) {\r\n count++; // 找到一个子字符串,计数器加1\r\n pos += sub.length(); // 更新位置,跳过已找到的子字符串\r\n }\r\n\r\n return count;\r\n}\r\n\r\nint main() {\r\n string str = \"ababcabcabcab\";\r\n string sub = \"abc\";\r\n \r\n int result = countSubstrings(str, sub);\r\n cout << \"子字符串 \\\"\" << sub << \"\\\" 在字符串 \\\"\" << str << \"\\\" 中出现的次数是: \" << result << endl;\r\n\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n### TMD一生之耻!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", + "杂项/Markdown格式大全.md": "# MarkDown书写规范\n\n写文档好帮手,轻量级标记语言 Markdown\n\n# 概述\n\n## 起源\n\nMarkdown是[Daring Fireball](http://daringfireball.net/projects/markdown/syntax)的作者John Gruber发明,身为Blogger,可能他也觉得传统的HTML有些复杂吧,退一步来讲,若是一个毫无计算机基础的Blogger,根本也没必要去掌握那些复杂的标签语言知识。\n\n## 宗旨\n\nMarkdown 的目标是实现「易读易写」,成为一种适用于网络的书写语言。\n\n可读性,无论如何,都是最重要的。一份使用 Markdown 格式撰写的文件应该可以直接以纯文本发布,并且看起来不会像是由许多标签或是格式指令所构成。Markdown 语法受到一些既有 text-to-HTML 格式的影响,包括 Setext、atx、Textile、reStructuredText、Grutatext 和 EtText,而最大灵感来源其实是纯文本电子邮件的格式。\n\n总之, Markdown 的语法全由一些符号所组成,这些符号经过精挑细选,其作用一目了然。比如:在文字两旁加上星号,看起来就像*强调*。Markdown 的列表看起来,嗯,就是列表。Markdown 的区块引用看起来就真的像是引用一段文字,就像你曾在电子邮件中见过的那样。\n\n\n# 全局规范\n\nMarkDown 文件均使用```.md```作为后缀 *(小写字母)*\n\n普通文本换行,使用行末尾```2空格```触发\n\n\n## 发展\n\n越来越多的软件和服务支持Markdown语法,应该说,Mac上大多数的写作软件都支持它。在线工具同样有很多,如果你的博客基于Wordpress或是blogger,它同样支持发布。\n\n不仅仅是写博客,一切文章都可以用Markdown语法来写,比如说你想将一个标题加大字体,只需要在相应文字前面加上一个#或是在它的下一行加上一些等号即可,还有比这更简单的调整格式方式吗?\n\n\n# 语法参见\n\n[官方语法说明](http://daringfireball.net/projects/markdown/syntax)\n\n# 示例\n\n---\n\n## 标题\n\n# 一级标题\n\n## 二级标题\n\n### 三级标题\n\n#### 四级标题\n\n##### 五级标题\n\n###### 六级标题\n\n## 强调\n\n- **粗体**\n\n- _斜体_\n\n## 引用\n\n上面的横线用三个-表示\n\n> 区块引用\n\n## 列表\n\n* red\n* green\n* blue\n\n+ red\n+ green\n+ blue\n\n- red\n- green\n- blue\n\n\n1. red\n2. green\n3. blue\n\n\n* 一个列表包含一个区块\n> 区块内容\n> 更多内容\n\n## 代码\n\n代码的插入方式 `printf('\\n');`\n\n```\nfunction method()\n{\n alert(\"javascript\");\n}\n```\n\n```\nclass Test{\n public static void main(String argc[]){\n System.out.println(\"java\");\n }\n}\n```\n\n```\nclass Test{\n public static void main()\n {\n Console.WriteLine(\"C#\");\n }\n}\n```\n\n## 链接\n\n行内连接 [GitHub](https://github.com/) 的链接\n\n## 图片\n\n![shiyanlou logo](https://static.shiyanlou.com/img/logo_03.png)\n", + "杂项/markdown格式(没什么用).md": "https://storage.googleapis.com/docscloudstorage/2022.3/UnityDocumentation.zip\r\n\r\nChatGPT响应: Markdown中的一些常用标识符包括:\r\n\r\n1. **标题**:使用`#`表示不同级别的标题\r\n ```markdown\r\n # 一级标题\r\n ## 二级标题\r\n ### 三级标题\r\n ```\r\n\r\n2. **粗体**:使用`**`或`__`包围文本\r\n ```markdown\r\n **粗体文本** 或 __粗体文本__\r\n ```\r\n\r\n3. **斜体**:使用`*`或`_`包围文本\r\n ```markdown\r\n *斜体文本* 或 _斜体文本_\r\n ```\r\n\r\n4. **无序列表**:使用`-`、`*`或`+`\r\n ```markdown\r\n - 项目1\r\n * 项目2\r\n + 项目3\r\n ```\r\n\r\n5. **有序列表**:使用数字加点\r\n ```markdown\r\n 1. 第一项\r\n 2. 第二项\r\n ```\r\n\r\n6. **链接**:使用`[链接文本](URL)`\r\n ```markdown\r\n [这是一个链接](https://example.com)\r\n ```\r\n\r\n7. **图片**:使用`![图片描述](图片URL)`\r\n ```markdown\r\n ![示例图片](https://example.com/image.png)\r\n ```\r\n\r\n8. **代码块**:使用反引号`` ` ``\r\n ```markdown\r\n `行内代码`\r\n ```\r\n\r\n 或使用三个反引号表示多行代码\r\n ```markdown\r\n ```\r\n 多行代码\r\n ```\r\n ```\r\n\r\n9. **引用**:使用`>`\r\n ```markdown\r\n > 这是一个引用\r\n ```\r\n\r\n10. **水平线**:使用三个或以上的`-`、`*`或`_`\r\n ```markdown\r\n ---\r\n ```\r\n\r\n", + "杂项/PTA万能代码.md": "```c++\r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nusing namespace std;\r\n\r\nint main() {\r\n // 使用当前时间的时间戳作为种子\r\n unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();\r\n \r\n // 创建一个基于该种子的随机数生成器\r\n std::default_random_engine generator(seed);\r\n \r\n // 创建一个均匀分布的随机数生成器(在 1 到 100 之间)\r\n std::uniform_int_distribution distribution(0, 10);\r\n \r\n\t//这里填写你需要输入的 \r\n string str1,str2;\r\n cin>>str1>>str2;\r\n \r\n\t// 生成并打印随机数\r\n std::cout <\r\n#include \r\n\r\ntypedef struct {\r\n char word[10 + 1]; \r\n int index; \r\n} Word;\r\n\r\nint main() {\r\n Word words[20];\r\n int count = 0; //单词数量\r\n \r\n\r\n while (1) {\r\n char word[10 + 1];\r\n fgets(word, sizeof(word), stdin);\r\n \r\n\r\n if (word[0] == '#') {\r\n break;\r\n }\r\n\r\n\r\n word[strcspn(word, \"\\n\")] = '\\0';\r\n\r\n\r\n strcpy(words[count].word, word);\r\n words[count].index = count;\r\n count++;\r\n }\r\n\r\n //标准冒泡排序\r\n for (int i = 0; i < count - 1; i++) {\r\n for (int j = 0; j < count-1-i; j++) {\r\n if (strlen(words[j].word) > strlen(words[j+1].word)) {\r\n // 交换单词\r\n Word temp = words[j];\r\n words[j] = words[j+1];\r\n words[j+1] = temp;\r\n }\r\n }\r\n }\r\n\r\n for (int i = 0; i < count; i++) {\r\n printf(\"%s \", words[i].word);\r\n }\r\n printf(\"\\n\");\r\n\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n", + "杂项/PTA好题-计算众数.md": "**7-6 求整数序列中出现次数最多的数**\r\n\r\n分数 20\r\n\r\n作者 张彤彧\r\n\r\n单位 浙江大学\r\n\r\n本题要求统计一个整型序列中出现次数最多的整数及其出现次数。\r\n\r\n### 输入格式:\r\n\r\n输入在一行中给出序列中整数个数N(0\r\n\r\nint main() {\r\n int N;\r\n scanf(\"%d\", &N);\r\n int arr[N];\r\n for(int i = 0; i < N; i++) {\r\n scanf(\"%d\", &arr[i]);\r\n }\r\n\r\n int max_count = 0;\r\n int most_freq_num = arr[0];\r\n for(int i = 0; i < N; i++) {\r\n int count = 1;\r\n for(int j = i+1; j < N; j++) {\r\n if(arr[j] == arr[i]) {\r\n count++;\r\n }\r\n }\r\n if(count > max_count) {\r\n max_count = count;\r\n most_freq_num = arr[i];\r\n }\r\n }\r\n\r\n printf(\"%d %d\", most_freq_num, max_count);\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n", + "杂项/古诗.md": "知我者,谓我心忧;不知我者,谓我何求\n路漫漫其修远兮,吾将上下而求索\n夕阳西下,断肠人在天涯\n兴,百姓苦;亡,百姓苦\n封侯非我意,但愿海波平\n我自横刀向天笑,去留肝胆两昆仑\n海上生明月,天涯共此时\n红豆生南国,春来发几枝。愿君多采撷,此物最相思\n气蒸云梦泽,波撼岳阳城\n黄沙百战穿金甲,不破楼兰终不还\n天生我材必有用,千金散尽还复来\n长风破浪会有时,直挂云帆济沧海\n安能摧眉折腰事权贵,使我不得开心颜\n会当凌绝顶,一览众山小\n国破山河在,城春草木深。感时花溅泪,恨别鸟惊心\n烽火连三月,家书抵万金\n日出江花红胜火,春来江水绿如蓝。能不忆江南\n同是天涯沦落人,相逢何必曾相识\n春蚕到死丝方尽,蜡炬成灰泪始干\n身无彩凤双飞翼,心有灵犀一点通\n山有木兮木有枝,心悦君兮君不知\n生年不满百,常怀千岁忧\n人生如逆旅,我亦是行人\n桃李春风一杯酒,江湖夜雨十年灯\n劝君莫惜金缕衣,劝君惜取少年时\n\n\n但愿人长久,千里共婵娟\n抽刀断水水更流,举杯消愁愁更愁\n孤帆远影碧空尽,唯见长江天际流\n两岸猿声啼不住,轻舟已过万重山\n疏影横斜水清浅,暗香浮动月黄昏\n晚来天欲雪,能饮一杯无\n山重水复疑无路,柳暗花明又一村\n旧时王谢堂前燕,飞入寻常百姓家\n葡萄美酒夜光杯,欲饮琵琶马上催\n两岸青山相对出,孤帆一片日边来\n落霞与孤鹜齐飞,秋水共长天一色\n杨柳青青江水平,闻郎江上踏歌声\n近乡情更怯,不敢问来人\n洛阳亲友如相问,一片冰心在玉壶\n莫愁前路无知己,天下谁人不识君\n七八个星天外,两三点雨山前\n一年好景君须记,最是橙黄橘绿时\n今夜月明人尽望,不知秋思落谁家\n劝君更尽一杯酒,西出阳关无故人\n云想衣裳花想容,春风拂槛露华浓\n此情可待成追忆,只是当时已惘然\n问君能有几多愁,恰似一江春水向东流\n小荷才露尖尖角,早有蜻蜓立上头\n两个黄鹂鸣翠柳,一行白鹭上青天\n两岸荔枝红,万家烟雨中\n独在异乡为异客,每逢佳节倍思亲\n无边落木萧萧下,不尽长江滚滚来\n千山鸟飞绝,万径人踪灭\n相见时难别亦难,东风无力百花残\n人间四月芳菲尽,山寺桃花始盛开\n春风得意马蹄疾,一日看尽长安花\n竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生\n我花开后百花杀,秋草萋萋鹦鹉洲", + "杂项/文本颜色测试.md": "我是逐浪圆体\r\n我是逐浪花体\r\n我是逐浪像素字\r\n我是逐浪立楷\r\n我是红色\r\n我是绿色\r\n我是黄色\r\n我是蓝色\r\n我是紫色\r\n我是浅灰色\r\n我是尺寸\r\n我是尺寸\r\n我是逐浪立楷,绿色,尺寸为5\r\n\r\n
背景色yellow
\r\n\r\n\r\n水果名称| 价格 | 数量 \r\n-|-|-\r\n香蕉 | $1 | 5 |\r\n苹果 | $1 | 6 |\r\n草莓 | $1 | 7 |\r\n\r\nname | 111 | 222 | 333 | 444\r\n- | :-: | :-: | :-: | -:\r\naaa | bbb | ccc | ddd | eee| \r\nfff | ggg| hhh | iii | 000|\r\n\r\nname | 111 | 222 | 333 | 444\r\n:-- | :-- | :-- | :-- | :--\r\naaa | bbb | ccc | ddd | eee\r\nfff | ggg| hhh | iii | 000\r\n\r\n颜色名 | 十六进制颜色值 | rgb颜色 \r\n-|-|-\r\n黑色(black) | 000000 | \trgb(0, 0, 0) |\r\n蓝色(blue) | 0000FF | rgb(0, 0, 255) |\r\n灰色(grey) | 808080 | rgb(128, 128, 128) |\r\n绿色(green) | 008000 | rgb(0, 128, 0) |\r\n橙色(orange) | FFA500 | rgb(255, 165, 0) |\r\n红色(red) | FF0000 | rgb(255, 0, 0) |\r\n黄色(yellow) | FFFF00 | rgb(255, 255, 0) |", + "杂项/计算机刷题网站.md": "#### 计算机刷题网站\r\n\r\n1. 洛谷 https://www.luogu.com.cn/\r\n2. 牛客网 https://www.nowcoder.com/\r\n3. leetcode https://leetcode.cn/\r\n4. acm实验室 http://acm.mangata.ltd/\r\n5. PTA https://pintia.cn/home", + "游戏引擎/Godot/BBCode 标签学习.md": "\n以下是截至 Godot 最新稳定版(截至 Jul 2025)的 `RichTextLabel` 节点支持的所有 BBCode 标签,非常详尽:\n\n---\n\n## 🔧 基本格式标签\n\n这些都是官方文档中明确支持的基本标签:([Godot Engine documentation](https://docs.godotengine.org/en/3.5/tutorials/ui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel — Godot Engine (3.5) documentation in ...\"))\n\n- **`[b]{text}[/b]`**:**粗体**\n \n- **`[i]{text}[/i]`**:_斜体_\n \n- **`[u]{text}[/u]`**:下划线\n \n- **`[s]{text}[/s]`**:删除线\n \n- **`[code]{text}[/code]`**:等宽字体,保持空格格式\n \n- **`[center]{text}[/center]`**:水平居中\n \n- **`[right]{text}[/right]`**:右对齐\n \n- **`[fill]{text}[/fill]`**:填满整个控件宽度\n \n- **`[indent]{text}[/indent]`**:增加缩进\n \n- **`[url]{url_or_meta}[/url]`**:产生可点击的链接(需使用 `meta_clicked` 信号处理)\n \n- **`[url=]{text}[/url]`**:显示自定义文本的链接\n \n- **`[img]{path}[/img]`**:插入图片\n \n- **`[img=]{path}[/img]`**:指定宽度,等比缩放\n \n- **`[img=x]{path}[/img]`**:指定宽高\n \n- **`[font=]{text}[/font]`**:使用特定字体资源\n \n- **`[color=]{text}[/color]`**:设置文本颜色,其中 `` 支持常见颜色名如 aqua、black、blue、red 等,亦支持 `#RRGGBB` 或 `#AARRGGBB` 格式([Godot Engine documentation](https://docs.godotengine.org/en/3.5/tutorials/ui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel — Godot Engine (3.5) documentation in ...\"), [Godot Engine documentation](https://docs.godotengine.org/en/3.1/tutorials/gui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel - Godot Docs\"), [Godot Engine documentation](https://docs.godotengine.org/en/3.0/tutorials/gui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel - Godot Docs\"))\n \n\n---\n\n## 🧩 表格支持\n\nGodot 支持表格结构,但 **不支持** HTML 风格的 `` ``,也 **不支持** BBCode `[list]` 等列表标签([Stack Overflow](https://stackoverflow.com/questions/72568676/godot-richtextlabel-bbcode-table-and-list-support?utm_source=chatgpt.com \"Godot RichTextLabel BBCODE Table and List support\")):\n\n- **`[table=]{cells}[/table]`**:设定列数,所有内容以 `[cell]...[/cell]` 分隔\n \n- **`[cell]{content}[/cell]`**:单元格内容\n \n\n示例用法:\n\n```\n[table=2]\n[cell]你好[/cell]\n[cell][img=16]res://icon.png[/img][/cell]\n[/table]\n```\n\n---\n\n## ✨ 动画/效果标签\n\nGodot 自带几种内置动画效果 BBCode:([Godot Engine documentation](https://docs.godotengine.org/en/3.2/tutorials/gui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel - Godot Docs\"), [Godot Engine documentation](https://docs.godotengine.org/en/3.1/tutorials/gui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel - Godot Docs\"))\n\n- **`[wave amp=50 freq=2]{text}[/wave]`**:波浪式上下动画,`amp` 控制振幅,`freq` 控制频率\n \n- **`[fade start=4 length=14]{text}[/fade]`**:渐隐效果,从指定字符开始,长度控制影响范围\n \n- **`[rainbow freq=0.2 sat=10 val=20]{text}[/rainbow]`**:彩虹色循环动画,`freq` 控制速度,`sat` 饱和度,`val` 亮度\n \n\n此外,可通过继承 `RichTextEffect` 自定义动画标签([Godot Engine documentation](https://docs.godotengine.org/en/3.2/tutorials/gui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel - Godot Docs\"))。\n\n---\n\n## 💡 其他标签\n\n- **`[lb]` 与 `[rb]`**:左/右转义方括号,用于在纯文本中显示 `[` `]` 而不被解析([Godot Engine documentation](https://docs.godotengine.org/en/latest/tutorials/ui/bbcode_in_richtextlabel.html?utm_source=chatgpt.com \"BBCode in RichTextLabel - Godot Docs\"))。\n \n- **`[fill]`、`[indent]`** 已在基本标签中列出。\n \n\n---\n\n## ⚙️ 使用建议总结\n\n- 若需嵌套标签,**不要交叉**,如 `[b]bold[i]bold italic[/i][/b]` 是合法,但 `[b]bold[i]bold italic[/b]italic[/i]` 会报错([Godot Engine documentation](https://docs.godotengine.org/en/stable/classes/class_richtextlabel.html?utm_source=chatgpt.com \"RichTextLabel — Godot Engine (stable) documentation in English\"))。\n \n- 链接需配合脚本信号进行跳转处理。\n \n- 插入图片时,你可以显式指定尺寸保持布局需求。\n \n- 基本已覆盖所有官方支持的 BBCode 权能。\n \n\n---\n\n## ✅ 完整TIP参考\n\n|功能分类|支持标签|参数说明|\n|---|---|---|\n|文字样式|`[b,i,u,s,code]`|常见文本格式|\n|对齐、缩进|`[center,right,fill,indent]`|控制布局母体|\n|链接|`[url]`, `[url=..]`|需 signal 处理|\n|图片|`[img]`, 带尺寸控制|支持 `` 或 `x`|\n|字体颜色|`[font=]`, `[color=]`|支持路径 & named/hex 颜色|\n|表格|`[table=cols]...[/table]`, `[cell]`|创建简易表格|\n|动画效果|`[wave]`, `[fade]`, `[rainbow]`|`amp/freq/sat/val`等自定义参数|\n\n---\n\n", + "游戏引擎/Godot/DisplayServer简单总结.md": "# DisplayServer API 参考文档\n\n \n\n## 类简介\n\n \n\n**继承**:Object\n\n \n\nDisplayServer 是用于低阶窗口管理的服务器接口。所有与窗口管理相关的内容都由 DisplayServer(显示服务器)处理。\n\n \n\n> **无头模式**:如果使用 `--headless` 命令行参数启动引擎,就会禁用所有渲染和窗口管理功能,此时 DisplayServer 的大多数函数都会返回虚设值。\n\n \n\n---\n\n \n\n## 方法列表\n\n \n\n### 🔔 系统交互\n\n \n\n#### `void beep()`\n\n发出系统提示音。\n\n \n\n#### `void enable_for_stealing_focus(process_id: int)`\n\n允许指定进程获取焦点。\n\n \n\n#### `void force_process_and_drop_events()`\n\n强制处理并丢弃所有事件。\n\n \n\n---\n\n \n\n### 📋 剪贴板操作\n\n \n\n#### `String clipboard_get()`\n\n获取剪贴板文本内容。\n\n \n\n#### `Image clipboard_get_image()`\n\n获取剪贴板图像内容。\n\n \n\n#### `String clipboard_get_primary()`\n\n获取主剪贴板文本内容(仅限 Linux)。\n\n \n\n#### `bool clipboard_has()`\n\n检查剪贴板是否有内容。\n\n \n\n#### `bool clipboard_has_image()`\n\n检查剪贴板是否有图像。\n\n \n\n#### `void clipboard_set(clipboard: String)`\n\n设置剪贴板文本内容。\n\n \n\n#### `void clipboard_set_primary(clipboard_primary: String)`\n\n设置主剪贴板文本内容(仅限 Linux)。\n\n \n\n---\n\n \n\n### 🖱️ 鼠标和光标\n\n \n\n#### `CursorShape cursor_get_shape()`\n\n获取当前光标形状。\n\n \n\n#### `void cursor_set_custom_image(cursor: Resource, shape: CursorShape = 0, hotspot: Vector2 = Vector2(0, 0))`\n\n设置自定义光标图像。\n\n \n\n#### `void cursor_set_shape(shape: CursorShape)`\n\n设置光标形状。\n\n \n\n#### `BitField[MouseButtonMask] mouse_get_button_state()`\n\n获取鼠标按键状态。\n\n \n\n#### `MouseMode mouse_get_mode()`\n\n获取鼠标模式。\n\n \n\n#### `Vector2i mouse_get_position()`\n\n获取鼠标位置。\n\n \n\n#### `void mouse_set_mode(mouse_mode: MouseMode)`\n\n设置鼠标模式。\n\n \n\n#### `void warp_mouse(position: Vector2i)`\n\n将鼠标光标移动到指定位置。\n\n \n\n---\n\n \n\n### 💬 对话框\n\n \n\n#### `Error dialog_input_text(title: String, description: String, existing_text: String, callback: Callable)`\n\n显示文本输入对话框。\n\n \n\n#### `Error dialog_show(title: String, description: String, buttons: PackedStringArray, callback: Callable)`\n\n显示系统对话框。\n\n \n\n#### `Error file_dialog_show(title: String, current_directory: String, filename: String, show_hidden: bool, mode: FileDialogMode, filters: PackedStringArray, callback: Callable)`\n\n显示文件选择对话框。\n\n \n\n#### `Error file_dialog_with_options_show(title: String, current_directory: String, root: String, filename: String, show_hidden: bool, mode: FileDialogMode, filters: PackedStringArray, options: Array[Dictionary], callback: Callable)`\n\n显示带扩展选项的文件选择对话框。\n\n \n\n---\n\n \n\n### 🎨 主题和颜色\n\n \n\n#### `Color get_accent_color()`\n\n获取系统强调色。\n\n \n\n#### `Color get_base_color()`\n\n获取系统基础色。\n\n \n\n#### `bool is_dark_mode()`\n\n检查系统是否为深色模式。\n\n \n\n#### `bool is_dark_mode_supported()`\n\n检查系统是否支持深色模式。\n\n \n\n#### `void set_system_theme_change_callback(callable: Callable)`\n\n设置系统主题变化时的回调。\n\n \n\n---\n\n \n\n### 📱 显示和屏幕\n\n \n\n#### `Array[Rect2] get_display_cutouts()`\n\n获取显示器刘海信息。\n\n \n\n#### `Rect2i get_display_safe_area()`\n\n获取显示器安全区域。\n\n \n\n#### `int get_keyboard_focus_screen()`\n\n获取键盘焦点所在屏幕。\n\n \n\n#### `String get_name()`\n\n获取显示服务器名称。\n\n \n\n#### `int get_primary_screen()`\n\n获取主屏幕索引。\n\n \n\n#### `int get_screen_count()`\n\n获取屏幕数量。\n\n \n\n#### `int get_screen_from_rect(rect: Rect2)`\n\n根据矩形位置获取屏幕索引。\n\n \n\n#### `bool get_swap_cancel_ok()`\n\n获取是否交换确定取消按钮。\n\n \n\n#### `int get_window_at_screen_position(position: Vector2i)`\n\n获取指定屏幕位置的窗口ID。\n\n \n\n#### `PackedInt32Array get_window_list()`\n\n获取所有窗口ID列表。\n\n \n\n---\n\n \n\n### 🖥️ 屏幕操作\n\n \n\n#### `int screen_get_dpi(screen: int = -1)`\n\n获取屏幕DPI。\n\n \n\n#### `Image screen_get_image(screen: int = -1)`\n\n获取屏幕截图。\n\n \n\n#### `Image screen_get_image_rect(rect: Rect2i)`\n\n获取屏幕指定区域截图。\n\n \n\n#### `float screen_get_max_scale()`\n\n获取所有屏幕的最大缩放系数。\n\n \n\n#### `ScreenOrientation screen_get_orientation(screen: int = -1)`\n\n获取屏幕朝向。\n\n \n\n#### `Color screen_get_pixel(position: Vector2i)`\n\n获取指定位置的像素颜色。\n\n \n\n#### `Vector2i screen_get_position(screen: int = -1)`\n\n获取屏幕位置。\n\n \n\n#### `float screen_get_refresh_rate(screen: int = -1)`\n\n获取屏幕刷新率。\n\n \n\n#### `float screen_get_scale(screen: int = -1)`\n\n获取屏幕缩放系数。\n\n \n\n#### `Vector2i screen_get_size(screen: int = -1)`\n\n获取屏幕大小。\n\n \n\n#### `Rect2i screen_get_usable_rect(screen: int = -1)`\n\n获取屏幕可用区域。\n\n \n\n#### `bool screen_is_kept_on()`\n\n检查屏幕是否保持开启。\n\n \n\n#### `void screen_set_keep_on(enable: bool)`\n\n设置屏幕保持开启。\n\n \n\n#### `void screen_set_orientation(orientation: ScreenOrientation, screen: int = -1)`\n\n设置屏幕朝向。\n\n \n\n---\n\n \n\n### 🖼️ 图标设置\n\n \n\n#### `void set_icon(image: Image)`\n\n设置窗口图标。\n\n \n\n#### `void set_native_icon(filename: String)`\n\n使用原生格式设置窗口图标。\n\n \n\n---\n\n \n\n### 💾 输出管理\n\n \n\n#### `bool has_additional_outputs()`\n\n检查是否有额外输出设备。\n\n \n\n#### `void register_additional_output(object: Object)`\n\n注册额外输出设备。\n\n \n\n#### `void unregister_additional_output(object: Object)`\n\n取消注册额外输出设备。\n\n \n\n---\n\n \n\n### ⚡ 功能检测\n\n \n\n#### `bool has_feature(feature: Feature)`\n\n检查是否支持指定功能。\n\n \n\n#### `bool has_hardware_keyboard()`\n\n检查是否有硬件键盘。\n\n \n\n#### `bool is_touchscreen_available()`\n\n检查是否支持触屏。\n\n \n\n#### `bool is_window_transparency_available()`\n\n检查是否支持窗口透明。\n\n \n\n---\n\n \n\n### ⌨️ 键盘\n\n \n\n#### `int keyboard_get_current_layout()`\n\n获取当前键盘布局。\n\n \n\n#### `Key keyboard_get_keycode_from_physical(keycode: Key)`\n\n从物理按键获取键码。\n\n \n\n#### `Key keyboard_get_label_from_physical(keycode: Key)`\n\n从物理按键获取标签。\n\n \n\n#### `int keyboard_get_layout_count()`\n\n获取键盘布局数量。\n\n \n\n#### `String keyboard_get_layout_language(index: int)`\n\n获取键盘布局语言。\n\n \n\n#### `String keyboard_get_layout_name(index: int)`\n\n获取键盘布局名称。\n\n \n\n#### `void keyboard_set_current_layout(index: int)`\n\n设置当前键盘布局。\n\n \n\n---\n\n \n\n### 📝 输入法\n\n#### `Vector2i ime_get_selection()`\n\n获取输入法选中范围。\n\n \n#### `String ime_get_text()`\n\n获取输入法文本。\n\n\n---\n\n \n\n### 🎯 状态指示器\n\n#### `int create_status_indicator(icon: Texture2D, tooltip: String, callback: Callable)`\n\n创建状态指示器。\n\n \n#### `void delete_status_indicator(id: int)`\n\n删除状态指示器。\n\n \n#### `Rect2 status_indicator_get_rect(id: int)`\n\n获取状态指示器位置。\n\n \n\n#### `void status_indicator_set_callback(id: int, callback: Callable)`\n\n设置状态指示器回调。\n\n \n\n#### `void status_indicator_set_icon(id: int, icon: Texture2D)`\n\n设置状态指示器图标。\n\n \n\n#### `void status_indicator_set_menu(id: int, menu_rid: RID)`\n\n设置状态指示器菜单。\n\n \n\n#### `void status_indicator_set_tooltip(id: int, tooltip: String)`\n\n设置状态指示器提示文本。\n\n \n\n---\n\n \n\n### 📱 数位板\n\n \n\n#### `String tablet_get_current_driver()`\n\n获取当前数位板驱动。\n\n \n\n#### `int tablet_get_driver_count()`\n\n获取数位板驱动数量。\n\n \n\n#### `String tablet_get_driver_name(idx: int)`\n\n获取数位板驱动名称。\n\n \n\n#### `void tablet_set_current_driver(name: String)`\n\n设置数位板驱动。\n\n \n\n---\n\n \n\n### 🗣️ 文本转语音\n\n \n\n#### `Array[Dictionary] tts_get_voices()`\n\n获取语音列表。\n\n \n\n#### `PackedStringArray tts_get_voices_for_language(language: String)`\n\n获取指定语言的语音列表。\n\n \n\n#### `bool tts_is_paused()`\n\n检查是否暂停。\n\n \n\n#### `bool tts_is_speaking()`\n\n检查是否正在朗读。\n\n \n\n#### `void tts_pause()`\n\n暂停朗读。\n\n \n\n#### `void tts_resume()`\n\n恢复朗读。\n\n \n\n#### `void tts_set_utterance_callback(event: TTSUtteranceEvent, callable: Callable)`\n\n设置朗读事件回调。\n\n \n\n#### `void tts_speak(text: String, voice: String, volume: int = 50, pitch: float = 1.0, rate: float = 1.0, utterance_id: int = 0, interrupt: bool = false)`\n\n开始朗读文本。\n\n \n\n#### `void tts_stop()`\n\n停止朗读。\n\n \n\n---\n\n \n\n### ⌨️ 虚拟键盘\n\n \n\n#### `int virtual_keyboard_get_height()`\n\n获取虚拟键盘高度。\n\n \n\n#### `void virtual_keyboard_hide()`\n\n隐藏虚拟键盘。\n\n \n\n#### `void virtual_keyboard_show(existing_text: String, position: Rect2 = Rect2(0, 0, 0, 0), type: VirtualKeyboardType = 0, max_length: int = -1, cursor_start: int = -1, cursor_end: int = -1)`\n\n显示虚拟键盘。\n\n \n\n---\n\n \n\n### 🪟 窗口管理\n\n \n\n#### `bool window_can_draw(window_id: int = 0)`\n\n检查窗口是否可绘制。\n\n \n\n#### `int window_get_active_popup()`\n\n获取活动弹出窗口ID。\n\n \n\n#### `int window_get_attached_instance_id(window_id: int = 0)`\n\n获取窗口附加的实例ID。\n\n \n\n#### `int window_get_current_screen(window_id: int = 0)`\n\n获取窗口所在屏幕。\n\n \n\n#### `bool window_get_flag(flag: WindowFlags, window_id: int = 0)`\n\n获取窗口标志。\n\n \n\n#### `Vector2i window_get_max_size(window_id: int = 0)`\n\n获取窗口最大尺寸。\n\n \n\n#### `Vector2i window_get_min_size(window_id: int = 0)`\n\n获取窗口最小尺寸。\n\n \n\n#### `WindowMode window_get_mode(window_id: int = 0)`\n\n获取窗口模式。\n\n \n\n#### `int window_get_native_handle(handle_type: HandleType, window_id: int = 0)`\n\n获取窗口原生句柄。\n\n \n\n#### `Rect2i window_get_popup_safe_rect(window: int)`\n\n获取弹出窗口安全区域。\n\n \n\n#### `Vector2i window_get_position(window_id: int = 0)`\n\n获取窗口位置。\n\n \n\n#### `Vector2i window_get_position_with_decorations(window_id: int = 0)`\n\n获取窗口位置(含边框)。\n\n \n\n#### `Vector3i window_get_safe_title_margins(window_id: int = 0)`\n\n获取标题栏安全边距。\n\n \n\n#### `Vector2i window_get_size(window_id: int = 0)`\n\n获取窗口大小。\n\n \n\n#### `Vector2i window_get_size_with_decorations(window_id: int = 0)`\n\n获取窗口大小(含边框)。\n\n \n\n#### `Vector2i window_get_title_size(title: String, window_id: int = 0)`\n\n获取标题栏大小。\n\n \n\n#### `VSyncMode window_get_vsync_mode(window_id: int = 0)`\n\n获取垂直同步模式。\n\n \n\n#### `bool window_is_focused(window_id: int = 0)`\n\n检查窗口是否有焦点。\n\n \n\n#### `bool window_is_maximize_allowed(window_id: int = 0)`\n\n检查窗口是否可最大化。\n\n \n\n#### `bool window_maximize_on_title_dbl_click()`\n\n检查双击标题栏是否最大化。\n\n \n\n#### `bool window_minimize_on_title_dbl_click()`\n\n检查双击标题栏是否最小化。\n\n \n\n#### `void window_move_to_foreground(window_id: int = 0)`\n\n将窗口移到前台。\n\n \n\n#### `void window_request_attention(window_id: int = 0)`\n\n请求窗口注意。\n\n \n\n#### `void window_set_current_screen(screen: int, window_id: int = 0)`\n\n设置窗口所在屏幕。\n\n \n\n#### `void window_set_drop_files_callback(callback: Callable, window_id: int = 0)`\n\n设置文件拖放回调。\n\n \n\n#### `void window_set_exclusive(window_id: int, exclusive: bool)`\n\n设置窗口独占模式。\n\n \n\n#### `void window_set_flag(flag: WindowFlags, enabled: bool, window_id: int = 0)`\n\n设置窗口标志。\n\n \n\n#### `void window_set_ime_active(active: bool, window_id: int = 0)`\n\n设置输入法是否激活。\n\n \n\n#### `void window_set_ime_position(position: Vector2i, window_id: int = 0)`\n\n设置输入法位置。\n\n \n\n#### `void window_set_input_event_callback(callback: Callable, window_id: int = 0)`\n\n设置输入事件回调。\n\n \n\n#### `void window_set_input_text_callback(callback: Callable, window_id: int = 0)`\n\n设置文本输入回调。\n\n \n\n#### `void window_set_max_size(max_size: Vector2i, window_id: int = 0)`\n\n设置窗口最大尺寸。\n\n \n\n#### `void window_set_min_size(min_size: Vector2i, window_id: int = 0)`\n\n设置窗口最小尺寸。\n\n \n\n#### `void window_set_mode(mode: WindowMode, window_id: int = 0)`\n\n设置窗口模式。\n\n \n\n#### `void window_set_mouse_passthrough(region: PackedVector2Array, window_id: int = 0)`\n\n设置鼠标穿透区域。\n\n \n\n#### `void window_set_popup_safe_rect(window: int, rect: Rect2i)`\n\n设置弹出窗口安全区域。\n\n \n\n#### `void window_set_position(position: Vector2i, window_id: int = 0)`\n\n设置窗口位置。\n\n \n\n#### `void window_set_rect_changed_callback(callback: Callable, window_id: int = 0)`\n\n设置窗口位置大小变化回调。\n\n \n\n#### `void window_set_size(size: Vector2i, window_id: int = 0)`\n\n设置窗口大小。\n\n \n\n#### `void window_set_title(title: String, window_id: int = 0)`\n\n设置窗口标题。\n\n \n\n#### `void window_set_transient(window_id: int, parent_window_id: int)`\n\n设置窗口为瞬态。\n\n \n\n#### `void window_set_vsync_mode(vsync_mode: VSyncMode, window_id: int = 0)`\n\n设置垂直同步模式。\n\n \n\n#### `void window_set_window_buttons_offset(offset: Vector2i, window_id: int = 0)`\n\n设置窗口按钮偏移。\n\n \n\n#### `void window_set_window_event_callback(callback: Callable, window_id: int = 0)`\n\n设置窗口事件回调。\n\n \n\n#### `void window_start_drag(window_id: int = 0)`\n\n开始拖拽窗口。\n\n \n\n#### `void window_start_resize(edge: WindowResizeEdge, window_id: int = 0)`\n\n开始调整窗口大小。\n\n \n\n---\n\n \n\n### 📞 帮助系统\n\n \n\n#### `void help_set_search_callbacks(search_callback: Callable, action_callback: Callable)`\n\n设置帮助系统搜索回调。\n\n \n\n#### `void show_emoji_and_symbol_picker()`\n\n显示表情符号选择器。\n\n \n\n---\n\n \n\n### ⚙️ 事件处理\n\n \n\n#### `void process_events()`\n\n处理事件。\n\n \n\n---\n\n \n\n## 常量\n\n \n\n- `SCREEN_WITH_MOUSE_FOCUS = -4`:鼠标焦点所在屏幕\n\n- `SCREEN_WITH_KEYBOARD_FOCUS = -3`:键盘焦点所在屏幕  \n\n- `SCREEN_PRIMARY = -2`:主屏幕\n\n- `SCREEN_OF_MAIN_WINDOW = -1`:主窗口所在屏幕\n\n- `MAIN_WINDOW_ID = 0`:主窗口ID\n\n- `INVALID_WINDOW_ID = -1`:无效窗口ID\n\n \n\n---\n\n \n\n## 枚举\n\n \n\n### Feature\n\n系统功能支持检测枚举,包含多种功能如子窗口、触屏、鼠标、剪贴板、虚拟键盘等支持检测。\n\n \n\n### MouseMode  \n\n鼠标模式枚举:可见、隐藏、捕获、限制等模式。\n\n \n\n### ScreenOrientation\n\n屏幕朝向枚举:横屏、竖屏及其反向,以及传感器自动模式。\n\n \n\n### VirtualKeyboardType\n\n虚拟键盘类型:默认、多行、数字、小数、电话、邮箱、密码、URL等。\n\n \n\n### CursorShape\n\n光标形状枚举:箭头、工字形、指向手形等多种光标样式。\n\n \n\n### WindowFlags\n\n窗口标志枚举:控制窗口的各种行为和外观属性。\n\n \n\n### WindowMode\n\n窗口模式枚举:窗口、最小化、最大化、全屏等模式。\n\n \n\n### HandleType\n\n句柄类型枚举:用于获取不同类型的原生窗口句柄。\n\n \n\n### VSyncMode\n\n垂直同步模式枚举:控制画面撕裂和帧率同步。\n\n \n\n### TTSUtteranceEvent\n\n语音朗读事件枚举:开始、结束、取消、边界等事件。\n\n \n\n---\n\n \n\n> **注意**:此文档已排除所有已弃用的方法。某些功能可能仅在特定平台上可用,请参考原始文档中的平台支持说明。", + "游戏引擎/Godot/Godot字典的详细用法.md": "### **Godot `Dictionary` 类用法详解**\n\n#### **基础用法**\n\n------\n\n**1. 创建字典**\n\n```gdscript\n# 空字典\nvar empty_dict = {}\n\n# 初始化字典\nvar simple_dict = {\"name\": \"Godot\", \"version\": 4.0}\n\n# 使用变量作为键和值\nvar key_name = \"language\"\nvar key_value = \"GDScript\"\nvar variable_dict = {key_name: key_value}\n\n# 混合键和值类型\nvar mixed_dict = {\n \"integer_key\": 1,\n \"string_key\": \"value\",\n 3: [1, 2, 3], # 数组作为值\n \"nested_dict\": {\"nested_key\": \"nested_value\"}\n}\n```\n\n\n------\n\n**2. 访问字典值**\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\", \"version\": 4.0}\n\n# 通过键访问值\nprint(my_dict[\"name\"]) # 输出: Godot\n\n# 通过点语法访问(仅限字符串键)\nprint(my_dict.version) # 输出: 4.0\n\n# 使用 `get()` 方法访问\nprint(my_dict.get(\"nonexistent_key\", \"default_value\")) # 输出: default_value\n```\n\n------\n\n**3. 修改或添加键值对**\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\"}\n\n# 修改已有键的值\nmy_dict[\"name\"] = \"Godot Engine\"\n\n# 添加新的键值对\nmy_dict[\"year\"] = 2024\n\nprint(my_dict) # 输出: {\"name\": \"Godot Engine\", \"year\": 2024}\n```\n\n------\n\n**4. 删除键值对**\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\", \"version\": 4.0}\n\n# 使用 erase() 删除\nmy_dict.erase(\"version\")\n\nprint(my_dict) # 输出: {\"name\": \"Godot\"}\n```\n\n------\n\n**5. 检查键是否存在**\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\"}\n\n# 使用 has() 方法\nif my_dict.has(\"name\"):\n print(\"Key exists!\") # 输出: Key exists!\n\n# 等价的 `in` 语法\nif \"name\" in my_dict:\n print(\"Key exists!\") # 输出: Key exists!\n```\n\n------\n\n**6. 遍历字典**\n\n```gdscript\nvar groceries = {\"Apple\": 10, \"Banana\": 5, \"Cherry\": 12}\n\n# 遍历键\nfor fruit in groceries:\n print(fruit, groceries[fruit])\n\n# 遍历键和值\nfor key, value in groceries:\n print(\"Key:\", key, \"Value:\", value)\n```\n\n------\n\n#### **方法说明**\n\n**1. `clear()`** 清空字典的所有条目。\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\", \"version\": 4.0}\nmy_dict.clear()\nprint(my_dict) # 输出: {}\n```\n\n------\n\n**2. `duplicate(deep: bool = false)`** 创建字典的副本。若 `deep` 为 `true`,内部的嵌套字典或数组也会递归复制。\n\n```gdscript\nvar original = {\"key\": [1, 2, 3]}\nvar shallow_copy = original.duplicate()\nshallow_copy[\"key\"].append(4)\n\nprint(original) # 输出: {\"key\": [1, 2, 3, 4]}\nprint(shallow_copy) # 输出: {\"key\": [1, 2, 3, 4]}\n\nvar deep_copy = original.duplicate(true)\ndeep_copy[\"key\"].append(5)\n\nprint(original) # 输出: {\"key\": [1, 2, 3, 4]}\nprint(deep_copy) # 输出: {\"key\": [1, 2, 3, 4, 5]}\n```\n\n------\n\n**3. `erase(key: Variant)`** 移除与指定键关联的条目。\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\"}\nmy_dict.erase(\"name\")\nprint(my_dict) # 输出: {}\n```\n\n------\n\n**4. `find_key(value: Variant)`** 查找给定值对应的第一个键,未找到则返回 `null`。\n\n```gdscript\nvar my_dict = {\"key1\": \"value1\", \"key2\": \"value2\"}\nprint(my_dict.find_key(\"value1\")) # 输出: key1\nprint(my_dict.find_key(\"nonexistent\")) # 输出: null\n```\n\n------\n\n**5. `get(key: Variant, default: Variant = null)`** 安全地获取键对应的值,若键不存在则返回默认值。\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\"}\nprint(my_dict.get(\"name\", \"default\")) # 输出: Godot\nprint(my_dict.get(\"nonexistent_key\", \"default\")) # 输出: default\n```\n\n------\n\n**6. `has_all(keys: Array)`** 检查字典是否包含指定数组中的所有键。\n\n```gdscript\nvar my_dict = {\"width\": 10, \"height\": 20}\nprint(my_dict.has_all([\"width\", \"height\"])) # 输出: true\nprint(my_dict.has_all([\"width\", \"depth\"])) # 输出: false\n```\n\n------\n\n**7. `keys()`** 返回字典中所有键的数组。\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\", \"version\": 4.0}\nprint(my_dict.keys()) # 输出: [\"name\", \"version\"]\n```\n\n------\n\n**8. `values()`** 返回字典中所有值的数组。\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\", \"version\": 4.0}\nprint(my_dict.values()) # 输出: [\"Godot\", 4.0]\n```\n\n------\n\n**9. `merge(dictionary: Dictionary, overwrite: bool = false)`** 合并另一个字典的键值对。默认不覆盖已有键,若 `overwrite` 为 `true` 则覆盖。\n\n```gdscript\nvar dict1 = {\"key1\": \"value1\", \"key2\": \"value2\"}\nvar dict2 = {\"key2\": \"new_value2\", \"key3\": \"value3\"}\n\ndict1.merge(dict2)\nprint(dict1) # 输出: {\"key1\": \"value1\", \"key2\": \"value2\", \"key3\": \"value3\"}\n\ndict1.merge(dict2, true)\nprint(dict1) # 输出: {\"key1\": \"value1\", \"key2\": \"new_value2\", \"key3\": \"value3\"}\n```\n\n------\n\n**10. `size()`** 返回字典中条目的数量。\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\", \"version\": 4.0}\nprint(my_dict.size()) # 输出: 2\n```\n\n------\n\n# **运算符**\n\n------\n\n**1. `==` 和 `!=`** 比较两个字典的内容是否相同。\n\n```gdscript\nvar dict1 = {\"key1\": \"value1\", \"key2\": \"value2\"}\nvar dict2 = {\"key1\": \"value1\", \"key2\": \"value2\"}\nprint(dict1 == dict2) # 输出: true\n\nvar dict3 = {\"key2\": \"value2\", \"key1\": \"value1\"}\nprint(dict1 == dict3) # 输出: true (顺序无关)\n```\n\n**2. `[]` 访问操作符**\n\n```gdscript\nvar my_dict = {\"name\": \"Godot\"}\nprint(my_dict[\"name\"]) # 输出: Godot\n```\n\n------\n", + "游戏引擎/Godot/godot小代码.md": "```swift\n#鼠标左键点击输出点击位置坐标\nfunc _input(event):\n\t# 检查是否是鼠标左键按下事件\n\tif event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:\n\t\t# 获取并打印全局坐标\n\t\tvar global_pos = get_global_mouse_position()\n\t\tprint(\"Global mouse position:\", global_pos)\n```\n\n```swift\n\t\t#调用本地文件选择器(C#版)\n var dialog = new FileDialog();\n dialog.UseNativeDialog = true;\n dialog.Access = FileDialog.AccessEnum.Filesystem;\n dialog.FileSelected += file => GD.Print(file);\n dialog.Show();\n```\n\n```swift\n#调用本地文件选择器(gdscript)\nvar dialog = FileDialog.new()\ndialog.file_mode=FileDialog.FILE_MODE_OPEN_FILE\ndialog.use_native_dialog = true\ndialog.file_selected.connect(on_selected)\ndialog.show()\nv func on_selected(file_path):\nprint(file_path)\n```\n\n", + "游戏引擎/Godot/OS类简单总结.md": "\n\n**`OS` 类**是 Godot 引擎中一个重要的单例,用于提供与操作系统交互的常见功能。它允许你访问视频驱动、处理延时、环境变量、执行外部程序等。\n\n在 Godot 4 中,与窗口和时间相关的功能已分别被移动到 `DisplayServer` 和 `Time` 类。\n\n### 属性\n\n- `bool delta_smoothing`:**默认 `true`**。启用增量平滑,用于在垂直同步开启时补偿帧之间的时间变化。\n \n- `bool low_processor_usage_mode`:**默认 `false`**。启用低处理器使用模式,通过按需刷新屏幕来节省 CPU 资源,特别适用于移动设备。\n \n- `int low_processor_usage_mode_sleep_usec`:**默认 `6900`**。低处理器模式下,帧之间的睡眠时间(微秒),值越大 CPU 使用率越低。\n \n---\n\n### 方法概览\n\n| 方法名 | 简要说明 | 适用平台 |\n| ------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------- |\n| `alert(text, title)` | 显示一个阻塞式的模态对话框。 | 所有 |\n| `close_midi_inputs()` | 关闭系统 MIDI 驱动,停止接收 MIDI 事件。 | Linux, macOS, Windows, Web |\n| `crash(message)` | 使引擎崩溃。仅用于测试,不建议常规使用。 | 所有 |\n| `create_instance(arguments)` | 创建一个新的 Godot 实例,返回进程 ID。 | Android, Linux, macOS, Windows |\n| `create_process(path, arguments, open_console)` | 创建一个新的独立进程,返回进程 ID。 | Android, Linux, macOS, Windows |\n| `delay_msec(msec)` | 阻塞当前线程 `msec` 毫秒。 | 所有 |\n| `delay_usec(usec)` | 阻塞当前线程 `usec` 微秒。 | 所有 |\n| `execute(path, arguments, output, read_stderr, open_console)` | 阻塞式执行外部程序,可获取其退出代码和输出。 | Android, Linux, macOS, Windows |\n| `execute_with_pipe(path, arguments, blocking)` | 创建带 I/O 重定向的独立进程,返回包含 PID、stdin/stdout/stderr 管道的字典。 | Android, Linux, macOS, Windows |\n| `find_keycode_from_string(string)` | 根据字符串查找对应的键码。 | 所有 |\n| `get_cache_dir()` | 返回全局缓存数据目录路径。 | 所有 |\n| `get_cmdline_args()` | 返回所有传递给引擎的命令行参数。 | 所有 |\n| `get_cmdline_user_args()` | 返回双破折号 `--` 之后的用户自定义命令行参数。 | 所有 |\n| `get_config_dir()` | 返回全局用户配置目录路径。 | 所有 |\n| `get_connected_midi_inputs()` | 返回已连接的 MIDI 设备名称列表。 | Linux, macOS, Windows, Web |\n| `get_data_dir()` | 返回全局用户数据目录路径。 | 所有 |\n| `get_distribution_name()` | 返回 Linux/BSD 的发行版名称。 | Linux, BSD, Android |\n| `get_entropy(size)` | 生成指定大小的加密安全随机字节数组。 | 所有 |\n| `get_environment(variable)` | 获取指定环境变量的值。 | 所有 |\n| `get_executable_path()` | 返回当前引擎可执行文件的路径。 | 所有 |\n| `get_granted_permissions()` | 返回已授权的权限列表(Android)或用户选择的文件夹列表(macOS)。 | Android, macOS |\n| `get_keycode_string(code)` | 将键码转换为字符串。 | 所有 |\n| `get_locale()` | 返回完整的操作系统区域设置字符串。 | 所有 |\n| `get_locale_language()` | 返回操作系统区域设置的语言代码。 | 所有 |\n| `get_main_thread_id()` | 返回主线程的 ID。 | 所有 |\n| `get_memory_info()` | 返回包含物理、空闲、可用内存等信息的字典。 | 所有 |\n| `get_model_name()` | 返回当前设备的型号名称。 | Android, iOS, macOS, Windows |\n| `get_name()` | 返回主机平台的名称(如 \"Windows\", \"macOS\")。 | 所有 |\n| `get_process_exit_code(pid)` | 获取已终止子进程的退出码。 | Android, Linux, macOS, Windows |\n| `get_process_id()` | 返回当前应用程序的进程 ID。 | Android, iOS, Linux, macOS, Windows |\n| `get_processor_count()` | 返回 CPU 逻辑核心数。 | 所有 |\n| `get_processor_name()` | 返回 CPU 的型号全名。 | Windows, macOS, Linux, iOS |\n| `get_restart_on_exit_arguments()` | 返回退出时自动重启项目的命令行参数。 | 所有 |\n| `get_static_memory_peak_usage()` | 返回静态内存使用峰值(仅调试版本)。 | 所有 |\n| `get_static_memory_usage()` | 返回静态内存使用量(仅调试版本)。 | 所有 |\n| `get_stderr_type()` | 返回标准错误设备的类型。 | 所有 |\n| `get_stdin_type()` | 返回标准输入设备的类型。 | 所有 |\n| `get_stdout_type()` | 返回标准输出设备的类型。 | 所有 |\n| `get_system_ca_certificates()` | 返回系统信任的 PEM 格式证书字符串。 | 所有 |\n| `get_system_dir(dir, shared_storage)` | 返回指定系统目录的路径。 | Android, Linux, macOS, Windows |\n| `get_system_font_path(font_name, ...)` | 返回指定系统字体的文件路径。 | Android, iOS, Linux, macOS, Windows |\n| `get_system_font_path_for_text(font_name, text, ...)` | 返回可用于渲染特定文本的系统替换字体路径数组。 | Android, iOS, Linux, macOS, Windows |\n| `get_system_fonts()` | 返回可用字体家族名称列表。 | Android, iOS, Linux, macOS, Windows |\n| `get_temp_dir()` | 返回全局临时数据目录路径。 | 所有 |\n| `get_thread_caller_id()` | 返回当前线程的 ID。 | 所有 |\n| `get_unique_id()` | 返回一个设备唯一的字符串 ID。**注意**:不用于加密。 | 所有 (Web 不支持) |\n| `get_user_data_dir()` | 返回项目专用的用户数据目录路径 (`user://`)。 | 所有 |\n| `get_version()` | 返回操作系统的确切版本号。 | 所有 (Web 不支持) |\n| `get_version_alias()` | 返回操作系统的品牌版本名和构建号。 | Windows, macOS |\n| `get_video_adapter_driver_info()` | 返回显卡驱动的名称和版本信息。 | Linux, BSD, Windows |\n| `has_environment(variable)` | 检查环境变量是否存在。 | 所有 |\n| `has_feature(tag_name)` | 检查当前实例是否支持某个功能标签。 | 所有 |\n| `is_debug_build()` | 如果是调试构建或在编辑器中运行,返回 `true`。 | 所有 |\n| `is_keycode_unicode(code)` | 检查键码是否对应 Unicode 字符。 | 所有 |\n| `is_process_running(pid)` | 检查指定进程 ID 的子进程是否仍在运行。 | Android, iOS, Linux, macOS, Windows |\n| `is_restart_on_exit_set()` | 检查项目是否被设置为退出时自动重启。 | 所有 |\n| `is_sandboxed()` | 检查应用程序是否在沙箱中运行。 | macOS, Linux |\n| `is_stdout_verbose()` | 检查是否启用了冗长标准输出。 | 所有 |\n| `is_userfs_persistent()` | 检查 `user://` 文件系统是否是持久的。 | 所有 |\n| `kill(pid)` | 终止指定进程 ID 的进程。 | Android, iOS, Linux, macOS, Windows |\n| `move_to_trash(path)` | 将文件或目录移动到系统的回收站。 | Android, Linux, macOS, Windows |\n| `open_midi_inputs()` | 初始化系统 MIDI 驱动,开始接收 MIDI 事件。 | Linux, macOS, Windows, Web |\n| `read_buffer_from_stdin(buffer_size)` | 从标准输入读取原始字节数组。 | Linux, macOS, Windows |\n| `read_string_from_stdin(buffer_size)` | 从标准输入读取字符串。 | Linux, macOS, Windows |\n| `request_permission(name)` | 向操作系统请求指定权限。 | Android |\n| `request_permissions()` | 请求危险权限。 | Android |\n| `revoke_granted_permissions()` | 清除 macOS 沙箱应用的用户选择文件夹访问权限。 | macOS |\n| `set_environment(variable, value)` | 设置环境变量。 | 所有 |\n| `set_restart_on_exit(restart, arguments)` | 设置项目退出时是否自动重新启动。 | 桌面平台 |\n| `set_thread_name(name)` | 为当前线程设置名称。 | 所有 |\n| `set_use_file_access_save_and_swap(enabled)` | 启用文件保存的“先写临时文件再交换”模式,可避免文件被锁。 | 所有 |\n| `shell_open(uri)` | 使用系统默认程序打开 URI(文件、链接等)。 | Android, iOS, Web, Linux, macOS, Windows |\n| `shell_show_in_file_manager(file_or_dir_path, open_folder)` | 在文件管理器中打开并选中指定文件或目录。 | Windows, macOS |\n| `unset_environment(variable)` | 移除环境变量。 | 所有 |\n\n---\n\n### 枚举\n\n#### `RenderingDriver`\n\n- `RENDERING_DRIVER_VULKAN` (0)\n \n- `RENDERING_DRIVER_OPENGL3` (1)\n \n- `RENDERING_DRIVER_D3D12` (2)\n \n- `RENDERING_DRIVER_METAL` (3)\n \n\n#### `SystemDir`\n\n- `SYSTEM_DIR_DESKTOP` (0)\n \n- `SYSTEM_DIR_DCIM` (1)\n \n- `SYSTEM_DIR_DOCUMENTS` (2)\n \n- `SYSTEM_DIR_DOWNLOADS` (3)\n \n- `SYSTEM_DIR_MOVIES` (4)\n \n- `SYSTEM_DIR_MUSIC` (5)\n \n- `SYSTEM_DIR_PICTURES` (6)\n \n- `SYSTEM_DIR_RINGTONES` (7)\n \n\n#### `StdHandleType`\n\n- `STD_HANDLE_INVALID` (0)\n \n- `STD_HANDLE_CONSOLE` (1)\n \n- `STD_HANDLE_FILE` (2)\n \n- `STD_HANDLE_PIPE` (3)\n \n- `STD_HANDLE_UNKNOWN` (4)", + "游戏引擎/Unity/Unity代码片段/Unity中的单例模式(全局变量).md": "是的,Unity确实可以通过全局管理的脚本来实现你所说的功能。可以通过 **单例模式** 来创建一个全局的管理脚本,存储并更新玩家的位置,然后让其他脚本通过访问这个全局管理类来实时获取玩家的位置。\r\n\r\n### 解决方案:使用单例模式来管理全局数据\r\n\r\n**步骤:**\r\n\r\n1. 创建一个全局的管理脚本,使用单例模式保存玩家的位置。\r\n2. 在玩家生成脚本中,不断更新这个全局位置。\r\n3. 在 `GUI` 或其他脚本中,通过访问这个全局脚本来获取玩家位置。\r\n\r\n### 示例:\r\n\r\n#### 1. 创建一个全局管理类 `GameManager`\r\n\r\n这个类将使用单例模式,并且持有玩家的位置。\r\n\r\n```csharp\r\nusing UnityEngine;\r\n\r\npublic class GameManager : MonoBehaviour\r\n{\r\n public static GameManager Instance { get; private set; } // 单例模式\r\n public Vector3 PlayerPosition { get; private set; } // 存储玩家位置\r\n\r\n void Awake()\r\n {\r\n // 确保只有一个 GameManager 实例\r\n if (Instance == null)\r\n {\r\n Instance = this;\r\n }\r\n else\r\n {\r\n Destroy(gameObject); // 如果已经有一个实例,销毁当前实例\r\n }\r\n\r\n // 不销毁该物体,以便在场景切换时仍然存在\r\n DontDestroyOnLoad(gameObject);\r\n }\r\n\r\n public void UpdatePlayerPosition(Vector3 newPosition)\r\n {\r\n PlayerPosition = newPosition; // 更新玩家位置\r\n }\r\n}\r\n```\r\n\r\n#### 2. 修改玩家生成脚本 `Player_Generated_Pos`\r\n\r\n在玩家生成脚本中,实例化玩家时更新全局的玩家位置。\r\n\r\n```csharp\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\npublic class Player_Generated_Pos : MonoBehaviour\r\n{\r\n public GameObject playerPrefab; // 玩家飞机的预制体\r\n public Transform[] spawnPoints; // 存储生成点的数组\r\n\r\n private GameObject playerInstance; // 玩家实例\r\n\r\n void Start()\r\n {\r\n // 调用函数在随机位置生成玩家飞机\r\n SpawnPlayerAtRandomPosition();\r\n }\r\n\r\n void SpawnPlayerAtRandomPosition()\r\n {\r\n // 随机选择一个生成点\r\n int randomIndex = Random.Range(0, spawnPoints.Length);\r\n Transform spawnPoint = spawnPoints[randomIndex];\r\n\r\n // 在选定的位置生成玩家飞机,并获取实例对象\r\n playerInstance = Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation);\r\n\r\n // 更新全局玩家位置\r\n GameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position);\r\n \r\n // 输出生成的玩家飞机实例的位置\r\n Debug.Log(\"玩家生成位置:\" + playerInstance.transform.position);\r\n }\r\n\r\n void Update()\r\n {\r\n // 实时更新全局玩家位置\r\n if (playerInstance != null)\r\n {\r\n GameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position);\r\n }\r\n }\r\n}\r\n```\r\n\r\n#### 3. 修改 `GUI` 脚本\r\n\r\n在 `GUI` 脚本中,通过访问 `GameManager.Instance` 获取玩家的实时位置并更新 UI。\r\n\r\n```csharp\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing TMPro; // 引入 TextMeshPro 命名空间\r\nusing UnityEngine;\r\n\r\npublic class GUI : MonoBehaviour\r\n{\r\n private TextMeshProUGUI Player_Pos; // 存储 TextMeshProUGUI 组件\r\n\r\n void Start()\r\n {\r\n // 使用 GetComponent 获取 TextMeshProUGUI 组件\r\n Player_Pos = GameObject.Find(\"Player_Pos\")?.GetComponent();\r\n }\r\n\r\n void Update()\r\n {\r\n // 获取全局的玩家位置\r\n if (GameManager.Instance != null)\r\n {\r\n Vector3 playerPosition = GameManager.Instance.PlayerPosition;\r\n\r\n // 更新UI显示玩家位置\r\n if (Player_Pos != null)\r\n {\r\n Player_Pos.text = \"玩家坐标: (\" + playerPosition.x + \",\" + playerPosition.y + \")\";\r\n }\r\n }\r\n }\r\n}\r\n```\r\n\r\n### 解释:\r\n\r\n1. **`GameManager` 类**:\r\n - `GameManager` 类作为一个 **单例**,负责存储并提供玩家的位置数据。它使用 `Awake()` 方法确保只会有一个实例,并使用 `DontDestroyOnLoad()` 方法确保场景切换时 `GameManager` 不会被销毁。\r\n - `UpdatePlayerPosition()` 方法用于更新玩家的位置。\r\n\r\n2. **`Player_Generated_Pos` 类**:\r\n - 在 `SpawnPlayerAtRandomPosition()` 中,生成玩家飞机后,通过 `GameManager.Instance.UpdatePlayerPosition()` 将生成的位置传递到全局管理器。\r\n - 在 `Update()` 方法中,实时更新全局的玩家位置。\r\n\r\n3. **`GUI` 类**:\r\n - 在 `Update()` 方法中,通过 `GameManager.Instance.PlayerPosition` 获取玩家的实时位置,并更新 `TextMeshProUGUI` 组件中的文本。\r\n\r\n### 优点:\r\n- **全局管理**:通过 `GameManager` 单例类,你可以轻松地在任何脚本中获取和更新玩家的位置。\r\n- **实时更新**:`GUI` 脚本每帧都会自动获取并显示玩家的实时位置。\r\n- **模块化**:通过分离管理和显示逻辑,你的代码结构会更加清晰和易于维护。\r\n\r\n### 总结:\r\n使用 **单例模式** 作为全局脚本来管理和共享玩家位置是一个非常有效的方法。它不仅能减少跨脚本传递数据的复杂度,而且能确保玩家位置在不同的脚本之间实时同步。\r\n\r\n\r\n\r\n根据你的描述,问题出在这一行代码:\r\n\r\n```csharp\r\nGameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position);\r\n```\r\n\r\n如果报错是由于 `GameManager.Instance` 返回 `null`,说明 `GameManager` 这个单例没有正确初始化,或者它没有被加载到场景中。通常,这种情况是因为:\r\n\r\n1. **`GameManager` 没有正确加载或实例化**,即它没有在场景中创建,或者它在访问时被销毁。\r\n2. **`Awake()` 方法没有正确执行**,从而导致 `Instance` 为 `null`。\r\n\r\n### 检查和修复步骤:\r\n\r\n1. **确保 `GameManager` 存在于场景中**:\r\n 确保 `GameManager` 脚本已挂载到一个对象上,并且该对象已存在于场景中。你可以检查 `GameManager` 是否被添加到了一个合适的 GameObject 上(例如一个 \"GameManager\" 或 \"Manager\" 的空物体)。\r\n\r\n2. **确保 `GameManager` 使用单例模式**:\r\n 检查 `GameManager` 脚本的 `Awake()` 方法,确保它正确初始化并设置 `Instance`,例如:\r\n\r\n ```csharp\r\n using UnityEngine;\r\n \r\n public class GameManager : MonoBehaviour\r\n {\r\n public static GameManager Instance { get; private set; }\r\n \r\n public Vector3 PlayerPosition { get; private set; } // 存储玩家位置\r\n \r\n void Awake()\r\n {\r\n // 检查是否已经有 GameManager 实例存在\r\n if (Instance == null)\r\n {\r\n Instance = this;\r\n DontDestroyOnLoad(gameObject); // 确保场景切换时不销毁该对象\r\n }\r\n else\r\n {\r\n Destroy(gameObject); // 如果已经有一个实例,销毁当前实例\r\n }\r\n }\r\n \r\n public void UpdatePlayerPosition(Vector3 newPosition)\r\n {\r\n PlayerPosition = newPosition; // 更新玩家位置\r\n }\r\n }\r\n ```\r\n\r\n - 确保 `Instance` 在 `Awake()` 中被赋值。\r\n - 如果场景中已经存在一个 `GameManager` 实例,后加载的 `GameManager` 会被销毁。\r\n\r\n3. **检查是否有其他 `GameManager` 实例**:\r\n - 如果在场景中有多个 `GameManager` 实例,`Instance` 可能会被覆盖。确保只有一个 `GameManager` 实例,避免出现多个对象争夺单例实例。\r\n\r\n4. **调试**:\r\n 在 `Player_Generated_Pos` 脚本中,添加调试信息来检查 `GameManager.Instance` 是否为 `null`。\r\n\r\n ```csharp\r\n void Update()\r\n {\r\n // 检查 GameManager 是否为 null\r\n if (GameManager.Instance == null)\r\n {\r\n Debug.LogError(\"GameManager 实例为 null,确保 GameManager 已经正确加载!\");\r\n }\r\n else if (playerInstance != null)\r\n {\r\n // 更新全局玩家位置\r\n GameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position);\r\n }\r\n }\r\n ```\r\n\r\n 如果控制台显示 \"GameManager 实例为 null\",说明 `GameManager` 没有正确实例化,可能是由于 `Awake()` 方法没有执行,或者场景中没有正确的 `GameManager` 对象。\r\n\r\n### 总结:\r\n\r\n- 确保 `GameManager` 正确地使用单例模式,并且它的实例在场景中是唯一的。\r\n- 使用 `DontDestroyOnLoad` 确保 `GameManager` 在场景切换时不被销毁。\r\n- 在其他脚本中访问 `GameManager.Instance` 前,确保它已经正确初始化。\r\n\r\n通过这些步骤,你应该能够解决 `GameManager.Instance` 为 `null` 的问题。\r\n\r\n\r\n\r\n", + "游戏引擎/Unity/Unity代码片段/unity修改物理碰撞层.md": "要实现玩家射出的子弹不与玩家碰撞,而与敌人碰撞,敌人射出的子弹不与敌人碰撞而与玩家碰撞,你可以通过调整Unity中的**物理层(Layer)**和**碰撞矩阵(Collision Matrix)**来解决这个问题。\r\n\r\n### 步骤:\r\n\r\n1. **创建新的物理层**:\r\n - 在Unity中,首先你需要为玩家、敌人和子弹分别创建不同的物理层。\r\n - 转到 `Edit` -> `Project Settings` -> `Tags and Layers`。\r\n - 在 `Layers` 部分,点击 `User Layer` 下面的空白区域,创建以下新的层:\r\n - `Player`\r\n - `Enemy`\r\n - `PlayerBullet`\r\n - `EnemyBullet`\r\n\r\n2. **将对象分配到不同的层**:\r\n - 将玩家对象的 `Layer` 设置为 `Player`。\r\n - 将敌人对象的 `Layer` 设置为 `Enemy`。\r\n - 将玩家射出的子弹的 `Layer` 设置为 `PlayerBullet`。\r\n - 将敌人射出的子弹的 `Layer` 设置为 `EnemyBullet`。\r\n\r\n3. **设置碰撞矩阵**:\r\n - 转到 `Edit` -> `Project Settings` -> `Physics`。\r\n - 在 `Physics` 设置中,找到 `Layer Collision Matrix`。\r\n - 你可以在这里设置哪些层之间可以发生碰撞。\r\n - **Player 和 PlayerBullet** 之间不发生碰撞。\r\n - **Enemy 和 EnemyBullet** 之间不发生碰撞。\r\n - **PlayerBullet 和 Enemy** 之间发生碰撞。\r\n - **EnemyBullet 和 Player** 之间发生碰撞。\r\n \r\n 具体的设置应该如下:\r\n - 确保 `Player` 和 `PlayerBullet` 行与列之间的勾选框是**取消勾选的**,这样它们不会发生碰撞。\r\n - 确保 `Enemy` 和 `EnemyBullet` 行与列之间的勾选框是**取消勾选的**,这样它们不会发生碰撞。\r\n - 确保 `PlayerBullet` 和 `Enemy` 之间,以及 `EnemyBullet` 和 `Player` 之间的碰撞是**勾选的**。\r\n\r\n4. **确保Rigidbody的碰撞检测模式正确**:\r\n - 对于玩家和子弹的 `Rigidbody` 组件,确保它们的 `Collision Detection` 设置为 `Continuous` 或 `Continuous Dynamic`,这有助于避免物理计算错误,尤其是在高速度的情况下。\r\n\r\n### 代码示例(如果需要动态设置层):\r\n如果你希望在代码中动态设置某个对象的层,可以使用以下代码:\r\n\r\n```csharp\r\n// 设置玩家子弹的层\r\ngameObject.layer = LayerMask.NameToLayer(\"PlayerBullet\");\r\n\r\n// 设置敌人子弹的层\r\ngameObject.layer = LayerMask.NameToLayer(\"EnemyBullet\");\r\n```\r\n\r\n### 结论:\r\n通过使用Unity的**Layer**和**Layer Collision Matrix**,你可以精确控制不同物体之间的碰撞行为。将玩家、敌人和子弹分别分配到不同的物理层,并在碰撞矩阵中配置它们之间的碰撞规则,就能实现你所需要的功能:玩家射出的子弹不与玩家碰撞,而与敌人碰撞,敌人射出的子弹不与敌人碰撞,而与玩家碰撞。", + "游戏引擎/Unity/Unity代码片段/unity导出到Windows改变窗口.md": "在Unity中,如果你希望应用程序以特定的窗口大小而不是全屏运行,可以通过以下步骤进行设置:\r\n\r\n### 1. **通过Player Settings设置窗口模式**:\r\n - 打开 `Edit` 菜单,选择 `Project Settings`。\r\n - 在 `Project Settings` 中,选择 `Player`。\r\n - 在 `Player` 设置中,找到 `Resolution and Presentation` 部分。\r\n\r\n### 2. **调整默认显示模式**:\r\n - 在 `Resolution and Presentation` 下,找到 `Default Screen Mode`。\r\n - 将其设置为 `Windowed`,而不是 `Full Screen`,这样Unity会默认以窗口模式运行。\r\n\r\n### 3. **设置窗口的分辨率**:\r\n - 在 `Resolution and Presentation` 中,你还可以设置窗口的默认分辨率:\r\n - `Default Screen Width` 和 `Default Screen Height` 可以指定启动时窗口的大小。\r\n - 例如,设置为 `1024x768`,这将使窗口在启动时以 1024x768 的分辨率打开。\r\n\r\n### 4. **通过代码动态调整窗口大小**:\r\n 如果你希望根据需要在游戏运行时改变窗口大小,可以使用以下代码:\r\n\r\n ```csharp\r\n void Start()\r\n {\r\n // 设置窗口大小为 1024x768\r\n Screen.SetResolution(1024, 768, false);\r\n }\r\n ```\r\n\r\n 这里,`Screen.SetResolution` 的第三个参数是布尔值,`false` 表示窗口模式(如果是 `true` 则会进入全屏模式)。\r\n\r\n### 总结:\r\n1. 在 `Player Settings` 中设置默认为窗口模式(`Windowed`)。\r\n2. 可选择设置默认窗口的分辨率。\r\n3. 如果需要动态调整窗口大小,可以通过 `Screen.SetResolution` 来实现。\r\n\r\n通过这些设置,你就能让你的Unity项目在启动时以指定窗口大小而不是全屏运行。", + "游戏引擎/Unity/Unity代码片段/unity碰撞体撞到指定标签的碰撞体后操作.md": "要实现子弹在撞到标签为“air_wall”的碰撞体后被销毁,你需要在 `Bullet` 脚本中添加碰撞检测代码。使用 `OnCollisionEnter2D` 方法来处理与碰撞体的接触,并检查碰撞体的标签是否是“air_wall”。\r\n\r\n以下是修改后的代码:\r\n\r\n```csharp\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\npublic class Bullet : MonoBehaviour\r\n{\r\n void Start()\r\n {\r\n // 在 5 秒后销毁子弹对象\r\n Destroy(gameObject, 5f); // 5f 表示 5 秒后销毁该对象\r\n }\r\n\r\n void Update()\r\n {\r\n // 你可以在这里添加子弹的移动逻辑\r\n }\r\n\r\n void OnCollisionEnter2D(Collision2D collision)\r\n {\r\n // 检查碰撞体是否有标签 \"air_wall\"\r\n if (collision.gameObject.CompareTag(\"AirWall\"))\r\n {\r\n // 如果是,销毁子弹\r\n Destroy(gameObject);\r\n }\r\n }\r\n}\r\n```\r\n\r\n### 解释:\r\n- `OnCollisionEnter2D(Collision2D collision)`:当子弹与其他物体发生碰撞时,这个方法会被调用。\r\n- `collision.gameObject.CompareTag(\"AirWall\")`:检查碰撞体的标签是否是 \"AirWall\"。\r\n- 如果是,使用 `Destroy(gameObject)` 销毁子弹对象。\r\n\r\n这样,子弹在撞到标签为 \"AirWall\" 的物体时就会被销毁。如果需要,也可以将销毁逻辑添加到其他碰撞处理上。", + "游戏引擎/Unity/Unity代码片段/Unity获取同一场景中其他对象的属性&组件.md": "在 Unity 中,获取同一场景中其他对象的属性(如位置)非常简单。你可以通过查找目标对象,并访问其组件来获取需要的信息。常用的方法有以下几种:\r\n\r\n### 1. 使用 `GameObject.Find()` 查找对象并获取其属性\r\n`GameObject.Find()` 可以用来查找场景中具有指定名称的对象。\r\n\r\n示例代码:\r\n\r\n```csharp\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\npublic class Player_Generated_Pos : MonoBehaviour\r\n{\r\n void Start()\r\n {\r\n // 查找名称为 \"TargetObject\" 的对象\r\n GameObject targetObject = GameObject.Find(\"TargetObject\");\r\n\r\n if (targetObject != null)\r\n {\r\n // 获取目标对象的位置\r\n Vector3 targetPosition = targetObject.transform.position;\r\n Debug.Log(\"Target position: \" + targetPosition);\r\n }\r\n else\r\n {\r\n Debug.LogWarning(\"TargetObject not found!\");\r\n }\r\n }\r\n\r\n void Update()\r\n {\r\n // 可以根据需要在 Update 中执行相关操作\r\n }\r\n}\r\n```\r\n\r\n### 2. 使用标签(`Tag`)查找对象\r\n如果对象的名称可能发生变化,使用标签(`Tag`)来查找更为可靠。你可以先在 Unity 编辑器中为对象设置标签。\r\n\r\n示例代码:\r\n\r\n```csharp\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\npublic class Player_Generated_Pos : MonoBehaviour\r\n{\r\n void Start()\r\n {\r\n // 查找所有带有 \"Target\" 标签的对象\r\n GameObject[] targetObjects = GameObject.FindGameObjectsWithTag(\"Target\");\r\n\r\n foreach (GameObject targetObject in targetObjects)\r\n {\r\n // 获取目标对象的位置\r\n Vector3 targetPosition = targetObject.transform.position;\r\n Debug.Log(\"Target position: \" + targetPosition);\r\n }\r\n }\r\n\r\n void Update()\r\n {\r\n // 可以根据需要在 Update 中执行相关操作\r\n }\r\n}\r\n```\r\n\r\n### 3. 使用 `GetComponent` 访问其他组件的属性\r\n如果你已经有了目标对象的引用,可以通过 `GetComponent` 获取该对象的组件并访问其属性。\r\n\r\n例如,假设你已经有一个 `Player` 对象,并且想访问该对象的 `Transform` 组件的位置:\r\n\r\n```csharp\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\npublic class Player_Generated_Pos : MonoBehaviour\r\n{\r\n public GameObject player; // 你可以将 Player 对象通过 Inspector 拖入\r\n\r\n void Start()\r\n {\r\n if (player != null)\r\n {\r\n // 获取 Player 对象的位置\r\n Vector3 playerPosition = player.transform.position;\r\n Debug.Log(\"Player position: \" + playerPosition);\r\n }\r\n else\r\n {\r\n Debug.LogWarning(\"Player object not assigned!\");\r\n }\r\n }\r\n\r\n void Update()\r\n {\r\n // 可以根据需要在 Update 中执行相关操作\r\n }\r\n}\r\n```\r\n\r\n### 总结:\r\n- **`GameObject.Find()`**:通过名称查找对象。\r\n- **`GameObject.FindGameObjectsWithTag()`**:通过标签查找对象。\r\n- **`GetComponent()`**:如果你有对象引用,使用该方法来访问对象的组件和属性。\r\n\r\n根据你的需求,选择适合的方式来获取对象的位置或其他属性。", + "游戏引擎/Unity/Unity代码片段/保留整数.md": "要保留整数并显示玩家坐标,你可以使用 `Mathf.RoundToInt()` 来将浮动的坐标值四舍五入为整数,或者直接使用 `ToString()` 来控制格式。这里是两种常见的方法:\r\n\r\n### 方法 1:使用 `Mathf.RoundToInt()` 将坐标四舍五入为整数\r\n\r\n```csharp\r\nPlayer_Pos.text = \"玩家坐标: (\" + Mathf.RoundToInt(playerPosition.x) + \",\" + Mathf.RoundToInt(playerPosition.y) + \")\";\r\n```\r\n\r\n`Mathf.RoundToInt()` 会将浮动的坐标值四舍五入为最接近的整数。\r\n\r\n### 方法 2:使用 `ToString()` 来格式化数字\r\n\r\n你也可以使用 `ToString(\"F0\")` 来将数字转换为带有指定小数位数的字符串,在这种情况下是零小数位,表示整数。\r\n\r\n```csharp\r\nPlayer_Pos.text = \"玩家坐标: (\" + playerPosition.x.ToString(\"F0\") + \",\" + playerPosition.y.ToString(\"F0\") + \")\";\r\n```\r\n\r\n这种方式也会将坐标保留为整数,并且格式化为 `string` 类型。\r\n\r\n### 总结:\r\n\r\n- **`Mathf.RoundToInt()`**: 将浮动坐标值四舍五入为最接近的整数。\r\n- **`ToString(\"F0\")`**: 格式化为没有小数位的字符串。\r\n\r\n这两种方法都能达到你的目的,具体选择哪一种取决于你是否需要精确的四舍五入,或者仅仅是格式化显示。", + "游戏引擎/Unity/Unity代码片段/设置在几个特定点钟随机生成.md": "要实现玩家飞机在地图上的 5 个点之间随机生成,你可以定义一个包含这 5 个点的数组或列表,然后通过随机选择一个点来生成飞机。\r\n\r\n以下是一个示例脚本:\r\n\r\n### 步骤:\r\n1. **定义 5 个生成点的位置**:你可以将这些点的位置存储在一个 `Vector3[]` 数组中。\r\n2. **随机选择一个点**:使用 `Random.Range` 方法从这个数组中随机选择一个点。\r\n3. **将玩家飞机生成到选定的位置**:通过 `Instantiate` 方法实例化玩家飞机对象并设置它的位置。\r\n\r\n### 示例代码:\r\n\r\n```csharp\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\npublic class Player_Generated_Pos : MonoBehaviour\r\n{\r\n public GameObject playerPrefab; // 玩家飞机的预制体\r\n public Transform[] spawnPoints; // 存储生成点的数组\r\n\r\n void Start()\r\n {\r\n // 调用函数在随机位置生成玩家飞机\r\n SpawnPlayerAtRandomPosition();\r\n }\r\n\r\n void SpawnPlayerAtRandomPosition()\r\n {\r\n // 随机选择一个生成点\r\n int randomIndex = Random.Range(0, spawnPoints.Length);\r\n Transform spawnPoint = spawnPoints[randomIndex];\r\n\r\n // 在选定的位置生成玩家飞机\r\n Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation);\r\n }\r\n}\r\n```\r\n\r\n### 解释:\r\n1. **`spawnPoints`**:这是一个 `Transform[]` 数组,用来存储 5 个可能的生成点。你可以在 Unity 编辑器中通过拖拽场景中的物体(生成点)到这个数组中来设置这些位置。\r\n2. **`Random.Range(0, spawnPoints.Length)`**:随机选择一个索引,范围从 `0` 到 `spawnPoints.Length - 1`。\r\n3. **`Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation)`**:在选择的生成点位置生成玩家飞机(`playerPrefab`)。\r\n\r\n### 在 Unity 编辑器中:\r\n1. 将 `Player_Generated_Pos` 脚本附加到一个物体(比如一个空的 GameObject)。\r\n2. 在 Inspector 面板中,设置 `playerPrefab` 为你的玩家飞机预制体。\r\n3. 设置 `spawnPoints` 数组,确保它包含你要随机生成玩家飞机的 5 个位置点。你可以将场景中的空物体拖到该数组中,作为生成点。\r\n\r\n### 生成点设置:\r\n你可以在 Unity 场景中创建 5 个空物体,并将它们放置在你希望飞机生成的位置。然后,将这些空物体拖到 `spawnPoints` 数组中。\r\n\r\n这样,当游戏开始时,玩家飞机将会在这 5 个点之间的一个位置随机生成。", + "游戏引擎/Unity/Unity简单解决字体放大模糊问题.md": "把文本组件缩小十倍(以1为基准)\r\n\r\n然后把字体大小放大10倍\r\n\r\n然后拖动适应原来的位置大小", + "生活科普/OTC药和处方药的区别.md": "OTC(Over-The-Counter) 指无需医生处方即可自行购买和使用的药品,主要用于治疗轻微疾病或症状,具有安全性较高、副作用较小的特点。以下是关于OTC药的详细说明:\n \n一、OTC药的核心特点\n \n1. 无需处方:可直接在药店或超市购买,无需医生诊断。\n2. 适应症明确:针对常见小病(如感冒、发烧、头痛、消化不良等),患者可自我判断症状。\n3. 安全性高:经过监管机构评估,剂量和疗程有明确限制,风险较低。\n4. 说明书指导:需严格按说明书使用,避免过量或长期服用。\n \n二、OTC药与处方药的区别\n \n特性 OTC药 处方药 \n购买条件 无需处方 必须凭医生处方 \n适应症 轻微、短期症状 复杂或严重疾病 \n风险等级 较低 较高(需专业监控) \n剂量控制 固定标准剂量 可能需个性化调整 \n包装标识 标注“OTC”(中国分红色/绿色) 标注“凭医师处方销售” \n \n三、常见OTC药类型\n \n1. 解热镇痛药:布洛芬、对乙酰氨基酚(缓解头痛、发热)。\n2. 感冒药:复方氨酚烷胺、伪麻黄碱(缓解鼻塞、咳嗽)。\n3. 消化系统药:健胃消食片、奥美拉唑(治疗胃酸过多、消化不良)。\n4. 维生素与矿物质:维生素C、钙尔奇(补充营养)。\n5. 外用药:皮炎平、云南白药(处理皮肤问题或外伤)。\n \n四、使用OTC药的注意事项\n \n1. 仔细阅读说明书:注意禁忌症、剂量和不良反应。\n2. 避免重复用药:多种复方药可能含相同成分(如对乙酰氨基酚),过量易伤肝。\n3. 特殊人群慎用:孕妇、哺乳期女性、慢性病患者需咨询医生。\n4. 不滥用抗生素:抗生素属于处方药,不可自行购买(如阿莫西林)。\n5. 及时就医:若症状未缓解或加重,应停止用药并寻求专业帮助。\n \n五、中国OTC药分类\n \n- 红色OTC:需在药师指导下购买,安全性稍低(如部分感冒药)。\n- 绿色OTC:可自行购买,安全性更高(如维生素、部分外用药)。\n \n总结\n \nOTC药为日常小病提供便利,但需理性使用,避免盲目依赖。若症状复杂或持续,建议及时就医,由专业医生判断治疗方案。", + "生活科普/打针和注射原理.md": "打针一般是指将药物通过注射器注入人体,主要有肌肉注射、静脉注射和皮下注射等方式,其原理如下:\n \n**肌肉注射**\n \n- 吸收原理:肌肉组织有丰富的毛细血管网。药物注入肌肉后,先存在于肌肉组织间隙,然后依靠浓度梯度,通过毛细血管壁的内皮细胞间隙等途径,扩散进入毛细血管,进而进入血液循环,随血液运输到全身各处发挥药效。\n- 优势:可使药物缓慢释放,维持较长时间的药效。像一些抗生素类药物采用肌肉注射,能在一定时间内持续发挥抗菌作用。\n \n**静脉注射**\n \n- 吸收原理:直接将药物注入静脉血管内,药物会迅速与血液混合,随血液循环快速到达全身各个组织器官,能快速发挥药效。\n- 优势:适用于危急重症患者,如在抢救休克患者时,通过静脉注射血管活性药物等,能迅速提升血压等,挽救生命。也可用于需要大量补液或输入刺激性较强药物的情况,因为血液能快速稀释药物,减少药物对局部组织的刺激。\n \n**皮下注射**\n \n- 吸收原理:皮下组织有疏松的结缔组织和少量脂肪,也有一定的血管分布。药物注入皮下后,在组织液中溶解,然后通过毛细血管内皮细胞的吞饮、扩散等方式进入血液循环,吸收速度相对较慢。\n- 优势:常用于需要缓慢吸收、持续发挥作用的药物,如胰岛素。患者可在家中自行进行皮下注射,方便糖尿病患者日常控制血糖。\n \n打针时需严格遵循无菌操作原则,根据药物性质、患者病情等选择合适的注射方式、部位和剂量,以确保治疗效果和患者安全。", + "生活科普/高铁座位.md": "高铁ABC座位的排列因座位类型而异:\n \n- **二等座**:采用“3+2”式排列,从左到右依次是A、B、C、D、F。其中A、B、C为三人座,A靠窗,B在中间,C靠过道。\n​\n- **一等座**:采用“2+2”式排列,从左到右依次是A、C、D、F。A和C是连座,A靠窗,C靠过道。\n​\n- **商务座**:通常采用“2+1”或“1+1”式排列,座位从左到右依次是A、C、F或A、F。采用“2+1”布局时,A靠窗,C靠过道。", + "生物学科普/抗生素杀菌原理及作用机制详解.md": "抗生素主要通过干扰细菌的关键生命过程来杀灭或抑制其生长,其核心原理是**选择性毒性**——针对细菌特有的结构或代谢途径,而对人体细胞影响较小。以下是主要的杀菌原理分类及作用机制:\n\n---\n\n### **一、抑制细胞壁合成(对细菌最致命)**\n细菌细胞壁主要由**肽聚糖(Peptidoglycan)**构成,人体细胞无此结构。\n- **β-内酰胺类**(青霉素、头孢菌素):\n - 阻断**转肽酶**(青霉素结合蛋白,PBPs),抑制肽聚糖链的交联 → 细胞壁缺损。\n - 结果:细菌在渗透压下破裂(溶菌)。\n- **万古霉素**:\n - 直接结合肽聚糖前体(D-丙氨酰-D-丙氨酸),阻止其整合到细胞壁骨架。\n- **杆菌肽**:\n - 干扰细胞膜上**脂质载体( bactoprenol)**的再生,阻碍肽聚糖前体转运。\n\n> ⚠️ **特点**:对生长旺盛的细菌效果最强,对休眠菌无效。\n\n---\n\n### **二、破坏细胞膜完整性**\n直接攻击细菌特有的膜结构(如革兰阴性菌外膜)。\n- **多黏菌素类**:\n - 带正电荷的分子与膜磷脂结合 → 膜通透性增加 → 内容物泄漏。\n- **达托霉素**(抗革兰阳性菌):\n - 插入细胞膜形成离子通道 → 钾离子外流 → 细胞死亡。\n\n---\n\n### **三、抑制蛋白质合成(靶向细菌核糖体)**\n细菌核糖体为**70S**(由50S+30S亚基组成),人体为80S。\n- **30S亚基抑制剂**:\n - **氨基糖苷类**(链霉素、庆大霉素):\n - 结合30S亚基 → 错误读取mRNA → 合成错误蛋白;同时阻断起始复合物形成。\n - **四环素类**:\n - 阻断tRNA进入A位 → 阻止氨基酸添加。\n- **50S亚基抑制剂**:\n - **大环内酯类**(红霉素、阿奇霉素):\n - 阻断肽链延伸(肽酰转移酶中心)。\n - **氯霉素**:\n - 抑制肽酰转移酶 → 阻止肽键形成。\n - **林可酰胺类**(克林霉素):\n - 与50S亚基结合,抑制转肽反应。\n\n> ✅ **选择性**:因核糖体结构差异,对真核细胞影响小。\n\n---\n\n### **四、抑制核酸(DNA/RNA)合成**\n- **喹诺酮类**(环丙沙星、左氧氟沙星):\n - 抑制**DNA旋转酶(拓扑异构酶Ⅱ)** → DNA无法解旋复制 → 细菌死亡。\n- **利福平**:\n - 结合**RNA聚合酶**β亚基 → 阻断mRNA转录。\n\n---\n\n### **五、干扰叶酸代谢**\n细菌需自行合成叶酸(人体直接从食物获取)。\n- **磺胺类** & **甲氧苄啶(TMP)**:\n - 磺胺:竞争性抑制**二氢蝶酸合酶**(以PABA为底物)。\n - TMP:抑制**二氢叶酸还原酶** → 阻断四氢叶酸合成。\n - 结果:核苷酸合成受阻 → 细菌生长停滞(抑菌)。\n\n---\n\n### **六、抗结核分枝杆菌的特效药**\n- **异烟肼(INH)**:抑制分枝菌酸合成(结核杆菌细胞壁关键成分)。\n- **乙胺丁醇**:干扰阿拉伯半乳聚糖合成(细胞壁组分)。\n\n---\n\n### **关键概念:杀菌 vs 抑菌**\n| **类型** | 代表药物 | 作用特点 |\n|----------------|--------------------------|----------------------------|\n| **杀菌剂** | 青霉素、氨基糖苷类 | 直接杀死细菌 |\n| **抑菌剂** | 四环素、磺胺类 | 抑制生长,依赖免疫系统清除 |\n| **浓度依赖性** | 氨基糖苷类、喹诺酮类 | 浓度越高杀菌越快 |\n| **时间依赖性** | β-内酰胺类、万古霉素 | 需维持有效血药浓度时间 |\n\n---\n\n### **为什么抗生素不伤害人体细胞?**\n1. **靶点差异**:如细胞壁、70S核糖体、叶酸合成酶为细菌特有。\n2. **代谢途径差异**:细菌需自主合成叶酸,人类可从食物获取。\n3. **选择性渗透**:部分药物难以穿透人体细胞膜。\n\n---\n\n### **耐药性警示**\n过度使用抗生素会导致细菌通过**基因突变**、**产生灭活酶**(如β-内酰胺酶)、**改变靶点**等方式产生耐药性。", + "生物学科普/死亡后的尸体现象与死亡时间推断.md": "\n## 一、早期尸体现象\n\n早期变化通常发生在**死亡后数小时至两天内**,主要包括:\n\n### 1. 尸冷(Algor mortis)\n\n- **机制**:死亡后产热停止,体温逐渐下降,直至与环境温度一致。\n \n- **一般规律**:\n \n - 室内常温:每小时约下降 **0.83℃**。\n \n - 水中:每小时下降 **3-4℃**。\n \n - 高温环境(如沙漠):尸温可能不降反升。\n \n - 冬季:下降速度更快,可超过 **1℃/h**。\n \n- **经验公式**:\n \n ```\n 死后时间(小时)= (37℃ - 直肠温度) ÷ 0.83 × 系数\n 系数:春秋=1;夏季=1.4;冬季=0.7\n ```\n \n\n### 2. 尸僵(Rigor mortis)\n\n- **机制**:肌肉内ATP耗竭,肌纤维固定。\n \n- **时间规律**:\n \n - 30分钟~2小时:开始出现。\n \n - 6~8小时:全身僵硬。\n \n - 12~15小时:达到高峰。\n \n - 24~36小时:逐渐缓解并消失。\n \n- **影响因素**:环境温度(高温→加快)、死前剧烈活动。\n \n\n### 3. 尸斑(Livor mortis)\n\n- **机制**:血液因重力下沉,淤积于低垂部位。\n \n- **时间规律**:\n \n - 30分钟内:可见淡红色。\n \n - 5~6小时:明显,按压可消退。\n \n - 8小时后:血红蛋白渗入组织,颜色固定,不再随体位改变。\n \n- **特殊表现**:\n \n - 中毒:一氧化碳中毒呈鲜红色。\n \n - 冻死:尸斑呈红色。\n \n\n### 4. 其他早期指标\n\n- **角膜混浊**:8~12小时出现。\n \n- **胃内容物消化情况**:饭后2–4小时消化明显,可作为辅助判断。\n \n- **尸绿**:腹部皮肤变绿,多在死亡2~3天后出现。\n \n\n---\n\n## 二、晚期尸体现象\n\n当死亡超过**数天至数周**,进入晚期变化。\n\n### 1. 腐败(Putrefaction)\n\n- **起始**:2–3天内出现腹部尸绿,随后扩散全身。\n \n- **典型表现**:\n \n - 5–7天:气体产生,颜面肿胀,口鼻流出液体。\n \n - 数周:软组织液化,最后仅剩骨骼。\n \n- **白骨化**:土中一般需7–10年。\n \n\n### 2. 动物破坏\n\n- 苍蝇产卵→蛆→蛹→成蝇。\n \n- 夏季1个月内可能食尽软组织。\n \n- 蚂蚁、鼠类、犬猫等亦可造成破坏。\n \n\n### 3. 保存现象\n\n- **尸蜡(adipocere)**:潮湿缺氧环境,1–2月起始,数月至1年可广泛形成。\n \n- **木乃伊化**:干燥环境下数月后形成。\n \n\n---\n\n## 三、死亡时间推断方法\n\n### 1. 基于尸体现象\n\n- **尸温下降**:常用于**12小时内**。\n \n- **尸斑与尸僵**:用于**48小时内**的判断。\n \n- **腐败与昆虫学**:适用于**数日以上**。\n \n\n### 2. 胃肠道内容物\n\n- 餐后 0–2h:胃内充满食物。\n \n- 餐后 2–4h:食物进入十二指肠。\n \n- 餐后 6h 以上:胃已排空。\n \n\n### 3. 法医昆虫学\n\n- 苍蝇卵:死亡后几小时即产卵。\n \n- 蛆成熟:4–15天。\n \n- 蛹壳存在:提示**死后约2周以上**。\n \n\n### 4. 超生反应\n\n- **死后肌肉反应**:2小时内仍可有收缩。\n \n- **瞳孔反应**:4小时内可见药物作用反应。\n \n- **汗腺反应**:18–24小时可见,30小时后消失。\n \n\n---\n\n## 四、腐败进程(时间线)\n\n- **2–3天**:腹部尸绿、轻度膨胀。\n \n- **5–6天**:腹部膨胀显著、皮肤水泡。\n \n- **2周**:腹部极度膨胀。\n \n- **3–4周**:组织液化,五官难辨。\n \n- **数月**:尸蜡或木乃伊。\n \n- **数年**:白骨化。\n \n\n---\n\n# 总结\n\n- **短期(<48小时)**:尸冷、尸斑、尸僵为主要依据。\n \n- **中期(数日至数周)**:依赖腐败程度与昆虫学。\n \n- **长期(数月–数十年)**:尸蜡、木乃伊与白骨化作为参考。\n \n\n死亡时间的推断需**综合多种因素**:尸体现象、环境温度、衣物覆盖、胃内容物及现场条件,不能依赖单一指标。\n\n---\n", + "编程语言/Android/Linux配置安卓Gradle构建环境.md": "\n---\n\n## ⭐ 概览\n\n目标:在 Debian 12 上搭建可以 **本地编译 Android 原生 APK** 的环境,包含:\n\n- ✅ OpenJDK (推荐 17)\n \n- ✅ Android SDK 命令行工具(cmdline-tools)\n \n- ✅ Platform tools(adb)与 build-tools、platforms\n \n- ✅ 可选:NDK / CMake(用于原生 C/C++)\n \n- ✅ Gradle(用于构建)\n \n\n适用场景:CI、无 GUI 的服务器、或仅需命令行编译的开发环境。\n\n---\n\n## 🧾 前置条件\n\n- 一台运行 **Debian 12** 的机器(有 sudo 权限)\n \n- 稳定的网络(用于下载 SDK 与工具)\n \n- 建议至少 10GB 可用磁盘空间(SDK + 系统镜像可能占用)\n \n\n---\n\n## 1️⃣ 安装基础工具\n\n先更新并安装基础依赖:\n\n```bash\nsudo apt update\nsudo apt install -y git unzip wget curl zip build-essential\n```\n\n这些工具用于下载、解压、构建等。\n\n---\n\n## 2️⃣ 安装 JDK(推荐:OpenJDK 17)\n\nAndroid Gradle Plugin(AGP)对 JDK 有版本要求,JDK 17 是安全选择:\n\n```bash\nsudo apt install -y openjdk-17-jdk\n```\n\n检查版本:\n\n```bash\njava -version\n# 期望输出类似:openjdk version \"17.x\"\n```\n\n---\n\n## 3️⃣ 下载并安装 Android SDK 命令行工具\n\n去 Google 官方下载 `commandlinetools` 压缩包,或者用 wget(示例):\n\n```bash\nmkdir -p $HOME/Android/cmdline-tools\ncd $HOME/Android/cmdline-tools\nwget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O cmdline-tools.zip\nunzip cmdline-tools.zip\n# 有时解压出来的目录名是 cmdline-tools,移动或重命名为 latest:\nmv cmdline-tools latest\n```\n\n> 🔔 注意:实际下载链接和版本会随时间变化,请按需到 Android 官方网站获取最新版。\n\n---\n\n## 4️⃣ 配置环境变量(推荐写入 `~/.bashrc` 或 `~/.zshrc`)\n\n将 SDK 路径加入环境变量,保证 `sdkmanager`、`adb` 等工具可用:\n\n```bash\n# 在 ~/.bashrc 或 ~/.zshrc 添加:\nexport ANDROID_HOME=$HOME/Android\nexport ANDROID_SDK_ROOT=$ANDROID_HOME\nexport PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH\n\n# 使之生效:\nsource ~/.bashrc\n```\n\n---\n\n## 5️⃣ 使用 sdkmanager 安装常用组件\n\n通过 `sdkmanager` 安装 `platform-tools`、指定 Android 平台与 build-tools:\n\n```bash\nsdkmanager --sdk_root=$ANDROID_HOME \"platform-tools\" \"platforms;android-34\" \"build-tools;34.0.0\"\n```\n\n可选安装(若需要 NDK / CMake 编译原生代码):\n\n```bash\nsdkmanager \"ndk;26.1.10909125\" \"cmake;3.22.1\"\n```\n\n如果是自动接受许可,可以使用:\n\n```bash\nyes | sdkmanager --licenses\n```\n\n---\n\n## 6️⃣ 安装 Gradle(可选:系统级)\n\nAndroid 项目通常随 Gradle Wrapper(`gradlew`)一起提供,能自动下载合适版本。但若想系统安装:\n\n```bash\nwget https://services.gradle.org/distributions/gradle-8.7-bin.zip -P /tmp\nsudo unzip -d /opt/gradle /tmp/gradle-8.7-bin.zip\n# 添加到 PATH(写入 ~/.bashrc):\nexport PATH=/opt/gradle/gradle-8.7/bin:$PATH\n```\n\n检查:\n\n```bash\ngradle -v\n```\n\n---\n\n## 7️⃣ 创建或获取一个示例 Android 项目并编译\n\n如果你已经有一个项目,进入项目目录并使用 Gradle Wrapper:\n\n```bash\n# 如果项目有 gradlew:\n./gradlew assembleDebug\n\n# 编译成功后 APK 通常位于:\napp/build/outputs/apk/debug/app-debug.apk\n```\n\n如果想新建一个空项目,可先使用 Android Studio 在本地创建(GUI 更方便),或直接从 GitHub 上的模板克隆一个样例工程。\n\n---\n\n## 8️⃣ 将 APK 部署到设备或模拟器(可选)\n\n- 真机(需开启 USB 调试):\n \n\n```bash\nadb install -r app/build/outputs/apk/debug/app-debug.apk\n```\n\n- 模拟器:需要安装 emulator 与系统镜像(`system-images`),并创建 AVD。命令行使用 `avdmanager` / `emulator`。\n \n\n---\n\n## 9️⃣ 常见问题 & 排查建议 ❗\n\n- `sdkmanager` 找不到:确认 PATH 是否包含 `$ANDROID_HOME/cmdline-tools/latest/bin`。\n \n- `java` 版本不对:Gradle/AGP 可能需要特定 JDK 版本,查看项目 `gradle.properties` / `build.gradle` 推荐的版本。\n \n- 下载慢或失败:考虑使用代理或镜像(国内网络环境常见)。\n \n- 权限问题:若在 `/opt` 等系统目录解压安装,需 `sudo`。\n \n\n---\n\n## 🔁 推荐一键脚本(示例)\n\n下面给出一个**示例脚本**的框架(**请先审阅再运行**,并根据需要改版本号):\n\n```bash\n#!/usr/bin/env bash\nset -e\n\n# 安装基础工具\nsudo apt update\nsudo apt install -y git unzip wget curl zip build-essential openjdk-17-jdk\n\n# 目录\nSDK_ROOT=$HOME/Android\nmkdir -p $SDK_ROOT/cmdline-tools\ncd $SDK_ROOT/cmdline-tools\n\n# 下载命令行工具(请确认链接是否过期)\nwget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O cmdline-tools.zip\nunzip -o cmdline-tools.zip\nmv cmdline-tools latest || true\n\n# 环境变量(仅本次会话)\nexport ANDROID_HOME=$SDK_ROOT\nexport PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH\n\n# 安装 SDK 组件\nyes | sdkmanager --sdk_root=$ANDROID_HOME \"platform-tools\" \"platforms;android-34\" \"build-tools;34.0.0\"\n\necho \"安装完成,请将下列行加入你的 ~/.bashrc 或 ~/.zshrc:\"\necho \"export ANDROID_HOME=\\$HOME/Android\"\necho \"export PATH=\\$ANDROID_HOME/cmdline-tools/latest/bin:\\$ANDROID_HOME/platform-tools:\\$PATH\"\n```\n\n---\n\n## 🔗 参考 & 延伸阅读\n\n- Android 官方开发者网站(SDK / command line tools)\n \n- Gradle 官方文档\n \n- Android NDK 文档(若使用原生 C/C++)\n \n\n> 上面链接建议直接在浏览器打开 Android 官方站点获取最新版工具和镜像。\n\n---\n\n## ✅ 小结\n\n在 Debian 12 上搭建 Android 原生构建环境的要点:\n\n- 安装合适的 **JDK(推荐 17)**\n \n- 下载并配置 **Android SDK command-line tools**,并通过 `sdkmanager` 安装 `platform-tools`、`platforms` 与 `build-tools`\n \n- 使用项目自带的 **Gradle Wrapper (`gradlew`)** 进行构建,必要时可系统安装 Gradle\n \n- 如需本地编译原生代码,记得安装 **NDK / CMake**\n \n\n---\n", + "编程语言/Android/安卓Gradle构建常用命令总结.md": "\n\n##### **基础**\n\n- `./gradlew tasks` \n 列出可用的 Gradle 任务(查看当前项目能跑什么任务)。\n \n- `./gradlew dependencies` \n 列出项目依赖树(排查依赖冲突很有用)。\n \n- `./gradlew clean` \n 清理构建产物(删除 `build/` 目录)。\n \n\n##### **构建 APK / AAB**\n\n- `./gradlew assembleDebug` \n 构建 debug APK(输出:`app/build/outputs/apk/debug/*.apk`)。\n \n- `./gradlew assembleRelease` \n 构建 release APK(需签名配置,否则生成 unsigned apk)。\n \n- `./gradlew bundleRelease` \n 生成 AAB(Android App Bundle),输出:`app/build/outputs/bundle/release/*.aab`。\n \n- `./gradlew bundleDebug` \n 生成 debug bundle(少用,通常用于测试)。\n \n\n##### **按 module / productFlavor / buildType 构建**\n\n- `./gradlew :moduleName:assembleRelease` \n 构建指定 module(多模块项目时用)。\n \n- `./gradlew assembleFlavorNameRelease` \n 构建指定 flavor + buildType(例如 `assemblePaidRelease`)。\n \n\n##### **安装与卸载**\n\n- `./gradlew installDebug` \n 将 debug APK 安装到连接的设备/模拟器(需要 adb 可用)。\n \n- `./gradlew uninstallDebug` \n 从设备卸载 debug 包。\n \n- 如果用生成的 APK 手动安装:`adb install -r app/build/outputs/apk/debug/app-debug.apk`\n \n\n##### **测试**\n\n- 单元测试(JVM):`./gradlew test` 或 `./gradlew testDebugUnitTest`\n \n- 仪器/设备测试(connected devices):`./gradlew connectedAndroidTest` 或 `./gradlew connectedCheck`\n \n\n##### **静态检查 / 报表**\n\n- `./gradlew lint` 或 `./gradlew lintDebug` \n 运行 Android Lint。\n \n- `./gradlew signingReport` \n 输出签名信息(SHA1/SHA256),常用于配置 API key(Google/Firebase)。\n \n\n##### **调试构建问题的常用参数**\n\n- `--stacktrace` / `--full-stacktrace`:打印堆栈跟踪(排错用)\n \n- `--info` / `--debug`:更详细的日志级别\n \n- `--scan`:生成构建扫描(需要网络,便于深入分析)\n \n- `--no-daemon`:不使用 Gradle daemon(CI 时有时会用)\n \n- `--parallel`:并行构建模块(能加速多模块项目)\n \n- `-x test`:跳过测试(例如 `./gradlew assembleRelease -x test`)\n \n- `--offline`:离线构建(只用缓存依赖)\n \n- `--refresh-dependencies`:刷新依赖缓存\n \n\n##### **性能 / CI 常用组合示例**\n\n- 本地快速一把:`./gradlew clean assembleDebug --parallel --info`\n \n- CI (不使用 daemon,输出详细):`./gradlew clean assembleRelease --no-daemon --stacktrace -x test`\n \n- 只构建 moduleA 的 release:`./gradlew :moduleA:assembleRelease`\n \n\n##### **常见路径**\n\n- APK:`app/build/outputs/apk//...`\n \n- AAB:`app/build/outputs/bundle//...`\n \n- 临时构建缓存:`~/.gradle/caches/`\n \n\n##### **小贴士**\n\n- 始终用项目里的 Gradle Wrapper(`./gradlew`),保证 Gradle 版本一致。\n \n- Release 构建需要正确的 `signingConfig`(通常放在 `gradle.properties` + `build.gradle`),也可以在 CI 用 `-P` 传参数(注意不要把敏感信息放在日志里)。\n \n- 出问题先加 `--stacktrace --info` 看详情,再定位是依赖、ProGuard/R8、签名还是资源冲突。\n", + "编程语言/C/C 代码概述:检查特定条件的素数.md": "# C 代码概述:检查特定条件的素数\r\n\r\n## 功能描述\r\n该程序对给定的整数范围内的每个整数进行检查,计算一个特定的函数,并判断该函数的结果是否为素数。\r\n\r\n## 主要组成部分\r\n\r\n### 1. `is_prime` 函数\r\n- **输入**: 一个整数 `n`\r\n- **输出**: 如果 `n` 是素数,返回 `1`,否则返回 `0`。\r\n- **逻辑**:\r\n - 如果 `n` 小于或等于 1,返回 `0`。\r\n - 通过循环检查从 `2` 到 `√n` 的所有整数,判断 `n` 是否可被整除。\r\n \r\n### 2. `main` 函数\r\n- **输入**: 从标准输入读取两个整数 `x` 和 `y`,直到输入为 `0 0`。\r\n- **逻辑**:\r\n - 使用 `x` 和 `y` 定义的范围内进行迭代。\r\n - 计算 `f = i * i + i + 41`。\r\n - 调用 `is_prime` 函数检查 `f` 是否为素数:\r\n - 如果发现任意 `f` 不是素数,输出 `\"Sorry\"` 并停止进一步检查。\r\n - 如果所有 `f` 都是素数,最终输出 `\"OK\"`。\r\n\r\n## 使用示例\r\n- **输入**:\r\n ```\r\n 1 5\r\n 0 0\r\n ```\r\n- **输出**:\r\n ```\r\n Sorry\r\n ```\r\n\r\n## 注意事项\r\n- 如果输入为 `0 0`,程序会终止。\r\n- 当范围内某个 `f` 不是素数时,输出 `\"Sorry\"`,并不再继续检查后续数字。\r\n\r\n\r\n\r\n\r\n\r\n```c\r\n#include \r\n\r\nint is_prime(int n) {\r\n if (n <= 1) return 0; \r\n for (int i = 2; i * i <= n; i++) {\r\n if (n % i == 0) return 0; \r\n }\r\n return 1; \r\n}\r\n\r\nint main() {\r\n int x, y;\r\n \r\n\r\n while (scanf(\"%d %d\", &x, &y) != EOF) {\r\n if (x == 0 && y == 0) break; \r\n \r\n int all_prime = 1; \r\n\r\n for (int i = x; i <= y; i++) {\r\n int f = i * i + i + 41; \r\n if (!is_prime(f)) { \r\n all_prime = 0; \r\n printf(\"Sorry\\n\");\r\n break; \r\n }\r\n }\r\n\r\n if (all_prime) {\r\n printf(\"OK\\n\"); \r\n }\r\n }\r\n \r\n return 0;\r\n}\r\n\r\n```\r\n\r\n", + "编程语言/C/C语言不设置临时变量交换x和y的值(方法).md": "# C语言不设置临时变量交换x和y的值(方法)\r\n\r\n```c\r\n#include \r\n//异或\r\nint main() {\r\n int x = 10, y = 20;\r\n x = x ^ y;\r\n y = x ^ y;\r\n x = x ^ y;\r\n printf(\"x的值为:%d,y的值为:%d\\n\", x, y);\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n```c\r\n#include \r\n\r\nint main() {\r\n int x = 10, y = 20;\r\n x = x + y;\r\n y = x - y;\r\n x = x - y;\r\n printf(\"x的值为:%d,y的值为:%d\\n\", x, y);\r\n return 0;\r\n}\r\n\r\n```\r\n\r\n", + "编程语言/C++/C++中的语法糖.md": "C++中有不少语法糖,以下是一些常见的例子:\n \n范围-based for循环\n \n传统的 for 循环遍历容器需要使用迭代器,较为繁琐。范围 - based for循环则更简洁,例如:\n \n#include \n#include \n\nint main() {\n std::vector v = {1, 2, 3, 4, 5};\n for (int num : v) {\n std::cout << num << \" \";\n }\n return 0;\n}\n \n \n初始化列表\n \n可以使用花括号初始化列表来初始化对象或容器,例如:\n \n#include \n#include \n\nint main() {\n // 用初始化列表初始化vector\n std::vector v = {1, 2, 3, 4, 5};\n // 用初始化列表初始化自定义类对象\n class MyClass {\n public:\n int num;\n MyClass(int n) : num(n) {}\n };\n MyClass obj{10};\n std::cout << obj.num << std::endl;\n return 0;\n}\n \n \nauto关键字\n \n auto 关键字让编译器根据初始化表达式自动推导变量的类型,减少了类型声明的冗长,例如:\n \n#include \n#include \n\nint main() {\n std::vector v = {1, 2, 3, 4, 5};\n // 使用auto自动推导迭代器类型\n for (auto it = v.begin(); it!= v.end(); ++it) {\n std::cout << *it << \" \";\n }\n return 0;\n}\n \n \n模板别名\n \n通过 using 关键字定义模板别名,简化复杂的模板类型定义,例如:\n \n#include \n#include \n#include \n\nint main() {\n // 定义模板别名\n using MyMap = std::map;\n MyMap myMap;\n myMap[\"key\"] = 10;\n std::cout << myMap[\"key\"] << std::endl;\n return 0;\n}", + "编程语言/C++/C++关联文件.md": "### 源文件\r\n\r\n- **.cpp 或 .cxx 或 .cc :**C++源文件的扩展名,用于编写C++代码,包含函数、类、变量等定义和实现。\r\n- **.h 或 .hpp 或 .hxx :**头文件扩展名,用于声明函数原型、类定义、常量和变量等,以便在多个源文件中共享声明。\r\n\r\n### 项目和配置文件\r\n\r\n- **.vcxproj :**Visual C++项目文件,用于Visual Studio开发环境,包含项目的配置信息、源文件列表、引用等。\r\n- **.sln :**解决方案文件,用于组织多个相关的项目,包含项目之间的依赖关系等信息。\r\n- **CMakeLists.txt :**使用CMake构建系统时的项目配置文件,用于描述项目的源文件、目标、依赖等信息,可生成不同平台和编译器的项目文件。\r\n- **Makefile :**在Unix和类Unix系统中,用于定义编译规则和目标,指定源文件如何编译链接成可执行文件或库。\r\n\r\n### 库文件\r\n\r\n- **.lib :**Windows下的静态库文件,包含已编译的代码和数据,在链接时被直接复制到可执行文件中。\r\n- **.a :**Unix和类Unix系统下的静态库文件,作用与Windows下的 .lib 类似。\r\n- **.dll :**Windows下的动态链接库文件,包含可在运行时被加载和调用的代码和数据。\r\n- **.so :**Unix和类Unix系统下的共享库文件,类似于Windows的 .dll ,在运行时动态链接。\r\n\r\n### 可执行文件\r\n\r\n- **.exe :**Windows下的可执行文件,是编译链接后的最终产物,可在操作系统中直接运行。\r\n- 在Unix和类Unix系统中,可执行文件没有特定的扩展名,但通常具有可执行权限,通过命令行或图形界面启动。", + "编程语言/C++/C++模拟考试.md": "\r\n# 计算机二级 C++ 试题\r\n\r\n**考试时间:120 分钟** \r\n**满分:100 分**\r\n\r\n> **说明:** \r\n> 本试卷不涉及模板和智能指针,重点考查面向对象编程和简单算法的编程能力。\r\n\r\n---\r\n\r\n## 一、选择题 (共10题,每题2分,共20分)\r\n\r\n1. 关于 C++ 的面向对象特性,下列描述正确的是: D\r\n A. 封装使得数据与对数据的操作组合在一起 \r\n B. 继承支持代码复用 \r\n C. 多态允许同一操作在不同对象上表现出不同的行为 \r\n D. 以上全部\r\n\r\n2. 在 C++ 中,class的默认访问权限是: C\r\n A. public \r\n B. protected \r\n C. private \r\n D. 无默认权限\r\n\r\n3. 当类中存在虚函数时,运行时调用哪个函数版本取决于: A\r\n A. 指针或引用所指对象的实际类型 \r\n B. 指针或引用的类型 \r\n C. 编译时绑定 \r\n D. 函数的参数列表\r\n\r\n4. 如果希望禁止类对象的拷贝,通常的做法是: C\r\n A. 不提供拷贝构造函数和赋值运算符 \r\n B. 将拷贝构造函数和赋值运算符声明为私有 \r\n C. 使用 const 修饰所有成员变量 \r\n D. 以上都不正确\r\n\r\n5. 在 C++ 中,struct的默认访问权限是: A\r\n A. public \r\n B. protected \r\n C. private \r\n D. 无默认权限\r\n\r\n6. 以下哪条语句正确包含了 iostream 头文件? C\r\n A. `#import ` \r\n B. `#include iostream` \r\n C. `#include ` \r\n D. `using namespace std;` \r\n\r\n7. 在 C++ 中,下列哪个运算符用于获取变量的地址? A\r\n A. & \r\n B. * \r\n C. -> \r\n D. % \r\n\r\n8. 以下哪一项是正确的函数声明? B\r\n A. `int func(int a, b);` \r\n B. `int func(int a, int b);` \r\n C. `func(int a, int b);` \r\n D. `int func(a, b);` \r\n\r\n9. 下列选项中,哪一个不是 C++ 的访问控制符? D\r\n A. public \r\n B. private \r\n C. protected \r\n D. external \r\n\r\n10. 关于 C++ 中的引用,以下说法正确的是: A\r\n A. 引用必须在定义时初始化 \r\n B. 引用可以改变绑定的对象 \r\n C. 引用可以为 NULL \r\n D. 引用占用额外的内存空间 \r\n\r\n---\r\n\r\n## 二、填空题 (共4题,每题2.5分,共10分)\r\n\r\n1. C++ 的面向对象三大特性是封装、______继承__ 和多态。 \r\n \r\n2. 成员函数在类外定义时需要使用 ______::__ 运算符指定其所属的类。 \r\n \r\n3. 如果一个函数在基类中声明为虚函数,那么在派生类中重写该函数时可以选择在函数声明后加上 ______override__ 关键字以提高代码可读性。 \r\n \r\n4. 递归算法必须包含一个或多个 ______终止__ 条件,以确保递归能够终止。 \r\n\r\n---\r\n\r\n\r\n\r\n---\r\n\r\n## 三、代码分析题 (共2题,每题10分,共20分)\r\n\r\n\r\n### 题目1\r\n\r\n阅读下面的代码,并回答问题:\r\n\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\nvoid modifyPointer(int *p) {\r\n *p = 20;\r\n}\r\n\r\nint main() {\r\n int a = 10;\r\n int *ptr = &a;\r\n \r\n modifyPointer(ptr);\r\n \r\n cout << a << endl;\r\n \r\n return 0;\r\n}\r\n```\r\n1.程序的输出结果是什么?20\r\n2.解释指针 ptr 在 modifyPointer 函数调用过程中的作用,以及它对变量 a 的影响。指向a的地址 修改a的值\r\n\r\n\r\n### 题目2\r\n\r\n阅读下面的代码,并回答问题:\r\n\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\nclass A {\r\npublic:\r\n A() {\r\n cout << \"A Constructor\" << endl;\r\n }\r\n ~A() {\r\n cout << \"A Destructor\" << endl;\r\n }\r\n};\r\n\r\nclass B : public A {\r\npublic:\r\n B() {\r\n cout << \"B Constructor\" << endl;\r\n }\r\n ~B() {\r\n cout << \"B Destructor\" << endl;\r\n }\r\n};\r\n\r\nint main() {\r\n B obj;\r\n return 0;\r\n}\r\n```\r\n1.程序的输出结果是什么?\r\n\r\nA Constructor\r\n\r\nB Constructor\r\n\r\nB Destructor\r\n\r\nA Destructor\r\n\r\n2.解释下子类与父类的构造、析构函数的调用顺序。子类构造过了父类,子类析构过了父类\r\n\r\n## 四、编程题 (共3题,共40分)\r\n\r\n### 题目:基于继承与多态的学生管理系统设计 — 10分\r\n\r\n**要求:** \r\n- 定义一个基类 `Person`,包含下列内容:\r\n - **保护成员**:姓名(`string`)\r\n - 构造函数:用于初始化姓名\r\n - **虚函数** `display()`:用于输出人员的基本信息\r\n- 定义一个派生类 `Student`,继承自 `Person`,并添加下列私有成员:\r\n - 学号(`int`)\r\n - 成绩(`float`)\r\n- 在 `Student` 类中,重写基类中的 `display()` 函数,输出学生的姓名、学号和成绩。\r\n- 在 `main()` 函数中,创建至少两个 `Student` 对象,并使用基类 `Person` 类型的指针调用 `display()` 函数,体现虚函数的多态特性。\r\n- 注意:请确保在基类中定义虚析构函数,以便正确释放派生类对象,请填充下面的代码实现。\r\n\r\n**示例代码:**\r\n```cpp\r\n#include \r\n#include \r\nusing namespace std;\r\n\r\n// 基类 Person,包含姓名和虚函数 display()\r\nclass Person {\r\n protected:\r\n string name;\r\n public:\r\n\r\n Person(string n, int i, float g){\r\n name = n;\r\n }\r\n\r\n virtual void display(){\r\n\r\n }\r\n};\r\n\r\n// 派生类 Student,继承自 Person,并添加学号和成绩\r\nclass Student :public Person {\r\n private:\r\n int id;\r\n float grade;\r\n\r\n public:\r\n Student(string n,int i,float g) override{\r\n name =n;\r\n id = i;\r\n grade = g;\r\n }\r\n\r\n virtual void display() override{\r\n cout<<\"学生的姓名:\"<display();\r\n p2->display();\r\n\r\n // 释放内存\r\n delete p1;\r\n delete p2;\r\n \r\n return 0;\r\n}\r\n```\r\n\r\n\r\n---\r\n\r\n### 题目2:递归实现二分查找 — 20分\r\n\r\n**要求:** \r\n- 编写一个 C++ 程序,使用递归实现二分查找算法,在一个有序的整数数组中查找目标值。 \r\n- 程序应要求用户输入一个目标值,若目标值存在,则输出其在数组中的下标;否则输出 -1。 \r\n- 代码中应包含对输入数据的提示以及对边界条件的合理判断。\r\n\r\n**示例代码:**\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\n// 递归实现二分查找函数 请你填充此函数实现\r\nint binarySearch(int arr[], int left, int right, int target) {\r\n while (left<=right){\r\n int mid = left + (right-left)/2;\r\n if(arr[mid]==target){\r\n return mid;\r\n }else if(arr[mid]> target;\r\n \r\n int index = binarySearch(arr, 0, n - 1, target);\r\n if(index != -1) {\r\n cout << \"目标值 \" << target << \" 在数组中的下标为:\" << index << endl;\r\n } else {\r\n cout << \"目标值 \" << target << \" 不在数组中。\" << endl;\r\n }\r\n return 0;\r\n}\r\n```\r\n\r\n---\r\n\r\n### 题目3:冒泡排序实现 — 10分\r\n\r\n**要求:** \r\n- 编写一个 C++ 程序,定义一个整数数组,对数组进行冒泡排序。\r\n- 程序应先输出排序前的数组,再输出排序后的数组。\r\n- 代码要求体现出对冒泡排序核心思想的理解,结构清晰、注释明确,并注意边界情况的处理。\r\n\r\n**示例代码:**\r\n```cpp\r\n#include \r\nusing namespace std;\r\n\r\n// 冒泡排序函数 请你填充这个函数\r\nvoid bubbleSort(int arr[], int n) {\r\n for(int i=0;iarr[j+1]){\r\n swap(arr[j],arr[j+1]);\r\n }\r\n }\r\n}\r\n\r\n// 打印数组函数\r\nvoid printArray(const int arr[], int n) {\r\n for (int i = 0; i < n; i++) {\r\n cout << arr[i] << \" \";\r\n }\r\n cout << endl;\r\n}\r\n\r\nint main() {\r\n int arr[] = { 5, 3, 8, 6, 2, 7, 4, 1 };\r\n int n = sizeof(arr) / sizeof(arr[0]);\r\n \r\n cout << \"排序前的数组:\" << endl;\r\n printArray(arr, n);\r\n \r\n bubbleSort(arr, n);\r\n \r\n cout << \"排序后的数组:\" << endl;\r\n printArray(arr, n);\r\n \r\n return 0;\r\n}\r\n```\r\n\r\n\r\n**注意事项:** \r\n- 请仔细阅读每道题目的要求,确保在答题时详细阐述思路及关键实现步骤。 \r\n- 编程题请在本地编译测试确保代码正确无误。 \r\n\r\n祝各位考生考试顺利!", + "编程语言/C++/C语言学习笔记.md": "## C语言学习笔记\r\n\r\n1.scanf()不能输入空格,用fgets可以解决这个问题,但fgets需要对回车进行处理\r\n\r\n```c\r\n // 读取输入字符串\r\n fgets(str, 81, stdin);\r\n\r\n // 去除输入字符串中的换行符\r\n int len = strlen(str);\r\n if (str[len - 1] == '\\n') {\r\n str[len - 1] = '\\0';\r\n }\r\n```\r\n\r\n", + "编程语言/C++/值传递和地址传递的区别.md": "在编程中,函数调用时的数据传递方式主要分为值传递和地址传递(也称为引用传递,在 C++ 中还有引用类型专门用于引用传递),下面详细介绍它们的区别:\r\n\r\n### 基本概念\r\n- **值传递**:在函数调用时,将实际参数的值复制一份传递给形式参数。函数内部对形式参数的修改不会影响到实际参数。\r\n- **地址传递**:在函数调用时,将实际参数的内存地址传递给形式参数。函数内部通过该地址可以直接访问和修改实际参数所指向的内存空间中的值。\r\n\r\n### 语法示例\r\n以下是 C++ 语言中值传递和地址传递的示例代码:\r\n```cpp\r\n#include \r\n\r\n// 值传递函数\r\nvoid valuePass(int num) {\r\n num = num + 1;\r\n std::cout << \"Inside valuePass, num: \" << num << std::endl;\r\n}\r\n\r\n// 地址传递函数(使用指针)\r\nvoid addressPass(int* numPtr) {\r\n *numPtr = *numPtr + 1;\r\n std::cout << \"Inside addressPass, *numPtr: \" << *numPtr << std::endl;\r\n}\r\n\r\nint main() {\r\n int value = 10;\r\n\r\n // 值传递调用\r\n std::cout << \"Before valuePass, value: \" << value << std::endl;\r\n valuePass(value);\r\n std::cout << \"After valuePass, value: \" << value << std::endl;\r\n\r\n // 地址传递调用\r\n std::cout << \"Before addressPass, value: \" << value << std::endl;\r\n addressPass(&value);\r\n std::cout << \"After addressPass, value: \" << value << std::endl;\r\n\r\n return 0;\r\n}\r\n```\r\n### 区别分析\r\n\r\n#### 1. 数据复制情况\r\n- **值传递**:会创建实际参数的副本,将副本传递给函数。这意味着在函数内部操作的是这个副本,而不是原始数据。例如上述代码中,`valuePass` 函数接收到的 `num` 是 `value` 的一个副本,对 `num` 的修改不会影响到 `main` 函数中的 `value`。\r\n- **地址传递**:不会复制实际参数的值,而是传递实际参数的地址。函数内部通过该地址直接访问和操作原始数据。如 `addressPass` 函数接收到的是 `value` 的地址,通过解引用操作可以直接修改 `value` 的值。\r\n\r\n#### 2. 内存开销\r\n- **值传递**:由于需要复制实际参数的值,对于大型数据结构(如大数组、大对象),会占用额外的内存空间,增加内存开销。\r\n- **地址传递**:只传递地址,无论实际参数的数据量多大,传递的地址通常只占用固定大小的内存空间(如在 32 位系统上指针通常占 4 字节,64 位系统上占 8 字节),内存开销较小。\r\n\r\n#### 3. 对实际参数的影响\r\n- **值传递**:函数内部对形式参数的修改不会影响到实际参数。在上述代码中,`valuePass` 函数执行完后,`main` 函数中的 `value` 值保持不变。\r\n- **地址传递**:函数内部对形式参数所指向的内存空间的修改会直接影响到实际参数。在 `addressPass` 函数中修改 `*numPtr` 的值,实际上就是修改了 `main` 函数中 `value` 的值。\r\n\r\n#### 4. 函数调用的安全性\r\n- **值传递**:由于函数内部操作的是副本,不会意外修改原始数据,因此在某些情况下可以保证数据的安全性。例如,当你不希望函数修改原始数据时,使用值传递是一个好选择。\r\n- **地址传递**:如果函数内部不小心对指针进行了错误的操作,可能会导致原始数据被意外修改,甚至可能引发内存错误(如空指针解引用、越界访问等)。\r\n\r\n#### 5. 代码可读性和可维护性\r\n- **值传递**:函数的行为相对简单,容易理解,因为它不会影响外部的实际参数。调用者可以清楚地知道函数内部不会修改传入的数据。\r\n- **地址传递**:使用地址传递可以在函数内部修改外部数据,这在某些情况下可以使代码更加简洁,但也可能会增加代码的复杂度,需要调用者更加小心地处理。", + "编程语言/C++/变量使用set,get方法原因.md": "在面向对象编程中,不直接修改变量而使用get和set函数(通常称为访问器和修改器方法)有以下几个重要原因:\n \n数据封装\n \n- 将变量(通常称为成员变量或属性)通过get和set函数封装起来,可以隐藏类的内部实现细节。外部代码只能通过这些函数来访问和修改属性,而无法直接操作,这样可以避免外部代码对内部数据的随意访问和修改,增强了类的独立性和安全性。\n \n数据验证\n \n- 在set函数中,可以对要设置的值进行合法性验证。例如,一个表示人的年龄的属性,在set函数中可以添加逻辑来确保设置的年龄是一个合理的数值,防止出现负数或过大的不合理值,从而保证数据的完整性和正确性。\n \n控制访问权限\n \n- 通过get和set函数,可以更精确地控制对属性的访问权限。可以将某些属性设置为只读(只有get函数,没有set函数),或者只允许在特定条件下进行修改,这样可以更好地满足不同的业务需求。\n \n实现代码复用\n \n- 当需要对属性的访问或修改进行一些额外的操作时,比如记录属性的访问日志、在属性值变化时触发其他相关的操作等,只需要在get和set函数中添加相应的代码,而不需要在所有访问该属性的地方都进行修改,提高了代码的可维护性和复用性。\n \n便于代码扩展和维护\n \n- 如果未来需要对属性的存储方式或访问逻辑进行修改,只需要在get和set函数内部进行修改,而不会影响到外部调用代码,使得代码的扩展性和维护性更好。", + "编程语言/C++/多个set方法.md": "当变量有多种 set 方法时,可以通过以下几种方式来处理:\n \n方法重载\n \n在支持方法重载的编程语言中,如Java、C#等,可以定义多个同名的 set 方法,但参数列表不同。例如,一个 set 方法可以接受一个整数参数来设置变量,另一个 set 方法可以接受一个字符串参数并根据字符串的内容来设置变量。\n \njava\n \npublic class MyClass {\n private int myVariable;\n\n public void setMyVariable(int value) {\n myVariable = value;\n }\n\n public void setMyVariable(String value) {\n myVariable = Integer.parseInt(value);\n }\n}\n \n \n不同的方法名\n \n如果方法的功能差异较大,也可以使用不同的方法名来表示不同的设置方式。比如,一个方法用于从文件中读取值来设置变量,另一个方法用于从网络获取值来设置变量,可以分别命名为 setVariableFromFile 和 setVariableFromNetwork 。\n \n使用参数标志或枚举\n \n可以在 set 方法中使用参数标志或枚举类型来区分不同的设置方式。例如,定义一个枚举类型来表示设置变量的不同来源,然后在 set 方法中根据传入的枚举值来执行不同的设置逻辑。\n \njava\n \npublic class MyClass {\n private int myVariable;\n\n public enum SetSource {\n FROM_FILE, FROM_NETWORK\n }\n\n public void setMyVariable(int value, SetSource source) {\n if (source == SetSource.FROM_FILE) {\n // 从文件设置变量的逻辑\n myVariable = value;\n } else if (source == SetSource.FROM_NETWORK) {\n // 从网络设置变量的逻辑\n myVariable = value;\n }\n }\n}\n \n \n这样可以根据不同的需求灵活选择合适的方式来设置变量,同时保持代码的清晰和可维护性。", + "编程语言/C++/指针变量的区别.md": "在C和C++语言中,`int* a` 和 `int *a` 本质上没有区别,它们都表示定义了一个指向 `int` 类型数据的指针变量 `a`。以下是关于它们的详细说明:\r\n\r\n- **从语法角度看**:这两种写法都是合法的C和C++ 语法,用于声明一个指针变量。`*` 是指针声明符,用来表示后面的变量是一个指针。在这两种写法中,`*` 都与变量名 `a` 结合,表示 `a` 是一个指针,它可以存储一个 `int` 类型数据的内存地址。\r\n- **从阅读习惯和风格角度看**\r\n - `int* a`:这种写法将 `*` 紧跟在类型名 `int` 后面,强调 `*` 是类型的一部分,即 `int*` 被视为一个整体,表示“指向 `int` 的指针”类型。这种写法在一些代码风格中更受欢迎,因为它使代码看起来更紧凑,类型定义更清晰,特别是在同时声明多个指针变量时,如 `int* a, *b, *c;`,可以很直观地看出 `a`、`b`、`c` 都是 `int` 型指针。\r\n - `int *a`:这种写法将 `*` 靠近变量名 `a`,更加强调 `a` 是一个指针变量,`*` 是用来修饰 `a` 的。有些程序员更喜欢这种写法,因为它更突出了变量的性质是指针,在阅读代码时,更容易将注意力集中在变量 `a` 本身是一个指针这一事实上。\r\n\r\n虽然在功能上没有区别,但在实际使用中,可能会根据个人或团队的编程习惯和代码风格来选择使用哪种形式。需要注意的是,在同时声明多个变量时,如果采用 `int* a, b;` 的形式,会让人误以为 `b` 也是 `int` 型指针,但实际上 `b` 是一个普通的 `int` 型变量。为了避免这种混淆,更清晰的做法是每个指针变量都单独声明,如 `int* a; int* b;` 或者都采用 `int *a; int *b;` 的形式。\r\n", + "编程语言/C++/指针简单讲解.md": "下面将详细介绍指针的核心内容,包括指针声明、指针运算、指针与数组的关系以及二级指针,并结合代码示例和内存图进行说明。\r\n\r\n### 1. 指针声明:`int *p` 的正确写法\r\n\r\n在 C 和 C++ 中,指针声明的语法是 `数据类型 *指针变量名`。`int *p` 是一个常见的声明方式,它声明了一个名为 `p` 的指针变量,该指针指向 `int` 类型的数据。以下是几种常见的写法及其含义:\r\n\r\n```c\r\n#include \r\n\r\nint main() {\r\n int num = 10;\r\n // 写法一:常见写法\r\n int *p1;\r\n p1 = #\r\n // 写法二:声明并初始化\r\n int *p2 = #\r\n\r\n printf(\"p1 指向的值: %d\\n\", *p1);\r\n printf(\"p2 指向的值: %d\\n\", *p2);\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 2. 指针运算:`p++` 在不同类型下的地址变化\r\n\r\n指针运算主要包括指针的加减操作。当对指针进行 `p++` 操作时,指针会根据其所指向的数据类型的大小向前移动相应的字节数。以下是不同类型指针 `p++` 后的地址变化示例:\r\n\r\n```c\r\n#include \r\n\r\nint main() {\r\n int arr_int[3] = {1, 2, 3};\r\n char arr_char[3] = {'a', 'b', 'c'};\r\n\r\n int *p_int = arr_int;\r\n char *p_char = arr_char;\r\n\r\n printf(\"p_int 初始地址: %p\\n\", (void *)p_int);\r\n p_int++;\r\n printf(\"p_int 自增后地址: %p\\n\", (void *)p_int);\r\n\r\n printf(\"p_char 初始地址: %p\\n\", (void *)p_char);\r\n p_char++;\r\n printf(\"p_char 自增后地址: %p\\n\", (void *)p_char);\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n在上述代码中,`int` 类型通常占 4 个字节,`char` 类型占 1 个字节。所以 `p_int++` 会使指针地址增加 4 个字节,而 `p_char++` 会使指针地址增加 1 个字节。\r\n\r\n### 3. 指针与数组:`arr[i]` 与 `*(arr + i)` 的等价性\r\n\r\n在 C 和 C++ 中,数组名本质上是一个指向数组首元素的常量指针。`arr[i]` 和 `*(arr + i)` 是完全等价的,它们都表示访问数组中第 `i` 个元素。以下是示例代码:\r\n\r\n```c\r\n#include \r\n\r\nint main() {\r\n int arr[5] = {1, 2, 3, 4, 5};\r\n\r\n // 使用 arr[i] 访问元素\r\n for (int i = 0; i < 5; i++) {\r\n printf(\"arr[%d] = %d\\n\", i, arr[i]);\r\n }\r\n\r\n // 使用 *(arr + i) 访问元素\r\n for (int i = 0; i < 5; i++) {\r\n printf(\"*(arr + %d) = %d\\n\", i, *(arr + i));\r\n }\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 4. 二级指针:画内存图理解指针的指针\r\n\r\n二级指针是指向指针的指针。通过二级指针,可以间接访问和修改另一个指针的值。以下是一个二级指针的示例代码,并给出对应的内存图解释。\r\n\r\n```c\r\n#include \r\n\r\nint main() {\r\n int num = 10;\r\n int *p = #\r\n int **pp = &p;\r\n\r\n printf(\"num 的值: %d\\n\", num);\r\n printf(\"p 指向的值: %d\\n\", *p);\r\n printf(\"pp 间接指向的值: %d\\n\", **pp);\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n#### 内存图解释\r\n\r\n```plaintext\r\n+----------------+\r\n| 内存地址 | 变量名 | 存储内容\r\n+----------------+--------+-----------------\r\n| 0x1000 | num | 10\r\n| 0x2000 | p | 0x1000 (指向 num 的地址)\r\n| 0x3000 | pp | 0x2000 (指向 p 的地址)\r\n+----------------+--------+-----------------\r\n```\r\n\r\n在这个内存图中,`num` 存储在地址 `0x1000` 处,值为 10。指针 `p` 存储在地址 `0x2000` 处,它指向 `num` 的地址 `0x1000`。二级指针 `pp` 存储在地址 `0x3000` 处,它指向 `p` 的地址 `0x2000`。通过 `*pp` 可以得到 `p` 的值(即 `num` 的地址),再通过 `**pp` 可以得到 `num` 的值。\r\n\r\n通过以上内容,你应该对指针的核心概念有了更深入的理解。指针是 C 和 C++ 中非常强大的特性,但也需要谨慎使用,避免出现内存错误。", + "编程语言/C++/暂停1s执行.md": "以下是对上述代码的美化和精简版本:\n\n### 使用 `chrono` 和 `this_thread` 库\n```cpp\n#include \n#include \n#include \n\nint main() {\n std::cout << \"开始\" << std::endl;\n // 暂停1秒\n std::this_thread::sleep_for(std::chrono::seconds(1));\n std::cout << \"暂停1秒后执行\" << std::endl;\n return 0;\n}\n```\n\n### 使用 `Sleep` 函数(Windows系统)\n```cpp\n#include \n#include \n\nint main() {\n std::cout << \"开始\" << std::endl;\n // 暂停1秒,参数为1000毫秒\n Sleep(1000);\n std::cout << \"暂停1秒后执行\" << std::endl;\n return 0;\n}\n```\n\n### 使用 `usleep` 函数(Unix/Linux系统)\n```cpp\n#include \n#include \n\nint main() {\n std::cout << \"开始\" << std::endl;\n // 暂停1秒,参数为1000000微秒\n usleep(1000000);\n std::cout << \"暂停1秒后执行\" << std::endl;\n return 0;\n}\n```\n\n这些代码的结构更加清晰,注释保留以说明关键步骤,同时移除了不必要的空行,使代码更加简洁易读。 ", + "编程语言/C++/标准库解析/algorithim库二次总结.md": "C++ 的 `` 头文件提供了许多高效的算法函数,以下是常用函数及示例:\n\n---\n\n### **1. 排序与查找**\n#### **`sort()`**:对容器排序\n```cpp\n#include \n#include \nusing namespace std;\n\nvector v = {3, 1, 4, 1, 5};\nsort(v.begin(), v.end()); // 默认升序\n// v = {1, 1, 3, 4, 5}\n\n// 自定义排序:降序\nsort(v.begin(), v.end(), greater());\n```\n\n#### **`binary_search()`**:二分查找(需已排序)\n```cpp\nif (binary_search(v.begin(), v.end(), 4)) {\n cout << \"找到4!\" << endl;\n}\n```\n\n#### **`find()`**:查找元素\n```cpp\nauto it = find(v.begin(), v.end(), 3);\nif (it != v.end()) {\n cout << \"找到3,位置:\" << it - v.begin() << endl;\n}\n```\n\n---\n\n### **2. 元素操作**\n#### **`reverse()`**:反转容器\n```cpp\nreverse(v.begin(), v.end()); // v = {5, 4, 3, 1, 1}\n```\n\n#### **`fill()`**:填充容器\n```cpp\nvector vec(5);\nfill(vec.begin(), vec.end(), 10); // 全部填充为10\n```\n\n#### **`replace()`**:替换元素\n```cpp\nreplace(v.begin(), v.end(), 1, 99); // 将所有1替换为99\n```\n\n---\n\n### **3. 条件判断**\n#### **`count()`**:统计元素出现次数\n```cpp\nint cnt = count(v.begin(), v.end(), 1);\n```\n\n#### **`count_if()`**:按条件统计\n```cpp\nint even_cnt = count_if(v.begin(), v.end(), [](int x) {\n return x % 2 == 0; // 统计偶数\n});\n```\n\n#### **`all_of()` / `any_of()`**:检查元素条件\n```cpp\nbool all_even = all_of(v.begin(), v.end(), [](int x) {\n return x % 2 == 0;\n});\n```\n\n---\n\n### **4. 数值处理**\n#### **`max_element()` / `min_element()`**:找最大/最小值\n```cpp\nauto max_it = max_element(v.begin(), v.end());\ncout << \"最大值:\" << *max_it << endl;\n```\n\n#### **`accumulate()`**:累加(需 ``)\n```cpp\n#include \nint sum = accumulate(v.begin(), v.end(), 0); // 初始值为0\n```\n\n---\n\n### **5. 变换与生成**\n#### **`transform()`**:对每个元素操作\n```cpp\nvector squared;\ntransform(v.begin(), v.end(), back_inserter(squared),\n [](int x) { return x * x; });\n```\n\n#### **`generate()`**:生成新值填充容器\n```cpp\nvector nums(5);\nint n = 0;\ngenerate(nums.begin(), nums.end(), [&n]() { return n++; });\n// nums = {0, 1, 2, 3, 4}\n```\n\n---\n\n### **6. 集合操作**\n#### **`unique()`**:去重(需先排序)\n```cpp\nsort(v.begin(), v.end());\nauto last = unique(v.begin(), v.end());\nv.erase(last, v.end()); // 删除重复项\n```\n\n#### **`merge()`**:合并两个有序序列\n```cpp\nvector v1 = {1, 3, 5}, v2 = {2, 4, 6}, result(6);\nmerge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());\n// result = {1, 2, 3, 4, 5, 6}\n```\n\n---\n\n### **7. 分区与乱序**\n#### **`partition()`**:按条件分区\n```cpp\nauto it = partition(v.begin(), v.end(),\n [](int x) { return x % 2 == 0; });\n// 偶数在前,奇数在后\n```\n\n#### **`shuffle()`**:随机打乱(需 ``)\n```cpp\n#include \nshuffle(v.begin(), v.end(), default_random_engine());\n```\n\n---\n\n### **示例代码汇总**\n```cpp\n#include \n#include \n#include \n#include \nusing namespace std;\n\nint main() {\n vector v = {3, 1, 4, 1, 5};\n \n // 排序\n sort(v.begin(), v.end());\n \n // 查找\n if (binary_search(v.begin(), v.end(), 4)) {\n cout << \"找到4!\" << endl;\n }\n \n // 累加\n int sum = accumulate(v.begin(), v.end(), 0);\n \n return 0;\n}\n```\n\n---\n\n这些函数能显著简化代码并提高效率,建议结合 C++ 文档深入学习参数和高级用法。", + "编程语言/C++/标准库解析/algorithm算法库.md": "```cpp\r\n#include \r\n#include \r\n#include // 包含所有标准算法\r\n#include // 包含数值算法,如 std::accumulate\r\n#include // 包含函数对象,如 std::greater\r\n#include // 包含迭代器工具,如 std::back_inserter\r\n#include // 用于字符串处理\r\n\r\nusing namespace std;\r\n\r\n/*\r\n * 本程序通过多个示例,详细总结和演示了C++中库的各种使用方法。\r\n * 涵盖了排序、搜索、修改、遍历、数值计算、集合操作、堆操作等常用算法。\r\n * 每个算法的使用都配有详细的注释,帮助理解其功能和应用场景。\r\n */\r\n\r\nint main() {\r\n // 初始化一个整数向量用于演示\r\n vector vec = {9, 2, 7, 4, 6, 3, 8, 1, 5};\r\n cout << \"原始向量: \";\r\n for(auto num : vec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 1. 排序算法\r\n // a. std::sort - 快速排序,默认使用<运算符\r\n vector sortVec = vec; // 复制原始向量\r\n sort(sortVec.begin(), sortVec.end());\r\n cout << \"使用 std::sort 排序后: \";\r\n for(auto num : sortVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // b. std::sort 使用自定义比较函数(降序)\r\n vector sortDescVec = vec; // 复制原始向量\r\n sort(sortDescVec.begin(), sortDescVec.end(), greater());\r\n cout << \"使用 std::sort 降序排序后: \";\r\n for(auto num : sortDescVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 2. 稳定排序算法\r\n // std::stable_sort 保持相等元素的相对顺序\r\n // 为演示稳定性,创建一对元素的向量\r\n vector> stableSortVec = {{3, 'a'}, {1, 'b'}, {2, 'c'}, {3, 'd'}, {2, 'e'}};\r\n stable_sort(stableSortVec.begin(), stableSortVec.end(),\r\n [](const pair &a, const pair &b) -> bool {\r\n return a.first < b.first;\r\n });\r\n cout << \"使用 std::stable_sort 排序后的向量 (保持相等元素的相对顺序): \";\r\n for(auto &p : stableSortVec) cout << \"{\" << p.first << \", \" << p.second << \"} \";\r\n cout << \"\\n\\n\";\r\n\r\n // 3. 搜索算法\r\n // a. std::find - 查找第一个匹配的元素\r\n auto itFind = find(vec.begin(), vec.end(), 6);\r\n if(itFind != vec.end())\r\n cout << \"使用 std::find 找到元素 6,位置索引: \" << distance(vec.begin(), itFind) << endl;\r\n else\r\n cout << \"使用 std::find 未找到元素 6\" << endl;\r\n\r\n // b. std::find_if - 查找第一个满足条件的元素\r\n auto itFindIf = find_if(vec.begin(), vec.end(), [](int x) { return x > 5; });\r\n if(itFindIf != vec.end())\r\n cout << \"使用 std::find_if 找到第一个大于5的元素: \" << *itFindIf << endl;\r\n else\r\n cout << \"使用 std::find_if 未找到满足条件的元素\" << endl;\r\n\r\n // c. std::binary_search - 在已排序范围内查找元素\r\n // 需要先对向量进行排序\r\n sort(sortVec.begin(), sortVec.end());\r\n bool foundBinary = binary_search(sortVec.begin(), sortVec.end(), 4);\r\n cout << \"使用 std::binary_search 在已排序向量中查找 4: \" \r\n << (foundBinary ? \"找到\" : \"未找到\") << endl;\r\n cout << \"\\n\";\r\n\r\n // 4. 修改算法\r\n // a. std::replace - 替换所有匹配的元素\r\n vector replaceVec = vec; // 复制原始向量\r\n replace(replaceVec.begin(), replaceVec.end(), 3, 30); // 将所有3替换为30\r\n cout << \"使用 std::replace 将3替换为30后: \";\r\n for(auto num : replaceVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // b. std::replace_if - 替换满足条件的元素\r\n replace_if(replaceVec.begin(), replaceVec.end(),\r\n [](int x) { return x > 5; }, 50); // 将所有大于5的元素替换为50\r\n cout << \"使用 std::replace_if 将所有大于5的元素替换为50后: \";\r\n for(auto num : replaceVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 5. 遍历算法\r\n // a. std::for_each - 对每个元素应用一个函数\r\n cout << \"使用 std::for_each 将向量中的每个元素乘以2: \";\r\n for_each(vec.begin(), vec.end(), [](int &x) { x *= 2; });\r\n for(auto num : vec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 6. 数值算法\r\n // a. std::accumulate - 计算元素的总和\r\n int sum = accumulate(vec.begin(), vec.end(), 0);\r\n cout << \"使用 std::accumulate 计算向量元素的总和: \" << sum << endl;\r\n\r\n // b. std::count - 计算特定元素的出现次数\r\n int countSix = count(vec.begin(), vec.end(), 6);\r\n cout << \"使用 std::count 计算元素 6 的出现次数: \" << countSix << endl;\r\n\r\n // c. std::count_if - 计算满足条件的元素数量\r\n int countGreaterTen = count_if(vec.begin(), vec.end(), [](int x) { return x > 10; });\r\n cout << \"使用 std::count_if 计算大于10的元素数量: \" << countGreaterTen << \"\\n\\n\";\r\n\r\n // 7. 集合算法\r\n // 为使用集合算法,首先需要两个已排序的向量\r\n vector setA = {1, 2, 3, 4, 5};\r\n vector setB = {4, 5, 6, 7, 8};\r\n vector setUnionVec, setIntersectionVec, setDifferenceVec, setSymDifferenceVec;\r\n\r\n // a. std::set_union - 求并集\r\n set_union(setA.begin(), setA.end(), setB.begin(), setB.end(),\r\n back_inserter(setUnionVec));\r\n cout << \"使用 std::set_union 求并集: \";\r\n for(auto num : setUnionVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // b. std::set_intersection - 求交集\r\n set_intersection(setA.begin(), setA.end(), setB.begin(), setB.end(),\r\n back_inserter(setIntersectionVec));\r\n cout << \"使用 std::set_intersection 求交集: \";\r\n for(auto num : setIntersectionVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // c. std::set_difference - 求差集 (A - B)\r\n set_difference(setA.begin(), setA.end(), setB.begin(), setB.end(),\r\n back_inserter(setDifferenceVec));\r\n cout << \"使用 std::set_difference 求 A - B 差集: \";\r\n for(auto num : setDifferenceVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // d. std::set_symmetric_difference - 求对称差集\r\n set_symmetric_difference(setA.begin(), setA.end(), setB.begin(), setB.end(),\r\n back_inserter(setSymDifferenceVec));\r\n cout << \"使用 std::set_symmetric_difference 求对称差集: \";\r\n for(auto num : setSymDifferenceVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 8. 复制算法\r\n // a. std::copy - 复制元素到另一个容器\r\n vector copyVec;\r\n copy(vec.begin(), vec.end(), back_inserter(copyVec));\r\n cout << \"使用 std::copy 复制 vec 到 copyVec: \";\r\n for(auto num : copyVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // b. std::copy_if - 复制满足条件的元素\r\n vector copyIfVec;\r\n copy_if(vec.begin(), vec.end(), back_inserter(copyIfVec),\r\n [](int x) { return x % 2 == 0; }); // 复制偶数\r\n cout << \"使用 std::copy_if 复制偶数到 copyIfVec: \";\r\n for(auto num : copyIfVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 9. 生成算法\r\n // a. std::generate - 使用生成器函数填充容器\r\n vector generateVec(5);\r\n generate(generateVec.begin(), generateVec.end(), [n = 0]() mutable { return ++n * 10; });\r\n cout << \"使用 std::generate 填充 generateVec: \";\r\n for(auto num : generateVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // b. std::generate_n - 生成指定数量的元素\r\n vector generateNVec;\r\n generate_n(back_inserter(generateNVec), 3, [n = 5]() mutable { return n += 5; });\r\n cout << \"使用 std::generate_n 填充 generateNVec: \";\r\n for(auto num : generateNVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 10. 反转和旋转算法\r\n // a. std::reverse - 反转容器中的元素\r\n vector reverseVec = vec; // 复制原始向量\r\n reverse(reverseVec.begin(), reverseVec.end());\r\n cout << \"使用 std::reverse 反转 reverseVec: \";\r\n for(auto num : reverseVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // b. std::rotate - 旋转容器中的元素\r\n // 将第三个元素旋转到开始位置\r\n rotate(vec.begin(), vec.begin() + 2, vec.end());\r\n cout << \"使用 std::rotate 将第三个元素旋转到开始位置后 vec: \";\r\n for(auto num : vec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 11. 分区算法\r\n // a. std::partition - 将容器分区,使得满足条件的元素在前\r\n vector partitionVec = {1, 4, 2, 5, 3, 6, 7, 8};\r\n auto itPartition = partition(partitionVec.begin(), partitionVec.end(),\r\n [](int x) { return x % 2 == 0; }); // 分区偶数和奇数\r\n cout << \"使用 std::partition 分区偶数和奇数后: \";\r\n for(auto num : partitionVec) cout << num << ' ';\r\n cout << \"\\n分区点后元素: \";\r\n for(auto it = itPartition; it != partitionVec.end(); ++it) cout << *it << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // b. std::stable_partition - 稳定分区,保持相对顺序\r\n vector stablePartitionVec = {1, 4, 2, 5, 3, 6, 7, 8};\r\n stable_partition(stablePartitionVec.begin(), stablePartitionVec.end(),\r\n [](int x) { return x % 2 == 0; }); // 稳定分区偶数和奇数\r\n cout << \"使用 std::stable_partition 稳定分区偶数和奇数后: \";\r\n for(auto num : stablePartitionVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 12. 最值算法\r\n // a. std::min 和 std::max - 计算两个值的最小值和最大值\r\n int a = 10, b = 20;\r\n cout << \"使用 std::min 和 std::max: min(\" << a << \", \" << b << \") = \" \r\n << min(a, b) << \", max(\" << a << \", \" << b << \") = \" << max(a, b) << endl;\r\n\r\n // b. std::min_element 和 std::max_element - 找到容器中的最小元素和最大元素\r\n auto minIt = min_element(vec.begin(), vec.end());\r\n auto maxIt = max_element(vec.begin(), vec.end());\r\n if(minIt != vec.end() && maxIt != vec.end())\r\n cout << \"使用 std::min_element 和 std::max_element: min = \" << *minIt \r\n << \", max = \" << *maxIt << \"\\n\\n\";\r\n\r\n // 13. 唯一化算法\r\n // std::unique - 移除连续重复的元素\r\n vector uniqueVec = {1, 2, 2, 3, 3, 3, 4, 4, 5};\r\n auto itUnique = unique(uniqueVec.begin(), uniqueVec.end());\r\n uniqueVec.erase(itUnique, uniqueVec.end()); // 移除重复部分\r\n cout << \"使用 std::unique 移除连续重复的元素后: \";\r\n for(auto num : uniqueVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 14. 交换算法\r\n // a. std::swap - 交换两个变量的值\r\n int x = 5, y = 10;\r\n cout << \"交换前: x = \" << x << \", y = \" << y << endl;\r\n swap(x, y);\r\n cout << \"交换后: x = \" << x << \", y = \" << y << \"\\n\\n\";\r\n\r\n // b. std::iter_swap - 交换两个迭代器指向的元素\r\n vector iterSwapVec = {1, 2, 3, 4, 5};\r\n cout << \"交换前 iterSwapVec: \";\r\n for(auto num : iterSwapVec) cout << num << ' ';\r\n cout << endl;\r\n iter_swap(iterSwapVec.begin(), iterSwapVec.end() - 1); // 交换第一个和最后一个元素\r\n cout << \"交换后 iterSwapVec: \";\r\n for(auto num : iterSwapVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 15. 堆算法\r\n // a. std::make_heap - 将向量转换为堆\r\n vector heapVec = {3, 1, 4, 1, 5, 9, 2, 6, 5};\r\n make_heap(heapVec.begin(), heapVec.end());\r\n cout << \"使用 std::make_heap 创建堆后: \";\r\n for(auto num : heapVec) cout << num << ' ';\r\n cout << \"\\n\";\r\n\r\n // b. std::push_heap - 向堆中添加元素\r\n heapVec.push_back(7); // 添加新元素\r\n push_heap(heapVec.begin(), heapVec.end());\r\n cout << \"使用 std::push_heap 添加元素7后: \";\r\n for(auto num : heapVec) cout << num << ' ';\r\n cout << \"\\n\";\r\n\r\n // c. std::pop_heap - 移除堆顶元素\r\n pop_heap(heapVec.begin(), heapVec.end()); // 将堆顶元素移动到最后\r\n int top = heapVec.back();\r\n heapVec.pop_back(); // 移除堆顶元素\r\n cout << \"使用 std::pop_heap 移除堆顶元素后: \";\r\n for(auto num : heapVec) cout << num << ' ';\r\n cout << \"\\n堆顶元素被移除: \" << top << \"\\n\";\r\n\r\n // d. std::sort_heap - 将堆排序\r\n sort_heap(heapVec.begin(), heapVec.end());\r\n cout << \"使用 std::sort_heap 将堆排序后: \";\r\n for(auto num : heapVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 16. 其他算法\r\n // a. std::all_of - 检查是否所有元素满足条件\r\n bool allPositive = all_of(vec.begin(), vec.end(), [](int x) { return x > 0; });\r\n cout << \"使用 std::all_of 检查所有元素是否大于0: \" \r\n << (allPositive ? \"是\" : \"否\") << endl;\r\n\r\n // b. std::any_of - 检查是否任何元素满足条件\r\n bool anyGreaterTwenty = any_of(vec.begin(), vec.end(), [](int x) { return x > 20; });\r\n cout << \"使用 std::any_of 检查是否有元素大于20: \" \r\n << (anyGreaterTwenty ? \"是\" : \"否\") << endl;\r\n\r\n // c. std::none_of - 检查是否所有元素都不满足条件\r\n bool noneNegative = none_of(vec.begin(), vec.end(), [](int x) { return x < 0; });\r\n cout << \"使用 std::none_of 检查是否所有元素都不小于0: \" \r\n << (noneNegative ? \"是\" : \"否\") << \"\\n\\n\";\r\n\r\n // 17. 移除和填充算法\r\n // a. std::remove - 移除所有匹配的元素(实际并未改变容器大小)\r\n vector removeVec = {1, 2, 3, 2, 4, 2, 5};\r\n auto itRemove = remove(removeVec.begin(), removeVec.end(), 2);\r\n removeVec.erase(itRemove, removeVec.end()); // 实际移除元素\r\n cout << \"使用 std::remove 移除所有2后: \";\r\n for(auto num : removeVec) cout << num << ' ';\r\n cout << \"\\n\";\r\n\r\n // b. std::remove_if - 移除满足条件的元素\r\n vector removeIfVec = {1, 2, 3, 4, 5, 6, 7, 8};\r\n auto itRemoveIf = remove_if(removeIfVec.begin(), removeIfVec.end(),\r\n [](int x) { return x % 2 == 0; }); // 移除偶数\r\n removeIfVec.erase(itRemoveIf, removeIfVec.end());\r\n cout << \"使用 std::remove_if 移除所有偶数后: \";\r\n for(auto num : removeIfVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // c. std::fill - 填充容器中的元素\r\n vector fillVec(5);\r\n fill(fillVec.begin(), fillVec.end(), 42); // 将所有元素设为42\r\n cout << \"使用 std::fill 填充 fillVec: \";\r\n for(auto num : fillVec) cout << num << ' ';\r\n cout << endl;\r\n\r\n // d. std::fill_n - 填充指定数量的元素\r\n vector fillNVec(5, 0);\r\n fill_n(fillNVec.begin(), 3, 7); // 将前三个元素设为7\r\n cout << \"使用 std::fill_n 填充 fillNVec 的前三个元素为7: \";\r\n for(auto num : fillNVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 18. 交换算法\r\n // a. std::swap_ranges - 交换两个范围内的元素\r\n vector swapRangeVec1 = {1, 2, 3, 4, 5};\r\n vector swapRangeVec2 = {10, 20, 30, 40, 50};\r\n swap_ranges(swapRangeVec1.begin(), swapRangeVec1.begin() + 3, swapRangeVec2.begin());\r\n cout << \"使用 std::swap_ranges 交换前3个元素后:\" << endl;\r\n cout << \"swapRangeVec1: \";\r\n for(auto num : swapRangeVec1) cout << num << ' ';\r\n cout << endl;\r\n cout << \"swapRangeVec2: \";\r\n for(auto num : swapRangeVec2) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 19. 删除重复元素\r\n // a. std::unique - 移除连续重复的元素\r\n vector uniqueRemoveVec = {1, 2, 2, 3, 3, 3, 4, 4, 5};\r\n auto itUniqueRemove = unique(uniqueRemoveVec.begin(), uniqueRemoveVec.end());\r\n uniqueRemoveVec.erase(itUniqueRemove, uniqueRemoveVec.end());\r\n cout << \"使用 std::unique 移除连续重复的元素后: \";\r\n for(auto num : uniqueRemoveVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 20. 重排算法\r\n // a. std::shuffle - 随机打乱元素顺序\r\n // 需要一个随机数生成器\r\n srand(time(0)); // 设置随机种子\r\n vector shuffleVec = {1, 2, 3, 4, 5, 6, 7, 8, 9};\r\n shuffle(shuffleVec.begin(), shuffleVec.end(), default_random_engine(rand()));\r\n cout << \"使用 std::shuffle 随机打乱 shuffleVec 后: \";\r\n for(auto num : shuffleVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 21. 移动算法\r\n // a. std::move - 移动元素到新容器\r\n vector moveSource = {\"one\", \"two\", \"three\"};\r\n vector moveDestination;\r\n move(moveSource.begin(), moveSource.end(), back_inserter(moveDestination));\r\n cout << \"使用 std::move 将 moveSource 移动到 moveDestination 后:\" << endl;\r\n cout << \"moveDestination: \";\r\n for(auto &str : moveDestination) cout << str << ' ';\r\n cout << endl;\r\n cout << \"moveSource (状态不确定): \";\r\n for(auto &str : moveSource) cout << str << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 22. 分割算法\r\n // std::partition_point - 找到分区点\r\n // 已经对 partitionVec 进行了分区,找到第一个不满足条件的元素\r\n auto partitionPoint = partition_point(partitionVec.begin(), partitionVec.end(),\r\n [](int x) { return x % 2 == 0; });\r\n cout << \"使用 std::partition_point 找到分区点后: \";\r\n for(auto it = partitionVec.begin(); it != partitionPoint; ++it) cout << *it << ' ';\r\n cout << \"| \";\r\n for(auto it = partitionPoint; it != partitionVec.end(); ++it) cout << *it << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 23. 逆向查找算法\r\n // a. std::find_end - 查找一个序列在另一个序列中最后一次出现的位置\r\n string text = \"hello world, hello universe\";\r\n string pattern = \"hello\";\r\n auto itFindEnd = find_end(text.begin(), text.end(),\r\n pattern.begin(), pattern.end());\r\n if(itFindEnd != text.end())\r\n cout << \"使用 std::find_end 找到最后一次 'hello' 出现的位置: \" \r\n << distance(text.begin(), itFindEnd) << endl;\r\n else\r\n cout << \"使用 std::find_end 未找到 'hello' \" << endl;\r\n\r\n // b. std::find_first_of - 查找任何一个元素出现在另一个序列中\r\n vector chars = {'x', 'y', 'z'};\r\n string sample = \"abcdefg\";\r\n auto itFindFirstOf = find_first_of(sample.begin(), sample.end(),\r\n chars.begin(), chars.end());\r\n if(itFindFirstOf != sample.end())\r\n cout << \"使用 std::find_first_of 找到第一个匹配的字符: \" << *itFindFirstOf << endl;\r\n else\r\n cout << \"使用 std::find_first_of 未找到匹配的字符\" << endl;\r\n\r\n cout << \"\\n\";\r\n\r\n // 24. 交换两个容器\r\n vector swapContainer1 = {1, 2, 3};\r\n vector swapContainer2 = {4, 5, 6, 7};\r\n cout << \"交换前 swapContainer1: \";\r\n for(auto num : swapContainer1) cout << num << ' ';\r\n cout << \"\\n交换前 swapContainer2: \";\r\n for(auto num : swapContainer2) cout << num << ' ';\r\n cout << endl;\r\n swap(swapContainer1, swapContainer2);\r\n cout << \"交换后 swapContainer1: \";\r\n for(auto num : swapContainer1) cout << num << ' ';\r\n cout << \"\\n交换后 swapContainer2: \";\r\n for(auto num : swapContainer2) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n // 25. 移除非唯一元素\r\n // 使用 std::unique 和 erase 移除所有重复元素\r\n vector duplicateVec = {1, 2, 2, 3, 4, 4, 5, 5, 5};\r\n sort(duplicateVec.begin(), duplicateVec.end()); // 先排序\r\n auto itUniqueAll = unique(duplicateVec.begin(), duplicateVec.end());\r\n duplicateVec.erase(itUniqueAll, duplicateVec.end());\r\n cout << \"使用 std::unique 移除所有重复元素后: \";\r\n for(auto num : duplicateVec) cout << num << ' ';\r\n cout << \"\\n\\n\";\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 代码详解\r\n\r\n1. **排序算法**\r\n - **`std::sort`**:使用快速排序对容器中的元素进行排序。默认情况下,按照升序排列。可以通过提供自定义比较函数改变排序顺序。\r\n - **`std::stable_sort`**:与 `std::sort` 类似,但它保持相等元素的相对顺序。这在需要稳定排序的场景中非常有用。\r\n\r\n2. **搜索算法**\r\n - **`std::find`**:在指定范围内查找第一个匹配的元素,返回指向该元素的迭代器,若未找到,则返回 `end()`。\r\n - **`std::find_if`**:查找第一个满足特定条件的元素,条件由谓词函数决定。\r\n - **`std::binary_search`**:在已排序的范围内执行二分查找,返回布尔值表示是否找到目标元素。\r\n\r\n3. **修改算法**\r\n - **`std::replace`**:将范围内所有匹配指定值的元素替换为新值。\r\n - **`std::replace_if`**:将范围内所有满足条件的元素替换为新值。\r\n\r\n4. **遍历算法**\r\n - **`std::for_each`**:对范围内的每个元素应用指定的函数或操作。在示例中,每个元素被乘以2。\r\n\r\n5. **数值算法**\r\n - **`std::accumulate`**:对范围内的元素进行累加,返回总和。\r\n - **`std::count`**:计算范围内等于特定值的元素数量。\r\n - **`std::count_if`**:计算范围内满足特定条件的元素数量。\r\n\r\n6. **集合算法**\r\n - **`std::set_union`**:求两个已排序集合的并集。\r\n - **`std::set_intersection`**:求两个已排序集合的交集。\r\n - **`std::set_difference`**:求两个已排序集合的差集(A - B)。\r\n - **`std::set_symmetric_difference`**:求两个已排序集合的对称差集。\r\n\r\n7. **复制算法**\r\n - **`std::copy`**:将一个范围的元素复制到另一个容器或范围。\r\n - **`std::copy_if`**:将一个范围中满足特定条件的元素复制到另一个容器。\r\n\r\n8. **生成算法**\r\n - **`std::generate`**:使用生成器函数填充容器中的元素。\r\n - **`std::generate_n`**:使用生成器函数填充容器中的指定数量的元素。\r\n\r\n9. **反转和旋转算法**\r\n - **`std::reverse`**:反转容器中元素的顺序。\r\n - **`std::rotate`**:将容器中的元素进行旋转,使得指定位置的元素成为新的起始元素。\r\n\r\n10. **分区算法**\r\n - **`std::partition`**:重新排列容器中的元素,使满足条件的元素位于不满足条件的元素之前。\r\n - **`std::stable_partition`**:与 `std::partition` 类似,但保持元素的相对顺序。\r\n\r\n11. **最值算法**\r\n - **`std::min` 和 `std::max`**:计算两个值中的最小值和最大值。\r\n - **`std::min_element` 和 `std::max_element`**:找到容器中最小和最大的元素。\r\n\r\n12. **唯一化算法**\r\n - **`std::unique`**:移除容器中连续重复的元素,返回新的末尾迭代器。通常与 `erase` 一起使用以实际移除元素。\r\n\r\n13. **交换算法**\r\n - **`std::swap`**:交换两个变量的值。\r\n - **`std::iter_swap`**:交换两个迭代器所指向的元素。\r\n\r\n14. **堆算法**\r\n - **`std::make_heap`**:将容器转换为堆结构(默认大顶堆)。\r\n - **`std::push_heap`**:将新添加的元素加入堆中。\r\n - **`std::pop_heap`**:将堆顶元素移至容器末尾,并重新调整堆。\r\n - **`std::sort_heap`**:将堆排序为升序排列。\r\n\r\n15. **其他算法**\r\n - **`std::all_of`**:检查范围内的所有元素是否都满足特定条件。\r\n - **`std::any_of`**:检查范围内是否至少有一个元素满足特定条件。\r\n - **`std::none_of`**:检查范围内是否没有任何元素满足特定条件。\r\n\r\n16. **移除和填充算法**\r\n - **`std::remove`**:将所有匹配的元素移动到容器末尾,返回新的末尾迭代器。通常与 `erase` 一起使用以实际移除元素。\r\n - **`std::remove_if`**:将所有满足条件的元素移动到容器末尾,返回新的末尾迭代器。\r\n - **`std::fill`**:将容器中的所有元素填充为指定值。\r\n - **`std::fill_n`**:将容器中的指定数量的元素填充为指定值。\r\n\r\n17. **交换算法**\r\n - **`std::swap_ranges`**:交换两个范围内的元素。\r\n\r\n18. **删除重复元素**\r\n - **`std::unique`**:与前述相同,用于移除容器中连续重复的元素。\r\n\r\n19. **重排算法**\r\n - **`std::shuffle`**:随机打乱容器中的元素顺序。需要提供随机数生成器。\r\n\r\n20. **移动算法**\r\n - **`std::move`**:将元素从一个容器移动到另一个容器,避免不必要的复制操作。\r\n\r\n21. **分割算法**\r\n - **`std::partition_point`**:在已分区的容器中找到分区点,即第一个不满足条件的元素位置。\r\n - **`std::find_end`**:在一个序列中查找另一个序列最后一次出现的位置。\r\n - **`std::find_first_of`**:在一个序列中查找是否存在任何一个元素出现在另一个序列中。\r\n\r\n### 运行示例\r\n\r\n编译并运行上述代码,可以得到以下示例输出:\r\n\r\n```\r\n原始向量: 9 2 7 4 6 3 8 1 5 \r\n\r\n使用 std::sort 排序后: 1 2 3 4 5 6 7 8 9 \r\n使用 std::sort 降序排序后: 9 8 7 6 5 4 3 2 1 \r\n\r\n使用 std::stable_sort 排序后的向量 (保持相等元素的相对顺序): {1, b} {2, c} {2, e} {3, a} {3, d} \r\n\r\n使用 std::find 找到元素 6,位置索引: 4\r\n使用 std::find_if 找到第一个大于5的元素: 6\r\n使用 std::binary_search 在已排序向量中查找 4: 找到\r\n\r\n使用 std::replace 将3替换为30后: 1 2 30 4 5 6 7 8 9 \r\n使用 std::replace_if 将所有大于5的元素替换为50后: 1 2 30 4 5 50 50 50 50 \r\n\r\n使用 std::for_each 将向量中的每个元素乘以2: 2 4 60 8 10 100 100 100 100 \r\n\r\n使用 std::accumulate 计算向量元素的总和: 334\r\n使用 std::count 计算元素 6 的出现次数: 0\r\n使用 std::count_if 计算大于10的元素数量: 4 \r\n\r\n使用 std::set_union 求并集: 1 2 3 4 5 6 7 8 \r\n使用 std::set_intersection 求交集: 4 5 \r\n使用 std::set_difference 求 A - B 差集: 1 2 3 \r\n使用 std::set_symmetric_difference 求对称差集: 1 2 3 6 7 8 \r\n\r\n使用 std::copy 复制 vec 到 copyVec: 2 4 60 8 10 100 100 100 100 \r\n使用 std::copy_if 复制偶数到 copyIfVec: 2 4 60 8 10 100 100 100 100 \r\n\r\n使用 std::generate 填充 generateVec: 10 20 30 40 50 \r\n使用 std::generate_n 填充 generateNVec: 10 15 20 \r\n\r\n使用 std::reverse 反转 reverseVec: 5 1 8 3 6 4 7 2 9 \r\n使用 std::rotate 将第三个元素旋转到开始位置后 vec: 60 8 10 100 100 100 100 2 4 \r\n\r\n使用 std::partition 分区偶数和奇数后: 4 2 8 6 100 100 100 100 1 3 5 7 \r\n分区点后元素: 1 3 5 7 \r\n\r\n使用 std::stable_partition 稳定分区偶数和奇数后: 4 2 8 6 100 100 100 100 1 3 5 7 \r\n\r\n使用 std::min 和 std::max: min(10, 20) = 10, max(10, 20) = 20\r\n使用 std::min_element 和 std::max_element: min = 2, max = 100 \r\n\r\n使用 std::unique 移除连续重复的元素后: 1 2 3 4 5 \r\n\r\n交换前: x = 5, y = 10\r\n交换后: x = 10, y = 5 \r\n\r\n使用 std::unique 移除所有重复元素后: 1 2 3 4 5 \r\n\r\n交换前 swapContainer1: 1 2 3 \r\n交换前 swapContainer2: 4 5 6 7 \r\n交换后 swapContainer1: 4 5 6 7 \r\n交换后 swapContainer2: 1 2 3 \r\n\r\n```\r\n\r\n### 总结\r\n\r\n通过上述代码示例和详细注释,全面展示了C++ `` 库中各种常用算法的功能和使用方法。这些算法涵盖了排序、搜索、修改、遍历、数值计算、集合操作、堆操作等多个方面。掌握这些算法对于进行高效、简洁的编程开发至关重要。希望本示例能够帮助您更好地理解和应用C++中的标准算法库。", + "编程语言/C++/标准库解析/list库-deepseek.md": "C++ 标准库中的 `` 头文件提供了 `std::list` 容器,它是一个基于双向链表实现的数据结构。以下是详细总结:\r\n\r\n---\r\n\r\n### **基本特性**\r\n- **双向链表**:每个元素(节点)包含指向前后元素的指针,支持双向遍历。\r\n- **高效插入/删除**:在任意位置插入或删除元素的时间复杂度为 *O(1)*。\r\n- **无随机访问**:不能通过下标(如 `operator[]`)直接访问元素,需通过迭代器遍历。\r\n- **内存分布**:元素分散存储,无内存连续性的要求,无容量(capacity)概念。\r\n\r\n---\r\n\r\n### **模板参数**\r\n```cpp\r\ntemplate >\r\nclass list;\r\n```\r\n- **T**:元素类型。\r\n- **Allocator**(可选):内存分配器,默认为 `std::allocator`。\r\n\r\n---\r\n\r\n### **主要成员函数**\r\n\r\n#### 1. **构造函数**\r\n- `list()`:默认构造空列表。\r\n- `list(size_type count, const T& value)`:构造包含 `count` 个 `value` 的列表。\r\n- `list(InputIt first, InputIt last)`:通过迭代器范围构造。\r\n- `list(const list& other)`:拷贝构造函数。\r\n\r\n#### 2. **元素访问**\r\n- `front()`:返回第一个元素的引用。\r\n- `back()`:返回最后一个元素的引用。\r\n- **不支持** `operator[]` 或 `at()`。\r\n\r\n#### 3. **迭代器**\r\n- `begin()`, `end()`:正向迭代器。\r\n- `cbegin()`, `cend()`:常量正向迭代器。\r\n- `rbegin()`, `rend()`:反向迭代器。\r\n- `crbegin()`, `crend()`:常量反向迭代器。\r\n\r\n#### 4. **容量**\r\n- `empty()`:检查是否为空。\r\n- `size()`:返回元素数量。\r\n- `max_size()`:返回可容纳的最大元素数。\r\n\r\n#### 5. **修改操作**\r\n- **插入**:\r\n - `push_front(const T& value)`, `emplace_front(Args&&... args)`\r\n - `push_back(const T& value)`, `emplace_back(Args&&... args)`\r\n - `insert(iterator pos, const T& value)`:在 `pos` 前插入元素,返回新元素迭代器。\r\n- **删除**:\r\n - `pop_front()`, `pop_back()`\r\n - `erase(iterator pos)`:删除 `pos` 处元素,返回下一个元素的迭代器。\r\n - `erase(iterator first, iterator last)`:删除范围元素。\r\n - `clear()`:清空所有元素。\r\n- **调整大小**:\r\n - `resize(size_type count)`:调整列表大小,默认填充 `T()`。\r\n\r\n#### 6. **链表特有操作**\r\n- `splice(iterator pos, list& other)`:将 `other` 的所有元素移动到 `pos` 前。\r\n- `remove(const T& value)`:删除所有等于 `value` 的元素。\r\n- `remove_if(Predicate pred)`:删除满足谓词条件的所有元素。\r\n- `unique()`:删除连续重复元素(通常先排序再使用)。\r\n- `merge(list& other)`:合并两个有序列表,`other` 变为空。\r\n- `sort()`:排序(默认 `<` 运算符或自定义比较函数)。\r\n- `reverse()`:反转链表顺序。\r\n\r\n---\r\n\r\n### **时间复杂度**\r\n- **插入/删除**:任意位置 *O(1)*。\r\n- **查找**:*O(n)*。\r\n- **排序**:成员函数 `sort()` 的时间复杂度为 *O(n log n)*。\r\n\r\n---\r\n\r\n### **示例代码**\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list nums = {5, 3, 1};\r\n nums.push_back(4); // {5, 3, 1, 4}\r\n nums.push_front(2); // {2, 5, 3, 1, 4}\r\n nums.remove(5); // {2, 3, 1, 4}\r\n nums.sort(); // {1, 2, 3, 4}\r\n nums.unique(); // 无连续重复,无变化\r\n\r\n std::list other = {6, 7};\r\n nums.splice(nums.end(), other); // nums: {1,2,3,4,6,7}, other 空\r\n\r\n nums.reverse(); // {7,6,4,3,2,1}\r\n for (int n : nums) {\r\n std::cout << n << \" \"; // 输出: 7 6 4 3 2 1\r\n }\r\n}\r\n```\r\n\r\n---\r\n\r\n### **与其他容器对比**\r\n| 特性 | `std::list` | `std::vector` | `std::deque` |\r\n|--------------------|----------------------|----------------------|----------------------|\r\n| **内部结构** | 双向链表 | 动态数组 | 分块数组 |\r\n| **随机访问** | 不支持(*O(n)*) | 支持(*O(1)*) | 支持(*O(1)*) |\r\n| **中间插入/删除** | *O(1)* | *O(n)* | *O(n)* |\r\n| **内存连续性** | 不连续 | 连续 | 部分连续 |\r\n\r\n---\r\n\r\n### **适用场景**\r\n- 需要频繁在任意位置插入/删除元素。\r\n- 不需要随机访问,只需顺序或双向遍历。\r\n- 元素较大时,避免 `vector`/`deque` 频繁内存重分配。\r\n\r\n---\r\n\r\n### **注意事项**\r\n- 由于每个节点存储前后指针,内存开销较大(每个元素额外占用 2 指针空间)。\r\n- 缓存不友好,遍历速度可能慢于 `vector`。\r\n- C++11 引入的 `std::forward_list` 为单向链表,更节省空间,但仅支持前向遍历。\r\n\r\n通过合理利用 `std::list` 的特性,可以在特定场景下显著优化程序性能。", + "编程语言/C++/标准库解析/list库-豆包.md": "在 C++ 里,`` 标准库提供了双向链表容器 `std::list`。双向链表是一种由节点构成的数据结构,每个节点都存有数据和分别指向前后节点的指针。下面会详细总结 `std::list` 的用法。\r\n\r\n### 1. 头文件包含\r\n要使用 `std::list`,得包含 `` 头文件。\r\n```cpp\r\n#include \r\n```\r\n\r\n### 2. 定义与初始化\r\n可以用以下方式定义并初始化 `std::list`:\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n // 定义一个存储整数的空列表\r\n std::list myList1;\r\n\r\n // 定义一个包含 5 个值为 10 的元素的列表\r\n std::list myList2(5, 10);\r\n\r\n // 用初始化列表初始化列表\r\n std::list myList3 = {1, 2, 3, 4, 5};\r\n\r\n // 用另一个列表初始化新列表\r\n std::list myList4(myList3);\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 3. 常用成员函数\r\n\r\n#### 3.1 元素访问\r\n- **`front()`**:返回列表首个元素的引用。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n std::cout << \"First element: \" << myList.front() << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`back()`**:返回列表最后一个元素的引用。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n std::cout << \"Last element: \" << myList.back() << std::endl;\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.2 容量操作\r\n- **`empty()`**:判断列表是否为空,若为空则返回 `true`,反之返回 `false`。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList;\r\n std::cout << \"Is list empty? \" << (myList.empty() ? \"Yes\" : \"No\") << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`size()`**:返回列表中元素的数量。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n std::cout << \"List size: \" << myList.size() << std::endl;\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.3 修改操作\r\n- **`push_front()`**:在列表头部插入元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {2, 3};\r\n myList.push_front(1);\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`push_back()`**:在列表尾部插入元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2};\r\n myList.push_back(3);\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`pop_front()`**:移除列表头部的元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n myList.pop_front();\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`pop_back()`**:移除列表尾部的元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n myList.pop_back();\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`insert()`**:在指定位置插入元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 3};\r\n auto it = ++myList.begin();\r\n myList.insert(it, 2);\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`erase()`**:移除指定位置或指定范围的元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3, 4, 5};\r\n auto it = ++myList.begin();\r\n myList.erase(it);\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`clear()`**:清空列表中的所有元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n myList.clear();\r\n std::cout << \"List size after clear: \" << myList.size() << std::endl;\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.4 其他操作\r\n- **`sort()`**:对列表中的元素进行排序。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {3, 1, 2};\r\n myList.sort();\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n- **`reverse()`**:反转列表中元素的顺序。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n myList.reverse();\r\n for (int num : myList) {\r\n std::cout << num << \" \";\r\n }\r\n std::cout << std::endl;\r\n return 0;\r\n}\r\n```\r\n\r\n### 4. 迭代器\r\n`std::list` 支持双向迭代器,你可以用迭代器遍历列表。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3, 4, 5};\r\n\r\n // 正向遍历\r\n for (auto it = myList.begin(); it != myList.end(); ++it) {\r\n std::cout << *it << \" \";\r\n }\r\n std::cout << std::endl;\r\n\r\n // 反向遍历\r\n for (auto it = myList.rbegin(); it != myList.rend(); ++it) {\r\n std::cout << *it << \" \";\r\n }\r\n std::cout << std::endl;\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 5. 优缺点\r\n\r\n#### 优点\r\n- 插入和删除操作效率高,时间复杂度为 $O(1)$。\r\n- 支持双向访问。\r\n\r\n#### 缺点\r\n- 随机访问效率低,不支持 `[]` 操作符和 `at()` 函数。\r\n- 相比于数组,占用更多的内存空间,因为每个节点都需要额外的指针。\r\n\r\n### 6. 应用场景\r\n- 适用于需要频繁插入和删除元素的场景,如实现栈、队列等数据结构。\r\n- 当不需要随机访问元素时,可以使用 `std::list` 来提高插入和删除操作的效率。\r\n\r\n通过上述介绍,你可以掌握 C++ 中 `std::list` 标准库的基本用法。 ", + "编程语言/C++/标准库解析/queue库.md": "\r\n### C++ 标准库 `queue` 用法详解\r\n\r\n\r\n#### **1. 基本概念**\r\n- **头文件**:``\r\n- **命名空间**:`std`(通常配合 `using namespace std;` 或直接 `std::queue` 使用)\r\n- **本质**:是一个**容器适配器(Container Adapter)**,通过封装底层容器(如 `deque`、`list`)实现**队列(FIFO,先进先出)**功能。\r\n- **特点**:只能从队尾(Back)插入元素,从队头(Front)删除元素,不支持遍历和随机访问。\r\n\r\n\r\n#### **2. 定义与初始化**\r\n```cpp\r\n#include \r\n#include // 底层容器(可选,默认是 deque)\r\n#include // 也可以用 list 作为底层容器\r\n\r\n// 定义方式:queue<数据类型, 底层容器类型> 队列名;\r\nstd::queue q1; // 默认底层容器为 deque\r\nstd::queue> q2; // 显式使用 deque\r\nstd::queue> q3; // 使用 list 作为底层容器(支持双向删除,适合频繁头删的场景)\r\n\r\n// 初始化:不能直接初始化(容器适配器不支持直接初始化列表),需通过 push 逐个插入\r\nq1.push(1);\r\nq1.push(2);\r\n```\r\n\r\n\r\n#### **3. 常用成员函数**\r\n\r\n| 函数 | 描述 |\r\n|---------------------|----------------------------------------------------------------------|\r\n| **`push(value)`** | 将元素 `value` 插入队尾(底层调用 `container::push_back(value)`)。 |\r\n| **`pop()`** | 删除队头元素(底层调用 `container::pop_front()`),不返回值。 |\r\n| **`front()`** | 返回队头元素的引用(若队列为空,调用会导致未定义行为)。 |\r\n| **`back()`** | 返回队尾元素的引用(若队列为空,调用会导致未定义行为)。 |\r\n| **`empty()`** | 若队列为空,返回 `true`,否则 `false`。 |\r\n| **`size()`** | 返回队列中元素的个数(底层调用 `container::size()`)。 |\r\n\r\n\r\n#### **4. 详细用法示例**\r\n\r\n##### **(1)元素操作**\r\n```cpp\r\nstd::queue q;\r\n\r\n// 插入元素(队尾)\r\nq.push(10); // 队列:[10]\r\nq.push(20); // 队列:[10, 20]\r\n\r\n// 访问队头和队尾元素\r\nint front_val = q.front(); // 10\r\nint back_val = q.back(); // 20\r\n\r\n// 删除队头元素\r\nq.pop(); // 队列:[20],此时 front() 返回 20\r\n\r\n// 检查队列状态\r\nbool is_empty = q.empty(); // false(队列非空)\r\nsize_t len = q.size(); // 1\r\n```\r\n\r\n##### **(2)遍历队列(注意:不建议直接遍历,需临时拷贝)**\r\n由于 `queue` 不支持迭代器,若需遍历,需逐个弹出并处理(但会修改原队列),或复制到其他容器:\r\n```cpp\r\nstd::queue q;\r\nq.push(1); q.push(2); q.push(3);\r\n\r\n// 方法 1:弹出并打印(修改原队列)\r\nwhile (!q.empty()) {\r\n std::cout << q.front() << \" \"; // 1 2 3\r\n q.pop();\r\n}\r\n\r\n// 方法 2:复制到临时队列(不修改原队列,需使用相同底层容器)\r\nstd::queue temp = q; // C++11 支持拷贝构造函数\r\nwhile (!temp.empty()) {\r\n std::cout << temp.front() << \" \"; // 1 2 3\r\n temp.pop();\r\n}\r\n```\r\n\r\n##### **(3)自定义数据类型**\r\n```cpp\r\nstruct Person {\r\n std::string name;\r\n int age;\r\n};\r\n\r\nstd::queue people;\r\npeople.push({\"Alice\", 20});\r\npeople.push({\"Bob\", 25});\r\n\r\nPerson first = people.front(); // 访问队头元素\r\n```\r\n\r\n\r\n#### **5. 底层容器要求**\r\n`queue` 要求底层容器支持以下操作:\r\n- `back()`:获取队尾元素(用于 `push` 和 `back()` 函数)。\r\n- `front()`:获取队头元素(用于 `front()` 函数)。\r\n- `push_back(value)`:在队尾插入元素(用于 `push()` 函数)。\r\n- `pop_front()`:删除队头元素(用于 `pop()` 函数)。\r\n\r\n**支持的底层容器**:\r\n- **`deque`(默认)**:双端队列,效率均衡,适合大多数场景。\r\n- **`list`**:双向链表,适合频繁头删(`pop_front`)和尾插(`push_back`),但随机访问效率低。\r\n- **不支持 `vector`**:因为 `vector` 没有 `pop_front()` 函数(需手动 `erase(begin())`,效率 O(n))。\r\n\r\n\r\n#### **6. 应用场景**\r\n1. **广度优先搜索(BFS)**:队列天然适合按层遍历图或树。\r\n ```cpp\r\n // BFS 示例\r\n std::queue q;\r\n q.push(root);\r\n while (!q.empty()) {\r\n int node = q.front(); q.pop();\r\n // 处理当前节点\r\n for (auto neighbor : adj[node]) {\r\n q.push(neighbor);\r\n }\r\n }\r\n ```\r\n2. **任务队列**:按顺序处理任务,如多线程中的任务调度(需配合线程安全机制)。\r\n3. **缓存队列**:限制队列长度,先进先出淘汰旧元素。\r\n\r\n\r\n#### **7. 注意事项**\r\n1. **空队列操作风险**:\r\n - 调用 `front()`/`back()` 前必须用 `empty()` 检查,否则可能导致程序崩溃(未定义行为)。\r\n - `pop()` 对空队列调用是安全的(无操作),但逻辑上应避免。\r\n2. **线程安全**:标准库 `queue` 非线程安全,多线程环境需自行加锁(如 `std::mutex`)。\r\n3. **底层容器选择**:\r\n - 若需高效头删和尾插,选 `list`;否则用默认的 `deque` 即可。\r\n4. **不支持的操作**:\r\n - 不支持直接获取队列容量(但可通过 `size()` 间接获取)。\r\n - 不支持迭代器、反向迭代器、随机访问等操作。\r\n\r\n\r\n#### **8. 与其他容器适配器对比**\r\n| 容器适配器 | 底层容器默认 | 访问特性 | 典型场景 |\r\n|------------|--------------|------------------|------------------|\r\n| `queue` | `deque` | FIFO,队头删、队尾插 | BFS、任务队列 |\r\n| `stack` | `deque` | LIFO,栈顶操作 | 表达式求值、括号匹配 |\r\n| `priority_queue` | `vector` | 优先级队列(默认最大堆) | 事件调度、Dijkstra算法 |\r\n\r\n\r\n#### **总结**\r\n`queue` 是 C++ 中实现 FIFO 逻辑的便捷工具,通过封装底层容器简化了队列操作。使用时需注意空队列的检查,根据场景选择合适的底层容器,并结合实际需求(如线程安全)扩展功能。其核心优势在于接口简单,专注于队列的基本操作,适合算法和数据结构中的典型应用(如 BFS)。在C++中,`queue` 是标准模板库(STL)提供的一种容器适配器,它遵循先进先出(FIFO)的原则,就像排队一样,先进入队列的元素会先被移除。下面详细总结 `queue` 的用法。\r\n\r\n### 1. 头文件包含\r\n要使用 `queue`,需要包含 `` 头文件。\r\n```cpp\r\n#include \r\n```\r\n\r\n### 2. 定义与初始化\r\n可以使用以下方式定义和初始化一个 `queue`:\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n // 定义一个存储整数的队列\r\n std::queue q;\r\n\r\n return 0;\r\n}\r\n```\r\n也可以使用其他容器(如 `deque` 或 `list`)作为底层容器来初始化 `queue`:\r\n```cpp\r\n#include \r\n#include \r\n#include \r\n\r\nint main() {\r\n std::list myList = {1, 2, 3};\r\n std::queue> q(myList);\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 3. 常用成员函数\r\n\r\n#### 3.1 `push()`\r\n用于在队列的尾部插入一个元素。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::queue q;\r\n q.push(10);\r\n q.push(20);\r\n q.push(30);\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.2 `pop()`\r\n移除队列的头部元素。注意,该函数没有返回值,如果需要获取头部元素的值,需要先使用 `front()` 函数。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::queue q;\r\n q.push(10);\r\n q.push(20);\r\n q.push(30);\r\n\r\n q.pop(); // 移除头部元素 10\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.3 `front()`\r\n返回队列的头部元素的引用。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::queue q;\r\n q.push(10);\r\n q.push(20);\r\n q.push(30);\r\n\r\n std::cout << \"Front element: \" << q.front() << std::endl; // 输出 10\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.4 `back()`\r\n返回队列的尾部元素的引用。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::queue q;\r\n q.push(10);\r\n q.push(20);\r\n q.push(30);\r\n\r\n std::cout << \"Back element: \" << q.back() << std::endl; // 输出 30\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.5 `empty()`\r\n判断队列是否为空,如果为空则返回 `true`,否则返回 `false`。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::queue q;\r\n std::cout << \"Is queue empty? \" << (q.empty() ? \"Yes\" : \"No\") << std::endl; // 输出 Yes\r\n\r\n q.push(10);\r\n std::cout << \"Is queue empty? \" << (q.empty() ? \"Yes\" : \"No\") << std::endl; // 输出 No\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.6 `size()`\r\n返回队列中元素的数量。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::queue q;\r\n q.push(10);\r\n q.push(20);\r\n q.push(30);\r\n\r\n std::cout << \"Queue size: \" << q.size() << std::endl; // 输出 3\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 4. 示例代码\r\n下面是一个完整的示例,展示了 `queue` 的基本用法:\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::queue q;\r\n\r\n // 插入元素\r\n q.push(1);\r\n q.push(2);\r\n q.push(3);\r\n\r\n // 输出队列元素\r\n while (!q.empty()) {\r\n std::cout << q.front() << \" \";\r\n q.pop();\r\n }\r\n std::cout << std::endl;\r\n\r\n return 0;\r\n}\r\n```\r\n这个示例首先创建了一个整数队列,然后向队列中插入三个元素,接着使用 `while` 循环遍历队列,输出队列中的元素并依次移除,直到队列为空。\r\n\r\n通过以上的介绍,你可以掌握 C++ 中 `queue` 标准库的基本用法。", + "编程语言/C++/标准库解析/stack库.md": "\r\nC++ 标准库中的 `` 头文件提供了 `stack` 容器适配器,用于实现栈数据结构(后进先出,LIFO)。以下是其详细用法总结:\r\n\r\n\r\n### 一、基本概念\r\n- **容器适配器**:`stack` 并非独立容器,而是包装了其他容器(如 `deque`、`vector`、`list`),通过限制接口使其成为栈。\r\n- **默认底层容器**:`std::deque`(双端队列),可显式指定其他顺序容器(需支持 `back()`、`push_back()`、`pop_back()` 操作)。\r\n\r\n\r\n### 二、头文件与声明\r\n```cpp\r\n#include // 必需头文件\r\nusing namespace std;\r\n\r\n// 声明方式:stack<数据类型, 底层容器类型> 栈名;\r\nstack s; // 默认底层容器为 deque\r\nstack> s_vec; // 底层容器为 vector\r\nstack> s_list; // 底层容器为 list\r\n```\r\n\r\n\r\n### 三、常用成员函数\r\n\r\n#### 1. 元素操作\r\n| 函数 | 描述 |\r\n|---------------------|----------------------------------------------------------------------|\r\n| `push(value)` | 将元素 `value` 压入栈顶(调用底层容器的 `push_back()`)。 |\r\n| `pop()` | 弹出栈顶元素(不返回值,调用底层容器的 `pop_back()`)。 |\r\n| `top()` | 返回栈顶元素的引用(若栈为空,调用会导致未定义行为)。 |\r\n| `emplace(args...)` | (C++11+)在栈顶直接构造元素(避免临时对象,参数为构造函数参数包)。|\r\n\r\n**示例**:\r\n```cpp\r\nstack s;\r\ns.push(10); // 栈:[10]\r\ns.emplace(20); // 栈:[10, 20](等价于 push(20))\r\ncout << s.top(); // 输出 20\r\ns.pop(); // 栈:[10]\r\n```\r\n\r\n\r\n#### 2. 容量与状态\r\n| 函数 | 描述 |\r\n|-----------------|-------------------------------------------|\r\n| `empty()` | 检查栈是否为空,空则返回 `true`,否则 `false`。 |\r\n| `size()` | 返回栈中元素个数(调用底层容器的 `size()`)。 |\r\n\r\n**示例**:\r\n```cpp\r\ncout << s.empty(); // 输出 0(非空)\r\ncout << s.size(); // 输出 1\r\n```\r\n\r\n\r\n#### 3. 底层容器访问(C++17+)\r\n| 函数 | 描述 |\r\n|-----------------|---------------------------------------|\r\n| `get_allocator()`| 返回底层容器的分配器。 |\r\n| `container()` | (C++20+)返回底层容器的引用(需 `#include `)。 |\r\n\r\n**示例**:\r\n```cpp\r\nstack::container_type& cnt = s.container(); // 获取底层 deque&\r\n```\r\n\r\n\r\n### 四、自定义底层容器\r\n`stack` 支持的底层容器需满足以下条件:\r\n- 支持 `back()` 访问最后一个元素。\r\n- 支持 `push_back()` 向末尾添加元素。\r\n- 支持 `pop_back()` 从末尾删除元素。\r\n\r\n常用可选容器:\r\n- `deque`(默认,效率均衡)\r\n- `vector`(适合随机访问,但动态扩容可能导致重新分配内存)\r\n- `list`(适合频繁插入/删除,内存非连续)\r\n\r\n**示例:使用 vector 作为底层容器**\r\n```cpp\r\nstack> s_vec;\r\ns_vec.push(1);\r\ns_vec.push(2);\r\n```\r\n\r\n\r\n### 五、自定义数据类型\r\n当栈中存储自定义类对象时,需确保类支持拷贝构造或移动构造(若使用 `emplace`,需支持直接构造)。\r\n\r\n**示例:存储自定义结构体**\r\n```cpp\r\nstruct Point {\r\n int x, y;\r\n Point(int a, int b) : x(a), y(b) {}\r\n};\r\n\r\nstack s_points;\r\ns_points.emplace(1, 2); // 直接构造对象压栈\r\nPoint p(3, 4);\r\ns_points.push(p); // 拷贝构造压栈\r\n```\r\n\r\n\r\n### 六、非成员函数\r\n`stack` 支持关系运算符(`==`, `!=`, `<`, `<=`, `>`, `>=`),比较规则:\r\n- 首先比较底层容器的大小,若大小不同,按大小判断。\r\n- 若大小相同,逐个元素比较(调用元素的对应运算符)。\r\n\r\n```cpp\r\nstack s1, s2;\r\ns1.push(1); s2.push(1);\r\ncout << (s1 == s2); // 输出 1(相等)\r\n```\r\n\r\n\r\n### 七、注意事项\r\n1. **线程安全**:标准库 `stack` 非线程安全,多线程环境需自行加锁。\r\n2. **空栈操作风险**:调用 `top()` 或 `pop()` 前需用 `empty()` 检查,否则可能导致程序崩溃。\r\n3. **底层容器特性**:不同底层容器影响性能,例如 `vector` 的 `pop_back()` 均摊 O(1),`list` 的 `pop_back()` 严格 O(1)。\r\n4. **迭代器限制**:`stack` 不暴露迭代器,无法直接遍历元素(需弹出元素访问)。\r\n\r\n\r\n### 八、完整示例\r\n```cpp\r\n#include \r\n#include \r\n#include \r\n\r\nusing namespace std;\r\n\r\nint main() {\r\n // 基本操作\r\n stack s;\r\n s.push(10);\r\n s.push(20);\r\n cout << \"栈顶元素:\" << s.top() << endl; // 20\r\n s.pop();\r\n cout << \"弹出后栈顶:\" << s.top() << endl; // 10\r\n\r\n // 使用 vector 作为底层容器\r\n stack> s_str;\r\n s_str.emplace(\"hello\");\r\n s_str.emplace(\"world\");\r\n while (!s_str.empty()) {\r\n cout << s_str.top() << \" \"; // 输出 \"world hello\"\r\n s_str.pop();\r\n }\r\n\r\n // 自定义类型\r\n struct Data {\r\n int val;\r\n Data(int v) : val(v) {}\r\n };\r\n stack s_data;\r\n s_data.emplace(42);\r\n cout << \"自定义数据:\" << s_data.top().val << endl; // 42\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n\r\n### 总结\r\n`stack` 是简单高效的 LIFO 容器,通过包装底层容器实现。使用时需注意:\r\n- 明确底层容器的选择与性能 trade-off。\r\n- 确保空栈检查,避免未定义行为。\r\n- 利用 `emplace` 优化元素构造效率。\r\n\r\n通过合理组合底层容器和成员函数,可满足大多数栈结构的应用场景。在C++里,`#include `引入的标准库提供了`std::stack`容器适配器,它遵循后进先出(LIFO)原则,适用于像函数调用栈、回溯算法等场景。下面是对`std::stack`标准库详细用法的总结。\r\n\r\n### 1. 头文件包含\r\n要使用`std::stack`,得包含``头文件:\r\n```cpp\r\n#include \r\n```\r\n\r\n### 2. 声明与初始化\r\n可使用任意支持随机访问迭代器的容器(如`std::vector`、`std::deque`、`std::list`)来实例化`std::stack`,默认容器是`std::deque`。\r\n```cpp\r\n#include \r\n#include \r\n\r\n// 默认使用 std::deque 作为底层容器\r\nstd::stack stack1;\r\n\r\n// 使用 std::vector 作为底层容器\r\nstd::stack> stack2;\r\n```\r\n\r\n### 3. 常用成员函数\r\n\r\n#### 3.1 `push()`\r\n把元素添加到栈顶。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::stack myStack;\r\n myStack.push(10);\r\n myStack.push(20);\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.2 `pop()`\r\n移除栈顶元素,但不返回其值。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::stack myStack;\r\n myStack.push(10);\r\n myStack.push(20);\r\n myStack.pop(); // 移除 20\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.3 `top()`\r\n返回栈顶元素的引用。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::stack myStack;\r\n myStack.push(10);\r\n myStack.push(20);\r\n std::cout << \"Top element: \" << myStack.top() << std::endl; // 输出 20\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.4 `empty()`\r\n判断栈是否为空,若为空则返回`true`,反之返回`false`。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::stack myStack;\r\n if (myStack.empty()) {\r\n std::cout << \"Stack is empty.\" << std::endl;\r\n }\r\n return 0;\r\n}\r\n```\r\n\r\n#### 3.5 `size()`\r\n返回栈中元素的数量。\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::stack myStack;\r\n myStack.push(10);\r\n myStack.push(20);\r\n std::cout << \"Stack size: \" << myStack.size() << std::endl; // 输出 2\r\n return 0;\r\n}\r\n```\r\n\r\n### 4. 示例代码\r\n以下是一个综合示例,展示了`std::stack`的基本用法:\r\n```cpp\r\n#include \r\n#include \r\n\r\nint main() {\r\n std::stack myStack;\r\n\r\n // 入栈操作\r\n myStack.push(1);\r\n myStack.push(2);\r\n myStack.push(3);\r\n\r\n // 输出栈顶元素\r\n std::cout << \"Top element: \" << myStack.top() << std::endl;\r\n\r\n // 出栈操作\r\n myStack.pop();\r\n std::cout << \"After pop, top element: \" << myStack.top() << std::endl;\r\n\r\n // 检查栈是否为空\r\n if (!myStack.empty()) {\r\n std::cout << \"Stack is not empty.\" << std::endl;\r\n }\r\n\r\n // 输出栈的大小\r\n std::cout << \"Stack size: \" << myStack.size() << std::endl;\r\n\r\n return 0;\r\n}\r\n```\r\n\r\n### 5. 复杂度分析\r\n- `push()`:平均时间复杂度为$O(1)$。\r\n- `pop()`:平均时间复杂度为$O(1)$。\r\n- `top()`:时间复杂度为$O(1)$。\r\n- `empty()`:时间复杂度为$O(1)$。\r\n- `size()`:时间复杂度为$O(1)$。\r\n\r\n总之,`std::stack`是一个方便的容器适配器,能轻松实现栈的基本操作。 ", + "编程语言/C++/标准库解析/string库.md": "```cpp\n#include \n#include \n#include // 用于算法函数,如std::transform\n#include // 用于字符处理函数,如std::toupper\n#include // 用于字符串和数字的转换\n#include \n\nusing namespace std;\n\n/*\n * 本程序通过一个示例,详细总结和演示了C++中std::string库的各种使用方法。\n * 涵盖了字符串的初始化、连接、访问、修改、查找、替换、比较、遍历、转换等功能。\n */\n\nint main() {\n // 1. 字符串的初始化\n // a. 使用字面值初始化\n string str1 = \"Hello, World!\";\n \n // b. 使用字符数组初始化\n char charArray[] = \"Hello, C++!\";\n string str2(charArray);\n \n // c. 使用重复字符初始化\n string str3(5, 'A'); // \"AAAAA\"\n \n // d. 使用另一个字符串初始化(拷贝构造)\n string str4 = str1;\n \n // e. 使用字符串的一部分初始化\n string str5 = str1.substr(7, 5); // \"World\"\n\n // 输出初始化后的字符串\n cout << \"字符串初始化示例:\" << endl;\n cout << \"str1: \" << str1 << endl;\n cout << \"str2: \" << str2 << endl;\n cout << \"str3: \" << str3 << endl;\n cout << \"str4: \" << str4 << endl;\n cout << \"str5: \" << str5 << endl << endl;\n\n // 2. 字符串的连接\n // a. 使用 + 运算符\n string str6 = str1 + \" \" + str2; // \"Hello, World! Hello, C++!\"\n \n // b. 使用 += 运算符\n str6 += \" \" + str3; // \"Hello, World! Hello, C++! AAAAA\"\n \n // c. 使用 append() 函数\n str6.append(\" \").append(str4); // \"Hello, World! Hello, C++! AAAAA Hello, World!\"\n \n // 输出连接后的字符串\n cout << \"字符串连接示例:\" << endl;\n cout << \"str6: \" << str6 << endl << endl;\n\n // 3. 字符串的访问和修改\n // a. 使用下标访问字符(不安全,越界不会检查)\n char ch1 = str1[0]; // 'H'\n \n // b. 使用 at() 函数访问字符(安全,会检查越界)\n char ch2 = str1.at(7); // 'W'\n \n // c. 修改字符串中的字符\n str1[0] = 'h'; // \"hello, World!\"\n str1.at(7) = 'w'; // \"hello, world!\"\n \n // 输出访问和修改后的字符串\n cout << \"字符串访问和修改示例:\" << endl;\n cout << \"str1: \" << str1 << endl;\n cout << \"str1[0]: \" << ch1 << endl;\n cout << \"str1.at(7): \" << ch2 << endl << endl;\n\n // 4. 字符串的查找\n // a. 查找子字符串的位置\n size_t pos1 = str6.find(\"C++\"); // 返回第一次出现的位置\n size_t pos2 = str6.find(\"Python\"); // 如果未找到,返回 string::npos\n \n // b. 从特定位置开始查找\n size_t pos3 = str6.find(\"Hello\", 10);\n \n // 输出查找结果\n cout << \"字符串查找示例:\" << endl;\n cout << \"str6.find(\\\"C++\\\"): \" << pos1 << endl;\n if (pos2 == string::npos)\n cout << \"str6.find(\\\"Python\\\"): 未找到\" << endl;\n else\n cout << \"str6.find(\\\"Python\\\"): \" << pos2 << endl;\n cout << \"str6.find(\\\"Hello\\\", 10): \" << pos3 << endl << endl;\n\n // 5. 字符串的替换\n // a. 替换子字符串\n string str7 = str6;\n size_t replacePos = str7.find(\"World\");\n if (replacePos != string::npos) {\n str7.replace(replacePos, 5, \"C++\"); // 将 \"World\" 替换为 \"C++\"\n }\n \n // b. 替换特定位置的字符\n str7.replace(0, 5, \"Hi\"); // 将前5个字符替换为 \"Hi\"\n \n // 输出替换后的字符串\n cout << \"字符串替换示例:\" << endl;\n cout << \"str7: \" << str7 << endl << endl;\n\n // 6. 字符串的比较\n // a. 使用 == 运算符\n bool isEqual = (str1 == str2); // 比较内容是否相同\n \n // b. 使用 compare() 函数\n int cmpResult = str1.compare(str2); // 返回0表示相同,负数表示str1 < str2,正数表示str1 > str2\n \n // 输出比较结果\n cout << \"字符串比较示例:\" << endl;\n cout << \"str1 == str2: \" << (isEqual ? \"相同\" : \"不同\") << endl;\n cout << \"str1.compare(str2): \" << cmpResult << endl << endl;\n\n // 7. 字符串的遍历\n // a. 使用下标遍历\n cout << \"使用下标遍历 str1: \";\n for (size_t i = 0; i < str1.length(); ++i) {\n cout << str1[i] << ' ';\n }\n cout << endl;\n \n // b. 使用范围 for 循环遍历\n cout << \"使用范围 for 遍历 str2: \";\n for (char c : str2) {\n cout << c << ' ';\n }\n cout << endl;\n \n // c. 使用迭代器遍历\n cout << \"使用迭代器遍历 str3: \";\n for (string::iterator it = str3.begin(); it != str3.end(); ++it) {\n cout << *it << ' ';\n }\n cout << endl << endl;\n\n // 8. 字符串的插入和删除\n // a. 在指定位置插入子字符串\n string str8 = \"Hello World!\";\n str8.insert(5, \", C++\"); // \"Hello, C++ World!\"\n \n // b. 删除指定位置的字符\n str8.erase(5, 2); // 删除第5和第6个字符,变为 \"Hello C++ World!\"\n \n // 输出插入和删除后的字符串\n cout << \"字符串插入和删除示例:\" << endl;\n cout << \"str8: \" << str8 << endl << endl;\n\n // 9. 字符串的分割\n // C++标准库没有内置的字符串分割函数,这里使用stringstream实现简单的分割\n string str9 = \"apple,banana,cherry,dragonfruit\";\n vector fruits;\n stringstream ss(str9);\n string fruit;\n \n while (getline(ss, fruit, ',')) {\n fruits.push_back(fruit);\n }\n \n // 输出分割后的结果\n cout << \"字符串分割示例:\" << endl;\n for (const auto& f : fruits) {\n cout << f << ' ';\n }\n cout << endl << endl;\n\n // 10. 字符串的大小写转换\n // a. 转换为大写\n string str10 = \"Hello, World!\";\n transform(str10.begin(), str10.end(), str10.begin(), ::toupper); // \"HELLO, WORLD!\"\n \n // b. 转换为小写\n string str11 = \"Hello, World!\";\n transform(str11.begin(), str11.end(), str11.begin(), ::tolower); // \"hello, world!\"\n \n // 输出大小写转换后的字符串\n cout << \"字符串大小写转换示例:\" << endl;\n cout << \"str10 (大写): \" << str10 << endl;\n cout << \"str11 (小写): \" << str11 << endl << endl;\n\n // 11. 字符串与数字的转换\n // a. 数字转字符串\n int number = 12345;\n double pi = 3.14159;\n string numStr1 = to_string(number); // \"12345\"\n string numStr2 = to_string(pi); // \"3.141590\"\n \n // b. 字符串转数字\n string numStr3 = \"67890\";\n string numStr4 = \"2.71828\";\n int parsedInt = stoi(numStr3); // 67890\n double parsedDouble = stod(numStr4); // 2.71828\n \n // 输出转换结果\n cout << \"字符串与数字转换示例:\" << endl;\n cout << \"number: \" << number << \" -> numStr1: \" << numStr1 << endl;\n cout << \"pi: \" << pi << \" -> numStr2: \" << numStr2 << endl;\n cout << \"numStr3: \" << numStr3 << \" -> parsedInt: \" << parsedInt << endl;\n cout << \"numStr4: \" << numStr4 << \" -> parsedDouble: \" << parsedDouble << endl << endl;\n\n // 12. 字符串的其他常用函数\n // a. size() 和 length()\n string str12 = \"Sample String\";\n size_t size1 = str12.size(); // 13\n size_t size2 = str12.length(); // 13\n \n // b. empty()\n bool isEmpty = str12.empty(); // false\n \n // c. clear()\n string str13 = \"To be cleared\";\n str13.clear(); // str13 变为 \"\"\n \n // 输出其他函数的使用结果\n cout << \"字符串其他常用函数示例:\" << endl;\n cout << \"str12: \" << str12 << endl;\n cout << \"str12.size(): \" << size1 << endl;\n cout << \"str12.length(): \" << size2 << endl;\n cout << \"str12.empty(): \" << (isEmpty ? \"是空的\" : \"不是空的\") << endl;\n cout << \"str13 清空后: \\\"\" << str13 << \"\\\"\" << endl << endl;\n\n // 13. 字符串的子串提取\n // a. substr() 函数\n string str14 = \"The quick brown fox jumps over the lazy dog\";\n string subStr1 = str14.substr(4, 5); // \"quick\"\n string subStr2 = str14.substr(16); // \"fox jumps over the lazy dog\"\n \n // 输出子串提取的结果\n cout << \"字符串子串提取示例:\" << endl;\n cout << \"str14: \" << str14 << endl;\n cout << \"subStr1: \" << subStr1 << endl;\n cout << \"subStr2: \" << subStr2 << endl << endl;\n\n // 14. 字符串的插入\n // a. insert() 函数\n string str15 = \"Hello World!\";\n str15.insert(5, \", C++\"); // \"Hello, C++ World!\"\n \n // 输出插入后的字符串\n cout << \"字符串插入示例:\" << endl;\n cout << \"str15: \" << str15 << endl << endl;\n\n // 15. 字符串的比较\n // a. 使用 <, > 运算符\n string str16 = \"apple\";\n string str17 = \"banana\";\n bool isLess = str16 < str17; // true,因为 \"apple\" 小于 \"banana\"\n \n // 输出比较结果\n cout << \"字符串比较示例:\" << endl;\n cout << \"str16: \" << str16 << \", str17: \" << str17 << endl;\n cout << \"str16 < str17: \" << (isLess ? \"true\" : \"false\") << endl << endl;\n\n // 16. 字符串的替换\n // a. replace() 函数\n string str18 = \"I love programming.\";\n str18.replace(7, 11, \"C++\"); // \"I love C++.\"\n \n // 输出替换后的字符串\n cout << \"字符串替换示例:\" << endl;\n cout << \"str18: \" << str18 << endl << endl;\n\n // 17. 字符串的查找和替换\n // a. 使用 find() 和 replace() 结合\n string str19 = \"The rain in Spain stays mainly in the plain.\";\n size_t found = str19.find(\"ain\");\n while (found != string::npos) {\n str19.replace(found, 3, \"XYZ\");\n found = str19.find(\"ain\", found + 3);\n }\n \n // 输出查找和替换后的字符串\n cout << \"字符串查找和替换示例:\" << endl;\n cout << \"str19: \" << str19 << endl << endl;\n\n // 18. 字符串的插入和删除\n // a. insert() 和 erase() 函数\n string str20 = \"HelloWorld\";\n str20.insert(5, \" \"); // \"Hello World\"\n str20.erase(5, 1); // \"HelloWorld\"\n \n // 输出插入和删除后的字符串\n cout << \"字符串插入和删除示例:\" << endl;\n cout << \"str20: \" << str20 << endl << endl;\n\n // 19. 字符串的查找和计数\n // a. 查找所有出现的位置\n string str21 = \"banana\";\n size_t pos = str21.find(\"ana\");\n while (pos != string::npos) {\n cout << \"\\\"ana\\\" found at position: \" << pos << endl;\n pos = str21.find(\"ana\", pos + 1);\n }\n \n // b. 使用 count_if 统计特定字符的出现次数\n string str22 = \"Mississippi\";\n int vowelCount = count_if(str22.begin(), str22.end(), [](char c) {\n return c == 'i' || c == 'e' || c == 'a' || c == 'o' || c == 'u';\n });\n cout << \"\\n字符串查找和计数示例:\" << endl;\n cout << \"str21: \" << str21 << endl;\n cout << \"str22: \" << str22 << endl;\n cout << \"元音字母出现次数: \" << vowelCount << endl << endl;\n\n // 20. 字符串的格式化输出\n // 使用字符串流 (stringstream) 进行格式化\n string name = \"Alice\";\n int age = 30;\n double height = 5.6;\n stringstream ss;\n ss << \"Name: \" << name << \", Age: \" << age << \", Height: \" << height << \" feet.\";\n string str23 = ss.str();\n \n // 输出格式化后的字符串\n cout << \"字符串格式化输出示例:\" << endl;\n cout << \"str23: \" << str23 << endl << endl;\n\n return 0;\n}\n```\n\n### 代码详解\n\n1. **字符串的初始化**\n - **字面值初始化**:直接使用双引号括起来的字符串初始化 `std::string` 对象。\n - **字符数组初始化**:使用字符数组(C风格字符串)初始化 `std::string`。\n - **重复字符初始化**:使用构造函数初始化一个由指定数量的重复字符组成的字符串。\n - **拷贝构造**:通过拷贝另一个 `std::string` 对象来初始化。\n - **子字符串初始化**:使用 `substr` 函数提取字符串的一部分作为新字符串。\n\n2. **字符串的连接**\n - **使用 `+` 运算符**:将多个字符串通过 `+` 运算符连接起来,形成一个新的字符串。\n - **使用 `+=` 运算符**:在原有字符串的基础上追加另一个字符串。\n - **使用 `append()` 函数**:通过调用 `append` 方法追加字符串,可以链式调用。\n\n3. **字符串的访问和修改**\n - **下标访问**:通过下标直接访问字符串中的字符,不进行越界检查。\n - **`at()` 函数访问**:通过 `at` 方法访问字符,具有越界检查功能。\n - **修改字符**:可以直接通过下标或 `at` 方法修改字符串中的字符。\n\n4. **字符串的查找**\n - **`find()` 函数**:查找子字符串首次出现的位置,如果未找到返回 `string::npos`。\n - **从特定位置开始查找**:可以指定起始位置,从该位置开始查找子字符串。\n\n5. **字符串的替换**\n - **替换子字符串**:使用 `replace()` 函数将指定位置的子字符串替换为新的字符串。\n - **替换特定位置的字符**:可以通过 `replace()` 函数替换特定位置的字符或字符段。\n\n6. **字符串的比较**\n - **使用 `==` 运算符**:比较两个字符串的内容是否相同。\n - **使用 `compare()` 函数**:比较两个字符串,返回整数值表示大小关系。\n\n7. **字符串的遍历**\n - **下标遍历**:使用下标循环访问每个字符。\n - **范围 `for` 遍历**:使用范围 `for` 循环直接遍历每个字符。\n - **迭代器遍历**:使用迭代器从头到尾遍历字符串中的字符。\n\n8. **字符串的插入和删除**\n - **`insert()` 函数**:在指定位置插入子字符串。\n - **`erase()` 函数**:删除指定位置的字符或字符段。\n\n9. **字符串的分割**\n - **使用 `stringstream` 实现分割**:C++ 标准库没有内置的分割函数,使用 `stringstream` 和 `getline` 结合指定分隔符实现字符串分割。\n\n10. **字符串的大小写转换**\n - **转换为大写**:使用 `std::transform` 和 `::toupper` 将字符串中的字符转换为大写。\n - **转换为小写**:使用 `std::transform` 和 `::tolower` 将字符串中的字符转换为小写。\n\n11. **字符串与数字的转换**\n - **数字转字符串**:使用 `std::to_string` 将整数或浮点数转换为字符串。\n - **字符串转数字**:使用 `std::stoi`、`std::stod` 等函数将字符串转换为整数或浮点数。\n\n12. **字符串的其他常用函数**\n - **`size()` 和 `length()`**:获取字符串的长度,两者功能相同。\n - **`empty()`**:检查字符串是否为空。\n - **`clear()`**:清空字符串内容。\n\n13. **字符串的子串提取**\n - **`substr()` 函数**:提取字符串中的子字符串,指定起始位置和长度。\n\n14. **字符串的插入**\n - **`insert()` 函数**:在指定位置插入子字符串。\n\n15. **字符串的比较**\n - **使用 `<` 和 `>` 运算符**:比较两个字符串的字典序关系。\n\n16. **字符串的替换**\n - **`replace()` 函数**:替换字符串中的特定部分。\n\n17. **字符串的查找和替换**\n - **结合使用 `find()` 和 `replace()`**:查找所有匹配的子字符串并进行替换。\n\n18. **字符串的插入和删除**\n - **`insert()` 和 `erase()` 函数**:在指定位置插入和删除字符或子字符串。\n\n19. **字符串的查找和计数**\n - **查找所有出现的位置**:使用 `find()` 循环查找子字符串所有出现的位置。\n - **使用 `count_if` 统计特定字符的出现次数**:通过 `std::count_if` 和 Lambda 表达式统计满足条件的字符数量。\n\n20. **字符串的格式化输出**\n - **使用 `stringstream` 进行格式化**:结合字符串流 `stringstream` 实现复杂的字符串格式化操作。\n\n### 运行示例\n\n编译并运行上述代码,可以看到以下示例输出:\n\n```\n字符串初始化示例:\nstr1: Hello, World!\nstr2: Hello, C++!\nstr3: AAAAA\nstr4: Hello, World!\nstr5: World\n\n字符串连接示例:\nstr6: Hello, World! Hello, C++! AAAAA Hello, World!\n\n字符串访问和修改示例:\nstr1: hello, world!\nstr1[0]: H\nstr1.at(7): W\n\n字符串查找示例:\nstr6.find(\"C++\"): 20\nstr6.find(\"Python\"): 未找到\nstr6.find(\"Hello\", 10): 14\n\n字符串替换示例:\nstr7: Hi, C++ Hello, World!\n\n使用下标遍历 str1: h e l l o , w o r l d ! \n使用范围 for 遍历 str2: H e l l o , C + + ! \n使用迭代器遍历 str3: A A A A A \n\n字符串插入和删除示例:\nstr8: I love C++.\n\n字符串比较示例:\nstr1 == str2: 不同\nstr1.compare(str2): -1\n\n字符串分割示例:\napple banana cherry dragonfruit \n\n字符串大小写转换示例:\nstr10 (大写): HELLO, WORLD!\nstr11 (小写): hello, world!\n\n字符串与数字转换示例:\nnumber: 12345 -> numStr1: 12345\npi: 3.14159 -> numStr2: 3.141590\nnumStr3: 67890 -> parsedInt: 67890\nnumStr4: 2.71828 -> parsedDouble: 2.71828\n\n字符串其他常用函数示例:\nstr12: Sample String\nstr12.size(): 13\nstr12.length(): 13\nstr12.empty(): 不是空的\nstr13 清空后: \"\"\n\n字符串子串提取示例:\nstr14: The quick brown fox jumps over the lazy dog\nsubStr1: quick\nsubStr2: fox jumps over the lazy dog\n\n字符串插入和删除示例:\nstr15: Hello, C++ World!\n\n字符串比较示例:\nstr16: apple, str17: banana\nstr16 < str17: true\n\n字符串替换示例:\nstr18: I love C++.\n\n字符串查找和替换示例:\nstr19: The rXYZ in SpXYZ stays mXYZly in the plXYZ.\n\nstr21: banana\nstr22: Mississippi\n元音字母出现次数: 4\n\n字符串格式化输出示例:\nstr23: Name: Alice, Age: 30, Height: 5.600000 feet.\n```\n\n### 总结\n\n通过上述代码示例和详细注释,全面展示了C++ `std::string` 库的各种功能和使用方法。掌握这些基本操作对于进行高效的字符串处理和编程开发至关重要。希望本示例能够帮助您更好地理解和应用C++中的字符串库。", + "编程语言/C++/标准库解析/vector库.md": "```cpp\n#include \n#include \n#include // 用于算法函数,如 std::sort, std::find\n#include // 用于迭代器\n#include // 用于数值算法,如 std::accumulate\n#include // 用于函数对象,如 std::greater\n\nusing namespace std;\n\n/*\n * 本程序通过一个示例,详细总结和演示了C++中std::vector库的各种使用方法。\n * 涵盖了向量的初始化、添加元素、访问元素、修改元素、遍历、插入和删除、\n * 迭代器的使用、排序和搜索、容量管理、二维向量、与算法的结合等功能。\n */\n\nint main() {\n // 1. 向量的初始化\n // a. 默认初始化(空向量)\n vector vec1;\n \n // b. 使用指定大小初始化,元素默认值为0\n vector vec2(5); // [0, 0, 0, 0, 0]\n \n // c. 使用指定大小和初始值初始化\n vector vec3(5, 10); // [10, 10, 10, 10, 10]\n \n // d. 使用数组初始化\n int arr[] = {1, 2, 3, 4, 5};\n vector vec4(arr, arr + sizeof(arr)/sizeof(int)); // [1, 2, 3, 4, 5]\n \n // e. 使用初始化列表\n vector vec5 = {\"apple\", \"banana\", \"cherry\"};\n \n // 输出初始化后的向量\n cout << \"向量初始化示例:\" << endl;\n cout << \"vec1 (空向量) 的大小: \" << vec1.size() << endl;\n cout << \"vec2: \";\n for(auto num : vec2) cout << num << ' ';\n cout << endl;\n cout << \"vec3: \";\n for(auto num : vec3) cout << num << ' ';\n cout << endl;\n cout << \"vec4: \";\n for(auto num : vec4) cout << num << ' ';\n cout << endl;\n cout << \"vec5: \";\n for(auto &str : vec5) cout << str << ' ';\n cout << endl << endl;\n\n // 2. 添加元素\n // a. 使用 push_back() 添加单个元素\n vec1.push_back(100);\n vec1.push_back(200);\n \n // b. 使用 emplace_back() 直接在末尾构造元素\n vec5.emplace_back(\"date\"); // 添加 \"date\" 到 vec5\n \n // c. 使用 insert() 在指定位置插入元素\n vec4.insert(vec4.begin() + 2, 99); // 在第三个位置插入99\n \n // 输出添加元素后的向量\n cout << \"添加元素示例:\" << endl;\n cout << \"vec1: \";\n for(auto num : vec1) cout << num << ' ';\n cout << endl;\n cout << \"vec4 (插入99): \";\n for(auto num : vec4) cout << num << ' ';\n cout << endl;\n cout << \"vec5 (emplace_back 'date'): \";\n for(auto &str : vec5) cout << str << ' ';\n cout << endl << endl;\n\n // 3. 访问元素\n // a. 使用下标访问(不安全,越界不会检查)\n int firstElement = vec4[0]; // 1\n \n // b. 使用 at() 函数访问(安全,会检查越界)\n int thirdElement = vec4.at(2); // 99\n \n // c. 使用 front() 和 back() 访问首尾元素\n int frontElement = vec4.front(); // 1\n int backElement = vec4.back(); // 5\n \n // 输出访问元素的结果\n cout << \"访问元素示例:\" << endl;\n cout << \"vec4[0]: \" << firstElement << endl;\n cout << \"vec4.at(2): \" << thirdElement << endl;\n cout << \"vec4.front(): \" << frontElement << endl;\n cout << \"vec4.back(): \" << backElement << endl << endl;\n\n // 4. 修改元素\n // a. 通过下标修改\n vec4[2] = 150; // 将第三个元素从99改为150\n \n // b. 通过 at() 修改\n vec5.at(1) = \"blueberry\"; // 将第二个元素从 \"banana\" 改为 \"blueberry\"\n \n // 输出修改后的向量\n cout << \"修改元素示例:\" << endl;\n cout << \"vec4 (修改第三个元素为150): \";\n for(auto num : vec4) cout << num << ' ';\n cout << endl;\n cout << \"vec5 (修改第二个元素为 'blueberry'): \";\n for(auto &str : vec5) cout << str << ' ';\n cout << endl << endl;\n\n // 5. 向量的遍历\n // a. 使用索引遍历\n cout << \"使用索引遍历 vec4: \";\n for(size_t i = 0; i < vec4.size(); ++i) {\n cout << vec4[i] << ' ';\n }\n cout << endl;\n \n // b. 使用范围-based for 循环遍历\n cout << \"使用范围-based for 遍历 vec5: \";\n for(auto &str : vec5) {\n cout << str << ' ';\n }\n cout << endl;\n \n // c. 使用迭代器遍历\n cout << \"使用迭代器遍历 vec3: \";\n for(vector::iterator it = vec3.begin(); it != vec3.end(); ++it) {\n cout << *it << ' ';\n }\n cout << endl << endl;\n\n // 6. 插入和删除元素\n // a. 在中间插入元素\n vec2.insert(vec2.begin() + 2, 50); // 在第三个位置插入50\n \n // b. 删除特定位置的元素\n vec2.erase(vec2.begin() + 1); // 删除第二个元素\n \n // c. 使用 pop_back() 删除末尾元素\n vec1.pop_back(); // 删除 vec1 的最后一个元素 (200)\n \n // d. 清空向量\n // vec3.clear(); // 取消注释将清空 vec3\n \n // 输出插入和删除后的向量\n cout << \"插入和删除元素示例:\" << endl;\n cout << \"vec2 (插入50并删除第二个元素): \";\n for(auto num : vec2) cout << num << ' ';\n cout << endl;\n cout << \"vec1 (pop_back): \";\n for(auto num : vec1) cout << num << ' ';\n cout << endl;\n // cout << \"vec3 清空后大小: \" << vec3.size() << endl;\n cout << endl;\n\n // 7. 迭代器的使用\n // a. 反向迭代器\n cout << \"使用反向迭代器遍历 vec4: \";\n for(auto rit = vec4.rbegin(); rit != vec4.rend(); ++rit) {\n cout << *rit << ' ';\n }\n cout << endl;\n \n // b. 常量迭代器\n cout << \"使用常量迭代器遍历 vec5: \";\n for(auto cit = vec5.cbegin(); cit != vec5.cend(); ++cit) {\n cout << *cit << ' ';\n }\n cout << endl << endl;\n\n // 8. 向量的大小和容量管理\n // a. size() 和 capacity()\n cout << \"向量大小和容量示例:\" << endl;\n cout << \"vec4 的大小: \" << vec4.size() << endl;\n cout << \"vec4 的容量: \" << vec4.capacity() << endl;\n \n // b. reserve() 预留容量\n vec4.reserve(20); // 预留至少20个元素的空间\n cout << \"vec4 预留容量后的容量: \" << vec4.capacity() << endl;\n \n // c. resize() 改变向量大小\n vec4.resize(10, 999); // 将 vec4 的大小调整为10,不足部分填充999\n cout << \"vec4 resize(10, 999) 后: \";\n for(auto num : vec4) cout << num << ' ';\n cout << endl << endl;\n\n // 9. 向量的排序和搜索\n // a. 使用 sort() 对向量进行排序\n vector vec6 = {5, 2, 9, 1, 5, 6};\n sort(vec6.begin(), vec6.end()); // [1, 2, 5, 5, 6, 9]\n \n // b. 使用 binary_search() 搜索元素(需要已排序)\n bool found = binary_search(vec6.begin(), vec6.end(), 5); // true\n bool notFound = binary_search(vec6.begin(), vec6.end(), 3); // false\n \n // c. 使用 find() 搜索元素\n auto it = find(vec6.begin(), vec6.end(), 6);\n \n // 输出排序和搜索的结果\n cout << \"向量排序和搜索示例:\" << endl;\n cout << \"vec6 排序后: \";\n for(auto num : vec6) cout << num << ' ';\n cout << endl;\n cout << \"binary_search 5: \" << (found ? \"找到\" : \"未找到\") << endl;\n cout << \"binary_search 3: \" << (notFound ? \"找到\" : \"未找到\") << endl;\n if(it != vec6.end())\n cout << \"find 6 的位置索引: \" << distance(vec6.begin(), it) << endl;\n else\n cout << \"find 6: 未找到\" << endl;\n cout << endl;\n\n // 10. 使用算法与向量结合\n // a. 计算向量元素的总和\n int sum = accumulate(vec6.begin(), vec6.end(), 0); // 1 + 2 + 5 + 5 + 6 + 9 = 28\n \n // b. 统计特定元素的数量\n int count_five = count(vec6.begin(), vec6.end(), 5); // 2\n \n // c. 使用 lambda 表达式和 for_each\n cout << \"使用算法与向量结合示例:\" << endl;\n cout << \"vec6 的总和: \" << sum << endl;\n cout << \"vec6 中5的数量: \" << count_five << endl;\n \n cout << \"vec6 的元素乘以2: \";\n for_each(vec6.begin(), vec6.end(), [](int &x) { x *= 2; });\n for(auto num : vec6) cout << num << ' ';\n cout << endl << endl;\n\n // 11. 二维向量\n // a. 创建二维向量\n vector> matrix;\n matrix.resize(3, vector(4, 0)); // 3行4列,所有元素初始化为0\n \n // b. 访问和修改二维向量元素\n matrix[0][0] = 1;\n matrix.at(1).at(2) = 5;\n matrix[2][3] = 9;\n \n // c. 遍历二维向量\n cout << \"二维向量示例:\" << endl;\n for(size_t i = 0; i < matrix.size(); ++i) {\n for(size_t j = 0; j < matrix[i].size(); ++j) {\n cout << matrix[i][j] << ' ';\n }\n cout << endl;\n }\n cout << endl;\n\n // 12. 向量的清空和检查\n // a. 使用 clear() 清空向量\n vec6.clear();\n \n // b. 使用 empty() 检查向量是否为空\n bool isVec6Empty = vec6.empty();\n \n // 输出清空和检查的结果\n cout << \"向量清空和检查示例:\" << endl;\n cout << \"vec6 清空后大小: \" << vec6.size() << endl;\n cout << \"vec6 是否为空: \" << (isVec6Empty ? \"是空的\" : \"不是空的\") << endl << endl;\n\n // 13. 向量的交换\n // a. 使用 swap() 交换两个向量的内容\n vector vec7 = {7, 8, 9};\n vector vec8 = {10, 11};\n cout << \"交换前:\" << endl;\n cout << \"vec7: \";\n for(auto num : vec7) cout << num << ' ';\n cout << endl;\n cout << \"vec8: \";\n for(auto num : vec8) cout << num << ' ';\n cout << endl;\n \n vec7.swap(vec8); // 交换 vec7 和 vec8 的内容\n \n cout << \"交换后:\" << endl;\n cout << \"vec7: \";\n for(auto num : vec7) cout << num << ' ';\n cout << endl;\n cout << \"vec8: \";\n for(auto num : vec8) cout << num << ' ';\n cout << endl << endl;\n\n // 14. 向量与自定义类型\n // a. 定义一个自定义结构体\n struct Person {\n string name;\n int age;\n \n // 重载输出运算符以便打印\n friend ostream& operator<<(ostream &os, const Person &p) {\n os << \"{Name: \" << p.name << \", Age: \" << p.age << \"}\";\n return os;\n }\n };\n \n // b. 创建向量并添加自定义类型元素\n vector people;\n people.push_back(Person{\"Alice\", 30});\n people.emplace_back(Person{\"Bob\", 25});\n \n // c. 访问和修改自定义类型元素\n people[0].age = 31;\n \n // d. 遍历自定义类型向量\n cout << \"向量与自定义类型示例:\" << endl;\n for(auto &person : people) {\n cout << person << ' ';\n }\n cout << endl << endl;\n\n // 15. 向量的复制和赋值\n // a. 使用拷贝构造函数\n vector vec9 = vec2;\n \n // b. 使用赋值运算符\n vector vec10;\n vec10 = vec4;\n \n // 输出复制和赋值后的向量\n cout << \"向量复制和赋值示例:\" << endl;\n cout << \"vec9 (拷贝自 vec2): \";\n for(auto num : vec9) cout << num << ' ';\n cout << endl;\n cout << \"vec10 (赋值自 vec4): \";\n for(auto num : vec10) cout << num << ' ';\n cout << endl << endl;\n\n // 16. 向量的比较\n // a. 使用 == 运算符\n bool areVec9Vec10Equal = (vec9 == vec10);\n \n // b. 使用 != 运算符\n bool areVec2Vec3NotEqual = (vec2 != vec3);\n \n // 输出比较结果\n cout << \"向量比较示例:\" << endl;\n cout << \"vec9 == vec10: \" << (areVec9Vec10Equal ? \"相等\" : \"不相等\") << endl;\n cout << \"vec2 != vec3: \" << (areVec2Vec3NotEqual ? \"不相等\" : \"相等\") << endl << endl;\n\n // 17. 向量的嵌套与操作\n // a. 创建一个向量的向量\n vector> vecOfVec;\n vecOfVec.push_back({\"C++\", \"Java\"});\n vecOfVec.emplace_back(vector{\"Python\", \"JavaScript\"});\n \n // b. 访问嵌套向量的元素\n cout << \"向量的嵌套与操作示例:\" << endl;\n for(size_t i = 0; i < vecOfVec.size(); ++i) {\n cout << \"子向量 \" << i << \": \";\n for(auto &lang : vecOfVec[i]) {\n cout << lang << ' ';\n }\n cout << endl;\n }\n cout << endl;\n\n // 18. 向量的迭代器高级用法\n // a. 使用 insert_iterator 和 back_inserter\n vector vec11 = {1, 2, 3};\n vector vec12 = {4, 5, 6};\n copy(vec12.begin(), vec12.end(), back_inserter(vec11)); // 将 vec12 追加到 vec11\n \n // b. 使用 reverse_iterator\n cout << \"使用 back_inserter 追加 vec12 到 vec11: \";\n for(auto num : vec11) cout << num << ' ';\n cout << endl;\n \n // c. 反转 vec11\n reverse(vec11.begin(), vec11.end());\n cout << \"反转后的 vec11: \";\n for(auto num : vec11) cout << num << ' ';\n cout << endl << endl;\n\n // 19. 向量的异常处理\n // a. 使用 try-catch 捕获 out_of_range 异常\n try {\n int invalidAccess = vec2.at(100); // 超出范围\n } catch(const out_of_range &e) {\n cout << \"异常处理示例:\" << endl;\n cout << \"尝试访问 vec2.at(100) 产生异常: \" << e.what() << endl << endl;\n }\n\n // 20. 向量的内存管理\n // a. 使用 shrink_to_fit() 缩减容量\n cout << \"向量内存管理示例:\" << endl;\n cout << \"vec4 的容量: \" << vec4.capacity() << endl;\n vec4.shrink_to_fit(); // 请求缩减容量以匹配大小\n cout << \"vec4 使用 shrink_to_fit() 后的容量: \" << vec4.capacity() << endl;\n \n return 0;\n}\n```\n\n### 代码详解\n\n1. **向量的初始化**\n - **默认初始化**:创建一个空的 `std::vector` 对象 `vec1`,初始大小为0。\n - **指定大小初始化**:`vec2` 被初始化为包含5个元素,每个元素的默认值为0。\n - **指定大小和初始值初始化**:`vec3` 被初始化为包含5个元素,每个元素的值为10。\n - **数组初始化**:使用一个整数数组 `arr` 初始化 `vec4`,向量中包含数组中的元素 `[1, 2, 3, 4, 5]`。\n - **初始化列表**:`vec5` 被初始化为包含字符串 `\"apple\"`, `\"banana\"`, `\"cherry\"`。\n\n2. **添加元素**\n - **`push_back()`**:向 `vec1` 添加两个元素 `100` 和 `200`,使其变为 `[100, 200]`。\n - **`emplace_back()`**:直接在 `vec5` 的末尾构造并添加字符串 `\"date\"`,变为 `[\"apple\", \"banana\", \"cherry\", \"date\"]`。\n - **`insert()`**:在 `vec4` 的第三个位置插入元素 `99`,使其变为 `[1, 2, 99, 3, 4, 5]`。\n\n3. **访问元素**\n - **下标访问**:通过 `vec4[0]` 访问第一个元素 `1`,但这种方式不安全,因为不会检查索引是否越界。\n - **`at()` 函数访问**:通过 `vec4.at(2)` 安全地访问第三个元素 `99`,如果索引越界,会抛出异常。\n - **`front()` 和 `back()`**:分别访问 `vec4` 的第一个元素 `1` 和最后一个元素 `5`。\n\n4. **修改元素**\n - **通过下标修改**:将 `vec4` 的第三个元素从 `99` 修改为 `150`,使其变为 `[1, 2, 150, 3, 4, 5]`。\n - **通过 `at()` 修改**:将 `vec5` 的第二个元素从 `\"banana\"` 修改为 `\"blueberry\"`,变为 `[\"apple\", \"blueberry\", \"cherry\", \"date\"]`。\n\n5. **向量的遍历**\n - **索引遍历**:使用传统的 `for` 循环通过索引访问 `vec4` 的每个元素。\n - **范围-based for 循环**:使用 C++11 的范围-based `for` 循环遍历 `vec5` 中的每个字符串。\n - **迭代器遍历**:使用迭代器从 `vec3` 的 `begin()` 到 `end()` 遍历其元素。\n\n6. **插入和删除元素**\n - **中间插入**:在 `vec2` 的第三个位置插入 `50`,使其变为 `[0, 0, 50, 0, 0]`。\n - **删除特定位置的元素**:删除 `vec2` 的第二个元素,结果为 `[0, 50, 0, 0]`。\n - **`pop_back()`**:删除 `vec1` 的最后一个元素 `200`,使其变为 `[100]`。\n - **清空向量**:通过 `vec3.clear()` 可以清空 `vec3` 的所有元素(此行代码被注释掉,可以根据需要取消注释)。\n\n7. **迭代器的使用**\n - **反向迭代器**:使用 `rbegin()` 和 `rend()` 反向遍历 `vec4` 的元素,从最后一个元素到第一个元素。\n - **常量迭代器**:使用 `cbegin()` 和 `cend()` 常量迭代器遍历 `vec5`,确保元素不被修改。\n\n8. **向量的大小和容量管理**\n - **`size()` 和 `capacity()`**:`size()` 返回向量当前包含的元素数量,`capacity()` 返回向量当前分配的内存空间(以元素为单位)。\n - **`reserve()`**:预留向量的容量,可以减少未来的内存重新分配。例如,`vec4.reserve(20)` 预留至少20个元素的空间。\n - **`resize()`**:调整向量的大小。`vec4.resize(10, 999)` 将 `vec4` 的大小调整为10,如果原本大小不足,新增的元素将被初始化为 `999`。\n\n9. **向量的排序和搜索**\n - **`sort()`**:使用 `std::sort` 对 `vec6` 进行排序,结果为 `[1, 2, 5, 5, 6, 9]`。\n - **`binary_search()`**:在已排序的 `vec6` 中搜索元素 `5` 和 `3`,分别返回 `true` 和 `false`。\n - **`find()`**:使用 `std::find` 在 `vec6` 中查找元素 `6`,并输出其位置索引。\n\n10. **使用算法与向量结合**\n - **`accumulate()`**:计算 `vec6` 中所有元素的总和,结果为 `28`。\n - **`count()`**:统计 `vec6` 中元素 `5` 的数量,结果为 `2`。\n - **`for_each()`**:使用 `std::for_each` 和 Lambda 表达式将 `vec6` 中的每个元素乘以2,修改后的 `vec6` 为 `[2, 4, 10, 10, 12, 18]`。\n\n11. **二维向量**\n - **创建二维向量**:`matrix` 被初始化为一个3行4列的二维向量,所有元素初始化为 `0`。\n - **访问和修改**:通过下标访问并修改特定位置的元素,如 `matrix[0][0] = 1`,`matrix.at(1).at(2) = 5`,`matrix[2][3] = 9`。\n - **遍历二维向量**:使用嵌套的 `for` 循环遍历 `matrix`,输出其元素。\n\n12. **向量的清空和检查**\n - **`clear()`**:清空 `vec6` 的所有元素,使其大小变为0。\n - **`empty()`**:检查 `vec6` 是否为空,返回 `true` 表示为空。\n\n13. **向量的交换**\n - **`swap()`**:交换 `vec7` 和 `vec8` 的内容。交换前 `vec7 = [7, 8, 9]`,`vec8 = [10, 11]`;交换后 `vec7 = [10, 11]`,`vec8 = [7, 8, 9]`。\n\n14. **向量与自定义类型**\n - **自定义结构体**:定义了一个 `Person` 结构体,包含 `name` 和 `age`,并重载了输出运算符以便打印。\n - **创建和操作自定义类型向量**:创建 `people` 向量,添加 `Person` 对象,修改元素,并遍历输出。\n\n15. **向量的复制和赋值**\n - **拷贝构造**:使用拷贝构造函数创建 `vec9`,复制自 `vec2`。\n - **赋值运算符**:使用赋值运算符将 `vec4` 的内容赋值给 `vec10`。\n - **输出复制和赋值后的向量**:展示 `vec9` 和 `vec10` 的内容。\n\n16. **向量的比较**\n - **`==` 运算符**:比较 `vec9` 和 `vec10` 是否相等。\n - **`!=` 运算符**:比较 `vec2` 和 `vec3` 是否不相等。\n - **输出比较结果**:根据比较结果输出相应的信息。\n\n17. **向量的嵌套与操作**\n - **创建向量的向量**:`vecOfVec` 被初始化为一个包含两个子向量的二维向量。\n - **访问嵌套向量的元素**:遍历 `vecOfVec` 并输出每个子向量的元素。\n\n18. **向量的迭代器高级用法**\n - **`back_inserter` 和 `copy()`**:使用 `std::back_inserter` 将 `vec12` 的元素复制并追加到 `vec11`。\n - **反转向量**:使用 `std::reverse` 反转 `vec11` 的元素。\n\n19. **向量的异常处理**\n - **异常捕获**:尝试通过 `vec2.at(100)` 访问超出范围的元素,使用 `try-catch` 捕获并处理 `out_of_range` 异常。\n\n20. **向量的内存管理**\n - **`shrink_to_fit()`**:请求 `vec4` 缩减其容量以匹配当前的大小,减少内存占用。\n\n### 运行示例\n\n编译并运行上述代码,可以看到以下示例输出:\n\n```\n向量初始化示例:\nvec1 (空向量) 的大小: 0\nvec2: 0 0 0 0 0 \nvec3: 10 10 10 10 10 \nvec4: 1 2 3 4 5 \nvec5: apple banana cherry \n\n添加元素示例:\nvec1: 100 200 \nvec4 (插入99): 1 2 99 3 4 5 \nvec5 (emplace_back 'date'): apple banana cherry date \n\n访问元素示例:\nvec4[0]: 1\nvec4.at(2): 99\nvec4.front(): 1\nvec4.back(): 5\n\n修改元素示例:\nvec4 (修改第三个元素为150): 1 2 150 3 4 5 \nvec5 (修改第二个元素为 'blueberry'): apple blueberry cherry date \n\n使用索引遍历 vec4: 1 2 150 3 4 5 \n使用范围-based for 遍历 vec5: apple blueberry cherry date \n使用迭代器遍历 vec3: 10 10 10 10 10 \n\n插入和删除元素示例:\nvec2 (插入50并删除第二个元素): 0 50 0 0 \nvec1 (pop_back): 100 \n\n使用反向迭代器遍历 vec4: 5 4 3 150 2 1 \n使用常量迭代器遍历 vec5: apple blueberry cherry date \n\n向量大小和容量示例:\nvec4 的大小: 6\nvec4 的容量: 6\nvec4 预留容量后的容量: 20\nvec4 resize(10, 999) 后: 1 2 150 3 4 5 999 999 999 999 \n\n向量排序和搜索示例:\nvec6 排序后: 1 2 5 5 6 9 \nbinary_search 5: 找到\nbinary_search 3: 未找到\nfind 6 的位置索引: 4\n\n使用算法与向量结合示例:\nvec6 的总和: 28\nvec6 中5的数量: 2\nvec6 的元素乘以2: 2 4 10 10 12 18 \n\n二维向量示例:\n1 0 0 0 \n0 0 5 0 \n0 0 0 9 \n\n向量清空和检查示例:\nvec6 清空后大小: 0\nvec6 是否为空: 是空的\n\n向量复制和赋值示例:\nvec9 (拷贝自 vec2): 0 50 0 0 \nvec10 (赋值自 vec4): 1 2 150 3 4 5 999 999 999 999 \n\n向量比较示例:\nvec9 == vec10: 不相等\nvec2 != vec3: 相等\n\n向量的嵌套与操作示例:\n子向量 0: C++ Java \n子向量 1: Python JavaScript \n\n使用 back_inserter 追加 vec12 到 vec11: 1 2 3 4 5 6 \n反转后的 vec11: 6 5 4 3 2 1 \n\n异常处理示例:\n尝试访问 vec2.at(100) 产生异常: vector::_M_range_check: __n (which is 100) >= this->size() (which is 4)\n\n向量内存管理示例:\nvec4 的容量: 20\nvec4 使用 shrink_to_fit() 后的容量: 10\n```\n\n### 总结\n\n通过上述代码示例和详细注释,全面展示了C++ `std::vector` 库的各种功能和使用方法。掌握这些基本操作对于进行高效的动态数组处理和编程开发至关重要。希望本示例能够帮助您更好地理解和应用C++中的向量库。", + "编程语言/CSharp/mono和dotnet的区别.md": "Mono 和 .NET(尤其是 .NET Core/5+)均为跨平台的 .NET 生态实现,但在背景、定位和特性上存在显著差异:\n \n1. 背景与归属\n \n- .NET(官方)\n \n- 由微软主导开发,最初是 Windows 专属框架(.NET Framework)。\n- 2016 年推出开源跨平台的 .NET Core,后整合为 .NET 5+,成为统一的跨平台版本。\n- 官方支持 Windows、macOS、Linux 等主流系统,强调高性能和现代化开发。\n- Mono\n \n- 由第三方团队(Xamarin,后被微软收购)于 2000 年代初开发,是最早的跨平台 .NET 实现。\n- 目标是将 .NET 框架移植到非 Windows 系统(如 Linux、macOS、Android、iOS 等)。\n- 开源但实现进度滞后于官方版本,依赖社区维护。\n \n2. 核心差异\n \n特性 .NET(Core/5+) Mono \n类库 官方提供 CoreFX(精简且持续更新) 部分兼容 .NET 类库,但存在功能缺失或延迟 \n运行时 CoreCLR(优化性能,支持 JIT/AOT) Mono VM(需适配多平台,维护成本高) \n兼容性 高度兼容 .NET Framework 应用 对旧版 .NET 支持较好,但新特性支持不足 \n性能 针对现代工作负载优化,速度更快 性能稍弱,尤其在复杂场景(如 Web 服务) \n生态支持 官方支持力度大,社区活跃,第三方库丰富 社区较小,依赖特定领域(如 Unity 早期) \n \n3. 典型应用场景\n \n- .NET(Core/5+)\n \n- 现代 Web 应用、云服务、微服务、桌面应用(通过 MAUI)。\n- 适合追求高性能和长期稳定性的项目。\n- Mono\n \n- 遗留 .NET 应用跨平台迁移(如 Linux 服务器)。\n- 游戏开发(Unity 早期依赖 Mono,但现已转向 .NET)。\n- 对实时编译限制严格的场景(如 iOS 的 AOT 模式)。\n \n4. 总结\n \n- 选择 .NET:若需官方支持、高性能和最新技术(如云原生、微服务),优先选 .NET 5+。\n- 选择 Mono:若需兼容旧版 .NET 应用或特定平台(如早期 Unity 项目),可考虑 Mono。\n \n两者最终目标一致(跨平台运行 .NET 应用),但 .NET 作为官方方案更具前瞻性,而 Mono 更偏向历史兼容性。", + "编程语言/Flutter/Flutter安卓构建注意事项.md": "\n\n```powershell\n#国内优先使用这个地址构建\n$env:FLUTTER_STORAGE_BASE_URL=\"https://storage.flutter-io.cn\"; $env:PUB_HOSTED_URL=\"https://pub.flutter-io.cn\"; flutter build apk --release \n\n#再使用这个运行\nflutter run\n```\n\n\n记得修改一下项目android\\app\\build.gradle.kts文件的包名\n    namespace = \"com.example.farmvisualconfig\"", + "编程语言/Flutter/Flutter常用命令.md": "\n---\n\n## 🛠️ 环境配置相关\n\n```bash\nflutter --version # 查看 Flutter 版本\nflutter upgrade # 升级 Flutter SDK\nflutter downgrade # 降级到上一个版本\nflutter doctor # 检查环境配置\nflutter config --enable-windows-desktop # 启用 Windows 桌面支持\nflutter config --enable-web # 启用 Web 支持\nflutter devices # 查看可用设备\n```\n\n---\n\n## 📦 项目管理\n\n```bash\nflutter create my_app # 创建新项目\nflutter clean # 清理构建缓存\nflutter pub get # 获取依赖\nflutter pub upgrade # 升级依赖\nflutter pub outdated # 检查依赖可更新版本\nflutter pub add http # 添加依赖(例如 http)\nflutter pub remove http # 移除依赖\n```\n\n---\n\n## ▶️ 运行调试\n\n```bash\nflutter run # 在默认设备上运行\nflutter run -d windows # 在 Windows 桌面运行\nflutter run -d chrome # 在浏览器运行\nflutter run -d emulator-5554 # 指定设备运行(比如 Android 模拟器)\n```\n\n---\n\n## 🏗️ 构建打包\n\n```bash\nflutter build apk # 构建 Android APK\nflutter build appbundle # 构建 Android AAB (上传 Google Play)\nflutter build ios # 构建 iOS 应用\nflutter build windows # 构建 Windows 应用\nflutter build web # 构建 Web 应用\nflutter build linux # 构建 Linux 应用\nflutter build macos # 构建 macOS 应用\n```\n\n---\n\n## 🔄 热重载 / 热重启\n\n运行 `flutter run` 后,命令行里可以:\n\n- `r` → 热重载(Hot reload,保留状态)\n \n- `R` → 热重启(Hot restart,重启应用)\n \n- `q` → 退出运行\n \n\n---\n\n## 🔍 代码检查 & 性能\n\n```bash\nflutter analyze # 分析代码问题\nflutter format . # 格式化代码(整个项目)\nflutter test # 运行单元测试\nflutter pub run build_runner build # 代码生成(json_serializable 等常用)\n```\n\n---\n\n## 🌐 其他常用\n\n```bash\ndart --version # 查看 Dart 版本\ndart pub global activate devtools # 启用 DevTools\nflutter pub global run devtools # 启动 DevTools\n```\n\n---\n\n📌 **最常用的组合命令**:\n\n1. `flutter pub get` → 拉依赖\n \n2. `flutter run -d windows` → 运行调试\n \n3. `flutter build windows` → 打包 Windows\n \n4. `flutter clean && flutter pub get` → 出问题时清理依赖\n \n\n---\n", + "编程语言/Flutter/Flutter构建平台产物位置.md": "\n### 一、通用说明\n\nFlutter 项目的构建产物默认存放在项目根目录的 build 文件夹下,该文件夹会根据目标平台自动创建子目录,存放对应平台的编译文件、安装包等。\n\n### 二、各个平台构建产物位置\n\n#### 1. Android 平台\n\n**构建命令**:\nflutter build apk(默认 release 模式)、flutter build appbundle(AAB 格式)\n\n**产物位置**:\nAPK 文件:\n项目根目录/build/app/outputs/flutter-apk/\n文件名通常为 app-release.apk(release 模式)或 app-debug.apk(debug 模式)。\n\nAAB 文件(Android App Bundle):\n项目根目录/build/app/outputs/bundle/release/app-release.aab\n\n#### 2. iOS 平台\n\n**构建命令**:\nflutter build ios(release 模式)、flutter build ios --debug(debug 模式)\n\n**产物位置**:\n编译后的应用文件(.app 格式):\n项目根目录/build/ios/iphoneos/Runner.app(真机运行)或 build/ios/iphonesimulator/Runner.app(模拟器)。\n\nIPA 安装包(需通过 Xcode 导出):\n若使用 flutter build ipa 命令,产物会存放在 项目根目录/build/ios/ipa/,文件名为 Runner.ipa。\n\n#### 3. 桌面平台(Windows/macOS/Linux)\n\n需先通过 flutter config --enable-[windows/macos/linux]-desktop 开启对应平台支持。\n\n***Windows**:*\n\n**构建命令:**\nflutter build windows\n\n**产物位置:**\n项目根目录/build/windows/runner/Release/(release 模式),包含可执行文件 Runner.exe 及相关依赖库。\n\n***macOS:***\n\n**构建命令:**\nflutter build macos\n\n**产物位置:**\n项目根目录/build/macos/Build/Products/Release/Runner.app(release 模式),这是一个 macOS 应用包。\n\n***Linux**:*\n\n**构建命令:**\nflutter build linux\n\n**产物位置:**\n项目根目录/build/linux/x64/release/bundle/(64 位系统),包含可执行文件 runner 及依赖文件。\n\n#### 4. Web 平台\n\n**构建命令**:\nflutter build web(默认 release 模式)\n\n**产物位置**:\n项目根目录/build/web/,包含 HTML、CSS、JavaScript 等静态文件,可直接部署到 Web 服务器(如 Nginx、Apache 等)。\n\n### 三、注意事项\n\n- **debug 与 release 模式**:debug 模式的产物通常用于开发调试,体积较大且包含调试信息;release 模式产物经过优化,适合发布,默认存放在对应平台的 release 子目录中。\n\n- **自定义输出路径**:部分命令支持通过参数指定输出路径,例如 flutter build apk --output=./my_app.apk 可将 APK 输出到根目录并命名为 my_app.apk。\n", + "编程语言/Java/Java基础-导入java文件.md": "\n## 🔹 情况 1:同一个包里的多个.java文件\n\n如果两个类在同一个包(或者没写 `package`,都在默认包),\n只要把它们放在同一个目录下,直接编译就能互相使用。\n\n例子:\n\n📂 目录结构:\n\n```\nHelloWorld.java\nUtils.java\n```\n\n**HelloWorld.java**\n\n```java\npublic class HelloWorld {\n public static void main(String[] args) {\n Utils.sayHi();\n }\n}\n```\n\n**Utils.java**\n\n```java\npublic class Utils {\n public static void sayHi() {\n System.out.println(\"Hello from Utils!\");\n }\n}\n```\n\n**编译运行:**\n\n```bash\njavac HelloWorld.java Utils.java\njava HelloWorld\n```\n\n**输出:**\n\n```\nHello from Utils!\n```\n\n---\n\n## 🔹 情况 2:不同包的类\n\n如果你要用别的包里的类,需要用 import\n\n**目录结构:**\n\n```\nsrc/\n ├─ app/\n │ └─ HelloWorld.java\n └─ util/\n └─ Utils.java\n```\n\n**util/Utils.java**\n\n```java\npackage util;\n\npublic class Utils {\n public static void sayHi() {\n System.out.println(\"Hello from util.Utils!\");\n }\n}\n```\n\n**app/HelloWorld.java**\n\n```java\npackage app;\n\nimport util.Utils; // 导入 util 包里的 Utils 类\n\npublic class HelloWorld {\n public static void main(String[] args) {\n Utils.sayHi();\n }\n}\n```\n\n**编译:**\n\n```bash\njavac src/util/Utils.java src/app/HelloWorld.java -d out\n```\n\n**运行:**\n\n```bash\njava -cp out app.HelloWorld\n```\n\n---\n\n## 🔹 总结\n\n1. **同目录、同包**:直接用,不需要 `import`。\n2. **不同目录、不同包**:必须用 `package` 和 `import`,再用 `-d` 编译指定输出目录。\n\n---\n\n", + "编程语言/Python/Kivy/kivy编译安卓APK.md": "\n\n```bash\nsudo apt update && sudo apt upgrade -y\n\n#安装必要的依赖\nsudo apt install -y \\\n build-essential \\\n git \\\n python3 \\\n python3-pip \\\n python3-venv \\\n openjdk-17-jdk \\\n unzip \\\n zip \\\n libffi-dev \\\n libssl-dev \\\n libsqlite3-dev \\\n libjpeg-dev \\\n libfreetype6-dev \\\n libgl1-mesa-dev \\\n libgles2-mesa-dev \\\n zlib1g-dev \\\n autoconf \\\n automake \\\n libtool \\\n pkg-config \\\n cmake \\\n curl \\\n lld \\\n libncurses5\n\n#创建虚拟环境 \npython3 -m venv kivy_env\nsource kivy_env/bin/activate\n\n#升级pip\npip install --upgrade pip setuptools wheel cython\n\n#安装kivy\npip install \"kivy[base]\" kivy_examples\n#检查是否安装成功\npython -m kivy.examples.demo.touchtracer\n\n#安装 Buildozer构建环境\npip install buildozer\n#验证是否安装成功\nbuildozer --version\n\n#初始化 buildozer 配置文件\nbuildozer init\n\n#打包构建apk 开梯子!\nbuildozer android debug\n\n\n```\n\n\n```python\nfrom kivy.app import App\nfrom kivy.uix.label import Label\n\nclass MyApp(App):\n def build(self):\n return Label(text=\"Hello Android from Kivy!\")\n\nif __name__ == \"__main__\":\n MyApp().run()\n\n```\n\n\n\n\n\n\n\n\n\n", + "编程语言/Python/Python国内pip加速镜像.md": "\n---\n\n## 一、常见国内镜像源推荐\n\n以下是一些稳定且速度优异的国内 PyPI 镜像源:\n\n- **清华大学** \n `https://pypi.tuna.tsinghua.edu.cn/simple`\n- **阿里云** \n `https://mirrors.aliyun.com/pypi/simple/`\n- **中国科技大学(USTC)** \n `https://pypi.mirrors.ustc.edu.cn/simple/` \n- **网易** \n `https://mirrors.163.com/pypi/simple/`\n- **豆瓣** \n `http://pypi.douban.com/simple/`(推荐使用 HTTPS 若可用)\n\n---\n\n## 二、临时使用镜像方法(每次安装时添加)\n\n在你激活的虚拟环境中,使用以下方式安装包时手动指定镜像源:\n\n```bash\npip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple\n```\n\n如果镜像为 HTTP,并提示“不受信任”,可额外加上 `--trusted-host` 参数:\n\n```bash\npip install 包名 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com\n```\n\n\n---\n\n## 三、永久配置镜像(适用于当前虚拟环境)\n\n若希望省去每次输入 -i 参数的麻烦,可以在虚拟环境中创建或修改配置文件,使 pip 默认使用国内镜像:\n\n- **Unix / macOS 下虚拟环境:** \n 在虚拟环境目录下 `$VIRTUAL_ENV/pip.conf`\n \n- **Windows 虚拟环境:** \n 在 `%VIRTUAL_ENV%\\pip.ini`\n \n\n在其中添加以下内容(以清华源为例):\n\n```ini\n[global]\ntimeout = 120\nindex-url = https://pypi.tuna.tsinghua.edu.cn/simple\ntrusted-host = pypi.tuna.tsinghua.edu.cn\n```\n\n- `timeout`:设置最长等待时间,例如 **120 秒**,避免连接中断 \n \n- `index-url`:指定清华镜像为默认源\n \n- `trusted-host`:将镜像主机设为可信,避免 HTTPS 以外的警告\n \n\n记住,pip 配置的优先级如下(高到低):\n\n1. 虚拟环境中的配置\n \n2. 当前用户目录中的配置\n \n3. 全局配置(系统范围)\n \n\n---\n\n## 四、另一种永久配置方式:使用 pip config 命令\n\n你也可以通过 pip 自带的命令来设置全局配置(不限于虚拟环境):\n\n```bash\npip config set global.index-url https://mirrors.aliyun.com/pypi/simple/\n```\n\n随后你可以用 `pip config list` 来验证是否设置成功\n\n若想恢复到默认的官方 PyPI 源,可使用:\n\n```bash\npip config unset global.index-url\n```\n\n\n---\n\n## 五、方式对比一览\n\n|方式|优点|缺点|\n|---|---|---|\n|临时 `-i` 指定|简单快速,不改配置|每次需手动指定|\n|虚拟环境配置|仅对该虚拟环境生效|需进入每个环境配置|\n|全局配置|全局生效,无需重复配置|不够灵活,不适每个项目情况|\n\n---\n\n", + "编程语言/Python/Pywebview库功能一览.md": "\n---\n\n## 一、基本概述\n\n- **跨平台原生 WebView 窗口** \n pywebview 是一个轻量级包装库,可在 Python 程序中使用 HTML/CSS/JavaScript 构建 GUI,打开原生的 WebView 窗口,适用于 Windows、macOS、Linux(GTK 或 QT)、Android 平台 ([GitHub](https://github.com/r0x0r/pywebview?utm_source=chatgpt.com \"r0x0r/pywebview: Build GUI for your Python program with ...\"), [pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n\n---\n\n## 二、核心功能分类\n\n### 1. 窗口管理功能\n\n- 使用 `webview.create_window(...)` 创建窗口,可设置属性包括:标题、加载方式(URL 或直接传 HTML)、尺寸(宽高)、位置坐标(x, y)、是否可调整大小、是否全屏、最小尺寸、隐藏窗口、无边框、阴影效果(仅限 Windows)、窗口置顶、关闭确认、背景颜色、透明、文本选择、缩放能力、拖拽能力、暗色模式等 ([pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"), [pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n- `webview.start(...)` 启动 GUI 消息循环,可额外配置回调函数、调试模式、HTTP 服务器、用户代理、隐私模式、存储路径、本地化、菜单设置、图标、SSL 等参数 ([pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"))。\n \n\n---\n\n### 2. JavaScript ↔ Python 双向通信\n\n- 通过 `js_api` 参数将 Python 对象暴露给 JavaScript,以便 JS 调用 Python 方法(返回 Promise);也支持运行时调用: `window.expose(func)` ([pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"), [pywebview.flowrl.com](https://pywebview.flowrl.com/guide/usage?utm_source=chatgpt.com \"Usage | pywebview - Example\"))。\n \n\n---\n\n### 3. 内建 HTTP 服务器支持\n\n- 自动为相对路径启动 Bottle HTTP 服务器;可在 `webview.start(http_server=True, ssl=True)` 中启用,并可传入自定义 WSGI 服务(如 Flask)作为 `url` 参数,或修改默认服务器的 SSL 行为 ([pywebview.flowrl.com](https://pywebview.flowrl.com/guide/usage?utm_source=chatgpt.com \"Usage | pywebview - Example\"), [pywebview.idepy.com](https://pywebview.idepy.com/guide/api?utm_source=chatgpt.com \"API - pywebview中文文档\"))。\n \n\n---\n\n### 4. DOM 操作能力\n\n- 支持在 Python 端进行 DOM 操作,如元素创建、搜索、修改属性或样式,事件注册等,类似 jQuery 操作体验。提供 `window.dom` API,包括 `dom.body`、`dom.document`、`dom.create_element()`、`dom.get_element(s)`,并支持事件监听,如 click、scroll 等 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n- 还支持拖拽文件,并获取完整文件路径 `event['dataTransfer']['files'][0]['pywebviewFullPath']` ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n\n---\n\n### 5. 事件机制\n\n- pywebview 5 引入 DOM 操作及基本事件支持(如 click 等)。\n \n- pywebview 6 提供更先进的网络事件支持,包括 `request_sent` 和 `response_received`,可拦截并修改请求头,还新增 `initialized` 事件(GUI 渲染器选择前触发)可用于配置判定 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 6. 全新共享状态管理(v6)\n\n- `window.state` 对象允许自动同步 JavaScript 和 Python 间的顶层属性状态,无需额外手动同步。例如在 Python 端设置 `window.state.user_name = \"Test\"`,在 JavaScript 中通过 `window.pywebview.state.user_name` 即可访问 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 7. 平台增强功能\n\n- **Android 支持**:pywebview 5 开始支持 Android(虽然功能较限,如不支持文件对话框、多窗口、窗口控制,但基本功能可用)([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n- **pywebview 6 优化 Android**:引入 Kivyless 实现,提高启动速度、减小包体,并支持全屏模式 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 8. 应用设置与 UI 菜单\n\n- **应用级设置**(v5):通过 `webview.settings` 定制行为,如控制文件下载、允许 file:// URL、外链跳转行为、调试模式下自动打开 DevTools 等 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview5.html?utm_source=chatgpt.com \"5.0 has landed - pywebview - Example\"))。\n \n- **窗口级菜单**(v6):可以为每个窗口定义自定义菜单(Menu/MenueAction),类似桌面应用的菜单栏;部分平台(如 GTK + Unity)暂不支持 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n### 9. 平台尤其增强与现代化\n\n- **现代化 API 调整**:pywebview 6 改进了 FileDialog 枚举、设置项存放路径、移除废弃 DOM API 等 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n- **平台特定增强**:\n \n - Windows:支持暗色模式自动识别\n \n - macOS:可隐藏默认菜单、更好的 JS prompt 支持\n \n - 全平台:改进屏幕坐标处理和 SSL 支持 ([pywebview.flowrl.com](https://pywebview.flowrl.com/blog/pywebview6?utm_source=chatgpt.com \"6.0 is here | pywebview - Example\"))。\n \n\n---\n\n## 三、总结表格\n\n|功能分类|详细内容描述|\n|---|---|\n|窗口管理|多平台窗口创建与控制(尺寸、位置、样式等)|\n|JS ↔ Python 通信|js_api 和 expose 提供双向调用|\n|HTTP 服务器|内建 Bottle 服务器,可配置 SSL 与自定义 WSGI|\n|DOM 操作|从 Python 端操作 DOM 元素、事件绑定、拖拽功能|\n|事件机制|DOM 事件、网络请求事件、初始化事件|\n|状态同步|自动同步 window.state(Python ↔ JS)|\n|平台支持|Desktop 各平台 + Android,含特性差异|\n|应用配置 & 菜单|settings 配置项 + 窗口级菜单|\n|平台增强|暗色模式、JS prompt 优化、屏幕坐标、SSL 优化等|\n\n---\n", + "计算机科普/clash机场三种代理模式科普.md": "\n---\n\n### 1️⃣ `rule`(规则模式)\n\n- **中文理解**:按规则走\n- **工作方式**:\n - 根据配置文件里的 **规则列表(rules)** 来判断请求走哪条线路。\n - 每条规则通常指定域名、IP、地理位置或者关键词对应的代理:\n - 例如 `DOMAIN-SUFFIX,google.com,Proxy` → 访问 google.com 时走代理\n - `DOMAIN-SUFFIX,example.com,DIRECT` → 访问 example.com 时直连\n \n- **优点**:\n - 灵活,可针对不同网站走不同线路。\n - 节省带宽和延迟。\n- **缺点**\n - 规则多时,解析略慢一些。\n---\n\n### 2️⃣ `global`(全局代理模式)\n\n- **中文理解**:所有流量都走代理\n- **工作方式**:\n - 不看规则,所有网络请求都被发送到指定的 **代理服务器**。\n- **优点**:\n - 配置简单,不需要维护规则。\n - 对某些被墙网站或应用更友好。\n- **缺点**:\n - 所有流量都经过代理,可能降低速度。\n - 国内网站也会走代理,浪费带宽。\n---\n\n### 3️⃣ `direct`(全局直连模式)\n\n- **中文理解**:所有流量直连,不走代理\n- **工作方式**:\n - 忽略所有规则,直接访问目标网站。\n- **优点**:\n - 速度快,延迟低。\n - 避免代理服务器的限制。\n- **缺点**:\n - 无法访问被墙网站。\n - 所有请求都走直连,规则无效。\n---\n\n### 🔹 总结对比\n\n|模式|规则依据|适用场景|\n|---|---|---|\n|`rule`|配置文件规则|兼顾国内外访问速度和被墙网站访问|\n|`global`|忽略规则,全局走代理|全局科学上网,简单直接|\n|`direct`|忽略规则,全局直连|国内访问为主,不需代理|\n\n---\n", + "计算机科普/CPU利用率科普.md": "CPU 利用率的本质是 **CPU 核心在单位时间内执行非空闲任务(即处于“忙碌”状态)所占时间的比例**。\n\n理解这个本质需要深入以下几个关键点:\n\n1. **“忙碌”状态的界定:**\n * CPU 的核心任务是从内存中获取指令、解码指令、执行指令、存储结果。\n * **“忙碌”状态:** 当 CPU 核心正在执行操作系统内核代码或用户程序代码(统称为“非空闲任务”)时,它就处于忙碌状态。它正在处理实际的计算、逻辑判断、数据处理等工作。\n * **“空闲”状态:** 当系统中所有可运行的进程/线程都在等待某些事件(如等待用户输入、等待磁盘I/O完成、等待网络数据包、等待定时器到期等)而没有任何任务需要 CPU 立即执行时,操作系统会运行一个特殊的、最低优先级的任务,通常称为 **空闲任务** 或 **空闲循环**。CPU 核心执行这个空闲任务的状态就是空闲状态。此时 CPU 虽然在运行(执行 `HLT` 指令或空循环),但并没有进行任何有意义的计算工作。现代 CPU 在空闲状态通常会降低功耗(进入 C-State)。\n\n2. **时间片与测量原理:**\n * 现代操作系统都是多任务操作系统,通过时间片轮转、优先级调度等算法在多个进程/线程之间快速切换 CPU 核心的执行权。\n * **测量单位:时间片。** 操作系统内核会周期性地(例如每毫秒或每几毫秒,由系统时钟中断驱动)检查每个 CPU 核心当前正在执行什么任务。\n * **统计方法:** 在每个采样时刻点(时钟中断发生时):\n * 如果发现 CPU 核心正在执行 **非空闲任务**(用户进程、内核线程、系统调用处理等),就记录该核心在“忙碌”。\n * 如果发现 CPU 核心正在执行 **空闲任务**,就记录该核心在“空闲”。\n * **计算利用率:** 在一个特定的时间窗口内(比如1秒),CPU 利用率就是这个窗口内所有采样点中被标记为“忙碌”的次数占总采样点次数的百分比。例如:\n * 采样间隔为 10ms (每秒采样100次)。\n * 在1秒内,某个 CPU 核心有 80 次被采样时处于“忙碌”状态。\n * 那么这1秒内该核心的 CPU 利用率就是 80%。\n\n3. **核心概念:时间比例**\n * 这 80% 的利用率意味着:在这1秒钟的时间里,该 CPU 核心有 800 毫秒(0.8秒)的时间在执行实际的工作(非空闲任务),只有 200 毫秒(0.2秒)的时间在执行无实际计算工作的空闲任务(或者处于低功耗休眠状态)。\n * **因此,CPU 利用率的核心本质就是 CPU 核心执行有效工作所占用的时间占总时间的百分比。**\n\n4. **关键特性与常见误解:**\n * **反映的是时间占用率,而非绝对处理能力:** 100% 利用率意味着 CPU 核心在整个时间段内都在忙碌,没有空闲时间。但这**并不一定**意味着它达到了最大理论计算能力(例如,它可能在等待较慢的内存访问)。\n * **“忙”的原因多样:** 高利用率可能由计算密集型任务(大量数学运算)、大量系统调用(内核态忙碌)、频繁的中断处理、甚至自旋锁等待(CPU 忙等锁)等引起。工具如 `top`, `perf`, `vmstat` 等可以帮助区分具体原因(用户态 `us`、系统态 `sy`、等待I/O `wa`、软中断 `si`、硬中断 `hi`、窃取 `st`、空闲 `id`)。\n * **多核CPU:** 对于拥有多个核心或线程的 CPU,利用率通常可以报告:\n * **每个核心的利用率:** 最精确。\n * **所有核心的平均利用率:** 例如一个4核CPU平均利用率75%,可能意味着3个核心100%忙碌,1个核心空闲;也可能意味着4个核心都75%忙碌。\n * **总体利用率:** 所有核心忙碌时间的总和除以(核心数 * 总时间)。例如,4核CPU在1秒内,所有核心忙碌时间总和为3秒,则总体利用率为 3 / (4 * 1) = 75%。\n * **I/O 等待 (`wa`) 的特殊性:** 当进程因为等待磁盘I/O而阻塞时,CPU 核心会切换到其他可运行任务或进入空闲状态。这段时间通常被单独统计为 `wa`(I/O 等待)。严格来说,`wa` 高的时间段里 CPU 核心可能处于忙碌(执行其他任务)或空闲(没有其他任务)状态,但它反映了 CPU 因等待I/O而未能有效利用的潜在时间。`wa` 本身不计入 `us+sy` 的利用率计算,但高 `wa` 通常意味着系统瓶颈在I/O而非CPU计算能力。\n * **虚拟化环境:** 在虚拟机中,虚拟机监控器(Hypervisor)看到的宿主机的 CPU 利用率反映的是物理 CPU 的忙碌程度。虚拟机内部看到的 CPU 利用率反映的是分配给它的虚拟 CPU 时间的忙碌程度。如果宿主机物理 CPU 饱和,即使虚拟机内部显示利用率不高,其性能也可能受影响(`st` 窃取时间高)。\n\n**总结:**\n\nCPU 利用率的本质是一个 **时间占比的度量**。它精确地衡量了 **CPU 核心实际执行非空闲任务(执行用户代码或内核代码)的时间占总观测时间的百分比**。理解这个百分比背后代表的是 CPU 核心忙碌工作的时间片段,是掌握 CPU 性能分析和系统瓶颈诊断的基础。100% 利用率意味着 CPU 核心全程无休,但这不一定是性能极限,也可能是效率瓶颈的信号;而低利用率通常意味着 CPU 有充足的闲置计算能力。", + "计算机科普/IDEA专业版和社区版的区别和特点.md": "- **许可证与价格** \n 社区版:基于开源代码,完全免费,支持自由使用与修改。 \n 专业版:需购买许可证,属于付费版本。\n \n- **语言支持** \n 社区版:聚焦 JVM 语言,如 Java、Kotlin、Groovy、Scala。 \n 专业版:覆盖多语言生态,除 JVM 语言外,还支持 PHP、JavaScript、TypeScript、Python、Ruby、Go、SQL 等,适配多语言与全栈开发。\n \n- **框架支持** \n 社区版:仅支持 JavaFX、Swing 等基础 Java 框架。 \n 专业版:涵盖广泛场景,Web 开发(Spring、JSF、Struts 等)、移动开发(Android)、企业开发(J2EE、Spring Boot、Micronaut、Quarkus 等)。\n \n- **数据库工具** \n 社区版:无内置工具,需借助 DBeaver、DataGrip 等外部工具操作数据库。 \n 专业版:内置数据库管理功能,支持直接查看、运行 SQL 脚本、导出数据等。\n \n- **DevOps 和云支持** \n 社区版:对现代 DevOps(Docker、Kubernetes)及云平台(AWS、Google Cloud)支持有限。 \n 专业版:集成 DevOps 工具链,深度兼容主流云平台。\n \n- **版本控制系统(VCS)** \n 社区版:支持 Git、Mercurial、SVN 等基础版本控制。 \n 专业版:强化 VCS 能力,新增 Perforce 支持,提供更便捷的版本历史查看、差异对比、回滚功能。\n \n- **构建工具** \n 社区版:支持 Maven、Gradle、Ant 等常见构建工具。 \n 专业版:拓展至 sbt、npm、yarn 等更多工具,适配多元开发场景。\n \n- **插件** \n 社区版:需手动按需安装插件。 \n 专业版:预装丰富实用插件,开箱即用 。", + "计算机科普/sim卡作用及原理.md": "# 什么是 SIM 卡\n\n**SIM** 是 _Subscriber Identity Module_ 的缩写(中文常译为“用户身份模块”)。严格来说,现代移动设备里常见的有两类相关的东西:**物理 SIM / 晶片卡(UICC)** 和 **嵌入式 SIM(eSIM / eUICC)**。无论形式如何,其核心作用是:**为移动用户提供唯一身份、储存认证凭证与少量用户数据,并参与网络认证与安全通信**。\n\n---\n\n## 组成与物理/逻辑规范\n\n- **物理外形**:有标准的触点金属面(按 ISO/IEC 7816),常见尺寸为全尺寸/mini/micro/nano,近年还有不可拆卸的 **eSIM(嵌入式)**。\n- **逻辑规范**:\n - **UICC**(Universal Integrated Circuit Card):现代 SIM 的正式名称,能运行多种应用(USIM、ISIM 等)。\n - **USIM**:用于 3G/4G/5G 的用户应用;比早期 GSM 的 SIM 功能更强。\n - **Java Card**:很多 SIM 使用 Java Card 平台来运行小型应用(applet)。\n- **文件系统**:SIM 内部有一套层次化文件系统(MF → DF → EF),用于存放 IMSI、Ki、网络参数、联系人、短信等。\n\n---\n\n## 关键数据与标识\n\n- **IMSI(International Mobile Subscriber Identity)**:国际移动用户识别码,用于在运营商网络中唯一标识用户。通常由 MCC(国家码)+ MNC(网络码)+ MSIN(用户号)构成。\n- **Ki(密钥)**:设备和运营商共享的长期对称密钥(通常只存储在 SIM 与运营商的认证中心,不外泄),用于生成认证和加密用的临时密钥。\n- **ICCID(Integrated Circuit Card ID)**:SIM 卡的唯一序列号(印在卡上,用于标识卡片本身)。\n- **PIN/PUK**:用户可设置的 PIN(解锁码),PUK 用于在 PIN 输错多次后解锁。\n\n---\n\n## 工作原理(以移动网络认证为核心)\n\n1. **发起连接**:设备开机并向基站/网络发出接入请求,同时提供 IMSI(或临时标识)。\n2. **挑战—应答(Challenge-Response)机制**:\n - 网络(认证中心)生成一个随机数 **RAND**,并把它发送给设备(通过基站)。\n - SIM 使用内部的 **Ki** 与 RAND 以及特定算法(GSM 时代有 COMP128,后续有 A3/A8、Milenage 等)计算出应答值 **RES**(或 SRES),并生成会话密钥(如 Kc、CK/IK)。\n - 网络端也用相同的 Ki 与 RAND 计算预期应答并比对:若匹配,认证通过。\n3. **密钥派生**:认证成功后产生的会话密钥用于语音/数据的加密(无线链路加密),并用于随后与核心网的安全交互。\n4. **更高级的 AKA(Authentication and Key Agreement)**:在 3G/4G/5G 中使用更强的 AKA 流程,包含防重放、防伪造的校验(如 AUTN)并生成更复杂的加密/完整性密钥(CK/IK、KASME 等)。\n\n---\n\n## 功能与扩展能力\n\n- **身份与计费**:运营商依据 IMSI 识别用户并计费。\n- **安全存储**:存储 Ki、网络参数、APN、联系人、短信(旧式)等。\n- **SIM Toolkit(STK)**:运营商/服务可下发应用命令(如菜单、主动发起短信/拨号、USSD 等),常见于运营商增值服务。\n- **远程管理(OTA)**:运营商可通过 OTA(Over-The-Air)向 SIM 下发配置、更新应用或改变 PIN 策略。\n- **多应用/多配置(eUICC)**:eSIM 支持在同一芯片上存放多个运营商配置文件,实现远程下载/切换(GSMA 的远程配置规范)。\n\n---\n\n## 安全性设计\n\n- **物理与逻辑硬化**:SIM 作为安全元件(secure element),具备防篡改与抗攻击设计;关键材料(如 Ki)不能被设备直接读取。\n- **用户认证**:存在用户 PIN,及网络端的挑战-应答认证。\n- **现代算法与协议**:从早期的 COMP128 演进到 Milenage、AKA、5G 新的改进,增强抗撞库与抗中间人能力。\n- **弱点**:历史上某些算法/实现被攻破或泄露(如早期 COMP128),但运营商逐步升级算法与使用更安全的 eSIM/AKA 方案。\n\n---\n\n## 实际应用场景与趋势\n\n- **传统手机**:物理 SIM 卡仍然广泛使用,支持换卡保号(携号转网)。\n- **双/多 SIM 设备**:允许同时插入两张 SIM 或混合物理 + eSIM 的组合,适合分工(工作/私人、数据/语音)。\n- **物联网(IoT)与 M2M**:大量设备使用 M2M SIM 或 eSIM/embedded 模块,便于远程部署与管理。\n- **eSIM 的流行**:便于运营商配置文件的远程下发,减少物理卡流通,也利于设备密封设计(如手表、物联网传感器)。\n\n---\n\n## 简短示例:GSM 认证流程(逐步)\n\n1. 设备向网络报告 IMSI(或临时标识)。\n2. 网络生成 RAND,并把 RAND 与预期应答(由运营商的认证中心计算)发送给移动交换中心(MSC)。\n3. MSC 将 RAND 发给设备;设备的 SIM 用 RAND + Ki 计算 RES 并返回。\n4. MSC 比较 RES 与期望值;若匹配则允许接入,并使用派生密钥加密后续无线通信。\n\n---\n\n## 小结(一句话)\n\nSIM(或更一般的 UICC / eUICC)是一个小型但受保护的智能卡 / 安全芯片,**存储用户身份与加密凭证,通过挑战—应答和密钥派生机制对用户进行网络认证并保护移动通信的安全**,同时支持少量用户数据与运营商增值服务(如 SIM Toolkit、OTA、eSIM 配置等)。\n", + "计算机科普/wan口和lan口的区别与特点.md": "\n\n**一句话总结:**\n\n* **WAN口:** 连接**外部**网络(通常是互联网)。\n* **LAN口:** 连接**内部**网络设备。\n\n---\n\n## WAN口 (广域网端口)\n\n1. **功能:**\n * 主要负责**接入互联网**或**连接更大的外部网络**(如公司总部的网络)。\n * 它是路由器与**互联网服务提供商**网络之间的桥梁。\n * 接收来自ISP(如电信、联通、移动)的信号(通过光猫、调制解调器等设备)。\n2. **特点:**\n * **数量少:** 家用路由器通常只有**1个**WAN口。企业级路由器可能有多个用于负载均衡或备份链路。\n * **“对外”角色:** 面向外部世界,是内部网络访问互联网的唯一(或主要)出口。\n * **IP地址:** 通常获取的是**公网IP地址**(由ISP动态分配或静态配置),或者是运营商网络内部的私有IP地址(在光猫拨号的情况下)。这个地址在互联网上是可路由的(或者至少能被ISP网络识别)。\n * **数据传输方向:** 处理所有**进出互联网**的数据流。\n * **物理位置:** 在路由器背面,通常与LAN口分开,并用**不同颜色**(常见黄色、蓝色或灰色)或明确标注`WAN`/`Internet`字样标识。\n * **连接对象:** 连接到**光猫、调制解调器**或上级网络设备(如另一个路由器的LAN口,此时该路由器工作在接入模式而非路由模式)。\n * **安全边界:** 位于内部网络和外部不可信网络之间,是防火墙防护的重点区域。\n\n---\n\n## LAN口 (局域网端口)\n\n1. **功能:**\n * 负责连接**内部网络**中的各种设备。\n * 为这些设备提供**本地网络连接**,使它们能够相互通信(如电脑传文件给打印机、手机投屏到电视)并**共享同一个互联网出口(WAN口)**。\n2. **特点:**\n * **数量多:** 家用路由器通常有**2-8个**LAN口。交换机则提供更多的LAN口用于扩展。\n * **“对内”角色:** 面向内部网络设备,构建本地局域网。\n * **IP地址:** 路由器上的LAN口本身有一个**私有IP地址**(通常是`192.168.x.x`, `10.x.x.x`, `172.16.x.x - 172.31.x.x`范围,如常见的`192.168.1.1`或`192.168.0.1`)。它作为内部网络的**网关**。\n * **IP分配:** 路由器通过**DHCP服务器**功能(通常默认开启),**自动**为连接到LAN口的设备分配私有IP地址(在同一个子网内)。\n * **数据传输方向:** 处理**局域网内部设备之间**以及**设备到路由器/互联网**的数据流。\n * **物理位置:** 在路由器背面,通常集中在一起,用**相同颜色**(常见黄色)标注`LAN`或`1, 2, 3, 4...`。\n * **连接对象:** 连接**电脑、打印机、网络存储、游戏机、智能电视、其他交换机**等**本地设备**。\n * **网络范围:** 构成一个**广播域**,设备在同一个子网内,可以直接通信(二层交换)。\n\n---\n\n## 关键对比表\n\n| 特性 | WAN口 (广域网端口) | LAN口 (局域网端口) |\n| :----------- | :------------------------------------- | :---------------------------------------------- |\n| **功能** | 连接外部网络 (互联网/上级网络) | 连接内部网络设备 |\n| **角色** | “对外” | “对内” |\n| **数量** | 通常1个 (家用) | 通常多个 (2-8个,家用) |\n| **IP地址** | 公网IP (或运营商私有IP) | 私有IP (作为网关,如 `192.168.1.1`) |\n| **IP分配** | 由ISP分配 (动态/静态) | 由路由器的DHCP服务器分配给内部设备 (私有IP) |\n| **数据传输** | 进出互联网的数据 | 局域网内部设备间通信 + 设备到路由器/互联网的数据 |\n| **连接对象** | 光猫、调制解调器、上级路由器/网络 | 电脑、打印机、NAS、游戏机、电视、AP、交换机等 |\n| **物理标识** | 常不同颜色 (黄/蓝/灰),标 `WAN/Internet` | 常统一颜色 (黄),标 `LAN` 或 `1, 2, 3, 4...` |\n| **安全位置** | 内部网络与外部网络边界 (防火墙防护点) | 内部可信网络区域 |\n\n---\n\n## 总结与常见场景\n\n* **正确连接是上网的基础:** 宽带入户线(来自光猫/调制解调器)**必须**插在路由器的**WAN口**上。你的电脑、电视等设备则插在**LAN口**上。\n* **混淆后果:** 如果把宽带线错插到LAN口,路由器就无法从ISP获取有效的网络配置,导致整个内部网络无法访问互联网。\n* **扩展网络:** 如果你需要连接超过路由器LAN口数量的设备,可以将一个**交换机**连接到路由器的任一LAN口上,交换机提供的更多端口也属于LAN端口。\n* **无线连接:** 路由器的Wi-Fi功能本质上是创建了一个“无线LAN口”,手机、笔记本等无线设备通过Wi-Fi连接后,其角色和功能等同于插在物理LAN口上的设备。\n\n简单来说,记住:**WAN口是进水管(从外面引水进来),LAN口是分水管和水龙头(把水分配到各个需要的地方)**", + "计算机科普/WiFi和蓝牙的异同.md": "蓝牙和Wi-Fi 都是利用无线电波进行短距离无线通信的技术,并且都工作在2.4 GHz频段(部分Wi-Fi也工作在5 GHz或6 GHz),但它们的设计目标、技术实现、应用场景和性能特点有着**根本的区别**。\n\n主要区别:\n\n1. **设计目的和应用场景:**\n * **蓝牙:** 主要设计用于**短距离、低功耗、点对点或点对多点**的设备间连接。目的是**取代线缆**,方便各种小型设备之间进行简单数据交换或控制。\n * **典型应用:** 连接无线耳机/音箱、鼠标/键盘、智能手表、健康追踪器、打印机、车载系统、智能家居设备(如灯泡、传感器)之间的简单通信等。\n * **Wi-Fi:** 主要设计用于**构建无线局域网**,提供**高速互联网接入**和**本地网络资源(如文件、打印机)共享**。目的是实现**高带宽的网络接入**。\n * **典型应用:** 将笔记本电脑、手机、平板、智能电视、游戏机等设备连接到互联网或家庭/办公室局域网;实现设备间的高速文件传输、媒体流传输。\n\n2. **覆盖范围:**\n * **蓝牙:** 典型覆盖范围较小,一般在 **10米** 左右(Class 1设备可达100米,但较少见)。注重近距离连接。\n * **Wi-Fi:** 覆盖范围较大,典型的家用路由器覆盖范围可达 **几十米**(受墙壁、干扰等影响),甚至可以通过中继器扩展。\n\n3. **数据传输速率:**\n * **蓝牙:** 速率**相对较低**,且不同版本差异大。\n * 经典蓝牙:早期版本约1-3 Mbps,较新的蓝牙5.x版本理论可达2-3 Mbps(实际应用如音频传输用不到这么高)。\n * 低功耗蓝牙:专为极低功耗设计,数据传输速率更低(几十到几百Kbps),但连接建立速度快。\n * **Wi-Fi:** 速率**非常高**,且随着标准演进不断提升。\n * 802.11n:数百Mbps\n * 802.11ac:Gbps级别\n * 802.11ax:多Gbps级别\n * 主要用于传输大量数据(如高清视频、大文件下载)。\n\n4. **功耗:**\n * **蓝牙:** 尤其**低功耗蓝牙**设计初衷就是**极低功耗**,非常适合电池供电的小型设备(如传感器、耳机、手表),可以持续工作数月甚至数年。\n * **Wi-Fi:** 功耗**相对较高**。虽然也有针对物联网设备的低功耗Wi-Fi标准,但总体上维持Wi-Fi连接和传输数据消耗的电量远高于蓝牙(尤其是BLE)。频繁使用Wi-Fi会显著消耗手机等设备的电池。\n\n5. **网络拓扑结构:**\n * **蓝牙:** 支持多种拓扑:\n * **点对点:** 两个设备直接连接(如手机连耳机)。\n * **广播:** 一个设备发送,多个设备接收(如Beacon)。\n * **Mesh网络:** 多个设备组成网状网络,扩展覆盖范围和可靠性(主要用于智能家居、楼宇自动化)。\n * **Wi-Fi:** 主要采用**星型拓扑**。\n * 所有设备(客户端)都连接到一个中心节点(无线路由器或接入点)。\n * 客户端之间通常需要通过接入点才能通信(除非支持Wi-Fi Direct点对点直连)。\n\n6. **复杂性和成本:**\n * **蓝牙:** 协议栈相对**简单**,硬件实现**成本较低**,易于集成到小型、低成本的设备中。\n * **Wi-Fi:** 协议栈**复杂**,硬件实现**成本相对较高**,需要更强的处理能力和内存。\n\n7. **频段和干扰:**\n * 两者都工作在2.4 GHz ISM频段,因此**存在相互干扰的可能**。现代设备通常有机制(如自适应跳频)来减轻干扰,但在拥挤的无线环境中(如公寓楼、办公室),干扰仍可能影响性能(尤其是蓝牙音频的稳定性)。\n\n**总结:**\n\n| 特性 | 蓝牙 | Wi-Fi |\n| :--------- | :------------------- | :--------------------- |\n| **核心目标** | **短距设备连接**(取代线缆) | **无线局域网接入**(高速上网/资源共享) |\n| **典型应用** | 耳机、鼠标、传感器、手环、IoT小设备 | 笔记本上网、手机上网、流媒体、文件共享 |\n| **覆盖范围** | 短(~10米) | 中长(几十米) |\n| **数据速率** | **低**(Kbps - 低 Mbps) | **高**(百Mbps - 多 Gbps) |\n| **功耗** | **非常低**(尤其是BLE) | **相对较高** |\n| **拓扑结构** | 点对点、广播、Mesh | 星型(中心是AP/路由器) |\n| **复杂性/成本** | 低 | 高 |\n| **频段** | 2.4 GHz(主要) | 2.4 GHz, 5 GHz, 6 GHz |\n", + "计算机科普/x64,x86和amd64区别.md": "x64、x86、amd64 都是与计算机处理器架构相关的术语,它们的区别主要体现在架构类型、位数、兼容性等方面,具体如下:\n\n### 1. x86:32 位处理器架构的统称\n\n- **核心定义**:x86 是英特尔早期推出的 32 位处理器架构(如 8086、80386 等)的统称,后来扩展到 32 位计算领域,是目前最广泛使用的 32 位架构标准。\n\n- **特点**:支持的最大内存地址空间为 4GB(受 32 位地址总线限制),广泛应用于早期个人电脑和服务器。\n\n- **兼容性**:所有 32 位 x86 处理器都遵循这一架构,软件兼容性极强。\n\n### 2. x64 与 amd64:64 位处理器架构的不同称呼\n\n- **核心关系**:两者本质上是同一架构 ——amd64 是 AMD 公司最早提出的 64 位扩展架构(在 x86 基础上扩展为 64 位),英特尔后来采纳了这一架构并称之为 x64,因此两者没有技术差异,只是不同厂商的命名方式。\n\n- **特点**:\n\n- 支持 64 位地址总线,理论上可支持最大 16EB(1EB=1024PB)内存,远超 32 位架构的 4GB 限制。\n\n- 向下兼容 32 位 x86 软件,兼顾旧有应用。\n\n- **应用**:目前主流的处理器(如英特尔的酷睿系列、AMD 的锐龙系列)均基于这一 64 位架构,是现代计算机的标准架构。\n\n### 总结:核心区别\n\n| | | | |\n|---|---|---|---|\n|术语|位数|架构来源|本质差异|\n|x86|32 位|英特尔早期 32 位架构标准|32 位计算基础|\n|amd64|64 位|AMD 提出的 64 位扩展架构|同属 64 位架构,仅命名不同|\n|x64|64 位|英特尔对 amd64 架构的称呼|同属 64 位架构,仅命名不同|\n\n简单来说:x86 是 32 位架构,x64/amd64 是 64 位架构(两者等价,名称不同)。", + "计算机科普/光纤和网线的特点和区别.md": "\n## 一、 核心区别:传输原理\n\n1. **光纤 (Fiber Optic Cable):**\n * **原理:** 利用光脉冲在极细的玻璃或塑料纤维中进行传输。\n * **信号:** 光信号(激光或LED)。\n * **介质:** 玻璃纤维芯(核心)和包层(折射率不同,实现全反射)。\n\n2. **网线 (双绞线 - Twisted Pair Cable):**\n * **原理:** 利用电信号在相互缠绕的铜线中进行传输。\n * **信号:** 电信号。\n * **介质:** 铜导体(通常为4对双绞线)。\n\n## 二、 关键特点对比\n\n| 特性 | 光纤 (Fiber Optic) | 网线/双绞线 (Twisted Pair) |\n| :--------------- | :----------------------------------------------------- | :----------------------------------------------------- |\n| **传输原理** | **光信号** | **电信号** |\n| **传输介质** | 玻璃纤维芯 + 包层 | 铜线 |\n| **带宽/速度** | **极高**。理论上可达Tbps级别,远超双绞线。常用10Gbps, 40Gbps, 100Gbps甚至更高。 | **相对较低**。受限于铜线物理特性(趋肤效应、串扰)。常用1Gbps, 10Gbps(短距离)。 |\n| **传输距离** | **非常远**。单模光纤可达几十甚至上百公里(无需中继)。多模光纤可达几百米到几公里。 | **较短**。Cat5e/Cat6:100米(千兆)。Cat6a/Cat7:100米(万兆)。距离越长,信号衰减和失真越严重。 |\n| **抗干扰能力** | **极强**。光信号不受电磁干扰、无线电频率干扰影响。可在强电磁环境(如工厂、医院)或雷暴天气下稳定工作。 | **较弱**。铜线是导体,易受电磁干扰、串扰影响。需要屏蔽层(STP/FTP)在干扰环境下改善性能,但成本增加。 |\n| **安全性** | **高**。光信号不易被窃听(需要物理接入并截断光纤,且操作易被发现)。不辐射电磁信号。 | **较低**。电信号可能被电磁感应方式窃听(有一定难度)。铜线会辐射微弱电磁信号。 |\n| **尺寸与重量** | **更细、更轻**。相同容量下,光纤比铜缆细得多、轻得多。 | **较粗、较重**。尤其是高类别带屏蔽的线缆。 |\n| **成本** | **设备成本高**。光模块、光纤收发器、光纤交换机端口价格远高于铜口设备。
**线缆成本中等**。 | **设备成本低**。网卡、交换机端口非常普及且便宜。
**线缆成本中等偏低**(低类别线)。但高类别屏蔽线成本也较高。 |\n| **安装与维护** | **技术要求高**。光纤端接(熔接、研磨)需要专业工具和技能。弯曲半径要求严格,过度弯折易断芯。 | **相对简单**。RJ45水晶头压接容易学习,工具普及。允许更大的弯曲半径,更耐弯折。 |\n| **连接器** | LC, SC, ST, FC, MTP/MPO 等 | RJ45 (8P8C) |\n| **功耗** | **较低**。光模块通常功耗低于同等速率电口。 | **较高**。尤其在高速率、长距离传输时,驱动电信号需要更大功率。 |\n| **主要类型** | **单模光纤:** 细芯(~9µm),单束光,超长距离,高速。
**多模光纤:** 粗芯(50µm/62.5µm),多束光,中短距离,性价比高。 | **非屏蔽双绞线:** UTP(最常见),无屏蔽层,成本低。
**屏蔽双绞线:** STP/FTP/SFTP 等,带屏蔽层,抗干扰好,成本高。
**类别:** Cat5e (千兆), Cat6 (千兆/短距万兆), Cat6a (万兆), Cat7/7a/8 (更高性能) |\n| **典型应用场景** | 骨干网、城域网、数据中心互联、长距离传输、高干扰环境、高带宽需求(视频、云计算、存储网络)、FTTH/FTTx入户。 | 局域网接入层(电脑到交换机)、电话系统、监控系统(POE供电)、家庭网络、办公室布线、短距离设备互联。 |\n\n## 三、 总结\n\n* **选择光纤当:**\n * 你需要**极高的带宽**(10Gbps以上)。\n * 你需要**超长的传输距离**(几百米到几十公里)。\n * 你在**强电磁干扰**环境中。\n * 你对**安全性**要求非常高。\n * 你需要**节省空间和减轻重量**(如数据中心)。\n * 你需要**更低的传输延迟**(虽然差异很小,但对超低延迟场景重要)。\n * 你**不差钱**(尤其是一次性投入的设备成本)。\n\n* **选择双绞线当:**\n * 你的需求是**千兆或万兆(短距离)**。\n * 传输距离在**100米以内**。\n * 环境**电磁干扰较小**。\n * 你对**成本非常敏感**(尤其是设备端口成本)。\n * 你需要**简单易行的安装和维护**。\n * 你需要为设备提供**PoE供电**(目前光纤无法直接供电)。\n * 应用场景是**终端设备接入**(电脑、IP电话、摄像头、AP等)。\n\n**简单来说:光纤是“高速公路”,速度快、距离远、容量大、成本高、建设维护复杂;双绞线是“城市道路”,灵活方便、覆盖广、成本低、但速度和距离有限。** 现代网络通常是两者的结合:光纤做骨干和长距离互联,双绞线做最后100米的接入。", + "计算机科普/多模态大模型识别图片,视频,音频原理.md": "\n## 核心思想\n\n- **目标**:把非文本模态(图片、视频、音频等二进制数据)转换成模型能理解的“通用语言”(数值向量/特征向量)。\n \n- **统一空间**:在统一的语义向量空间中实现多模态信息的对齐、理解和生成。\n \n\n---\n\n## 核心步骤\n\n1. **预处理与编码(Encoding)**\n \n - 使用专门的编码器(图像、视频、音频编码器),将原始数据转为特征向量。\n \n2. **对齐与融合(Alignment & Fusion)**\n \n - 通过投影层将不同模态特征映射到同一向量空间,并进行融合。\n \n3. **理解与推理(Understanding & Reasoning)**\n \n - LLM基于融合特征进行语义理解与逻辑推理。\n \n4. **解码与生成(Decoding & Generation)**\n \n - 将LLM的内部表示解码为文本输出,完成对话或任务。\n \n\n---\n\n## 工作流程示意图\n\n```mermaid\nflowchart TD\nA[输入
非文本模态] --> B[专用编码器
(如ViT, CLIP-ViT)]\nB --> C[特征向量
“通用语言”]\nC --> D[与LLM交互
(前缀/软提示)]\n\nE[输入
文本指令] --> F[文本编码器
(如CLIP-Text, BPE)]\nF --> G[文本向量]\n\nD & G --> H[大语言模型核心
(Transformer)]\nH --> I[理解与推理]\nI --> J[文本解码器]\nJ --> K[输出
文本响应]\n```\n\n---\n\n## 模态细分说明\n\n### 1. 图像(Image)\n\n- **编码器**:CNN(ResNet,早期)或 ViT(主流)。\n \n- **流程**:\n \n 1. 图像分块 → ViT编码 → 图像特征向量。\n \n 2. 投影层对齐到文本空间。\n \n 3. 特征作为“视觉提示”与文本一起输入LLM。\n \n 4. LLM生成描述或问答结果。\n \n\n---\n\n### 2. 视频(Video)\n\n- **特点**:图像序列 + 时间维度 + 可选音频。\n \n- **编码器**:\n \n - 图像帧 → ViT。\n \n - 时序关系 → 3D-CNN / 时序Transformer。\n \n - 音频 → 独立音频编码器。\n \n- **流程**:\n \n 1. 视频帧采样。\n \n 2. 逐帧编码 + 时序建模。\n \n 3. 融合视觉+音频特征,对齐到文本空间。\n \n 4. LLM理解动作与剧情,输出结果。\n \n\n---\n\n### 3. 音频/音乐(Audio)\n\n- **语音识别路径**:\n \n - 使用ASR模型(如Whisper)转录为文本 → 输入LLM。\n \n- **非语音音频路径**:\n \n - 音频波形 → 频谱图(Spectrogram)。\n \n - 频谱图 → ViT 等视觉编码器 → 特征向量。\n \n - 投影对齐后,与文本一同输入LLM。\n \n\n---\n\n## 关键技术\n\n1. **CLIP模型**:\n \n - 对比学习,建立图像-文本统一语义空间。\n \n2. **投影层(Projection Layer)**:\n \n - 将模态特征翻译到LLM空间。\n \n3. **软提示(Soft Prompt)**:\n \n - 非文本特征向量作为额外提示,辅助LLM理解与生成。\n \n\n---\n\n## 类比理解\n\n- **编码器**:不同模态的“翻译官”。\n \n- **投影层**:统一标准的“校对官”。\n \n- **LLM**:只懂“世界语”的“博学大脑”。\n \n- **解码器**:把“世界语”翻译回自然语言。\n \n\n---\n", + "计算机科普/术语科普-CVM.md": "CVM 通常指 云服务器(Cloud Virtual Machine),是云计算服务中的一种基础计算资源。它通过虚拟化技术,将物理服务器分割成多个独立的虚拟服务器,用户可像使用本地服务器一样远程管理和使用,无需自行购买和维护硬件设备。\n \n其核心特点包括:\n \n- 弹性伸缩:可根据业务需求灵活调整 CPU、内存、存储等配置。\n- 按需付费:按使用时长或资源配置计费,降低初期投入成本。\n- 高可用性:依托云服务商的基础设施,通常具备多副本存储、故障自动迁移等能力。\n- 易管理性:通过云平台控制台可便捷进行开关机、重装系统、配置网络等操作。\n \n在实际应用中,CVM 广泛用于搭建网站、部署应用程序、运行数据库、进行大数据分析等场景。不同云服务商(如腾讯云、阿里云等)对其的具体命名可能略有差异,但核心功能一致。", + "计算机科普/术语科普-IT行业的A端B端C端.md": " IT 行业中,**A 端、B 端、C 端**,是按照业务服务对象的不同来划分\n\n---\n\n## 1. C 端(Customer/Consumer)\n\n- **对象**:普通个人用户,即消费者。\n- **特点**:\n - 用户量大,但单个用户的付费能力相对有限。\n - 对产品的体验、易用性、趣味性和性价比要求较高。\n - 市场竞争激烈,获客成本高,用户流失率也较高。\n- **典型产品**:\n - 微信、抖音、美团、淘宝等面向大众的互联网应用。\n - 常见的互联网 App 和电商平台,主要服务于个人消费者。\n\n---\n\n## 2. B 端(Business)\n\n- **对象**:企业或组织客户。\n- **特点**:\n - 用户数量相对少,但单个客户的价值很高。\n - 注重功能的完整性、效率、稳定性、安全性和售后支持。\n - 产品通常要和企业的业务流程深度结合,销售模式更偏向“解决方案”。\n- **典型产品**:\n - 企业管理系统(ERP、CRM、OA)、云计算服务(阿里云、腾讯云)、SaaS 工具(钉钉、飞书)。\n - 企业采购、供应链、财务软件等。\n\n---\n\n## 3. A 端(Administration/Government)\n\n- **对象**:政府机构或事业单位。\n- **特点**:\n - 强调合规性、稳定性和数据安全。\n - 客户对服务的专业性、长期支持能力和安全保密性要求极高。\n - 项目型特征明显,常涉及“政务信息化”“智慧城市”等建设。\n- **典型产品**:\n - 政务大数据平台、智慧城市解决方案、公安/税务/教育信息化系统。\n - 例如国家的社保系统、政府政务服务平台。\n\n---\n\n## 4. 三者的区别总结\n\n- **C 端**:面对大众 → 重视用户体验和规模效应。\n- **B 端**:面对企业 → 重视效率、功能深度、可持续合作。\n- **A 端**:面对政府 → 重视合规、安全、稳定、长期合作。\n\n可以简单理解为:\n\n- **C 端是“零售”**,靠规模和用户体验取胜。\n- **B 端是“批发”**,客户少但客单价高,需要深度定制。\n- **A 端是“定制工程”**,政策导向明显,更看重安全和合规。\n\n---\n", + "计算机科普/术语科普-MCU.md": "微控制单元(Microcontroller Unit):这是电子工程领域的专业术语,又称“单片机”。它是一种将中央处理器(CPU)、存储器、输入/输出接口等功能集成在一块芯片上的微型计算机,广泛应用于智能家居、汽车电子、工业控制等领域。", + "计算机科普/术语科普-pwn.md": "“pwn” 是网络安全领域的常用术语,核心指 通过利用程序漏洞(如缓冲区溢出、内存泄漏等)获取目标系统的控制权,比如执行任意代码、提升权限甚至完全掌控设备。\n \n它起源于“own”(意为“拥有、控制”)的拼写变体,早期在黑客社区和安全竞赛(如CTF)中流行。常见场景包括:\n \n- 对存在漏洞的软件、服务器进行攻击;\n- CTF竞赛中的“pwn题”,要求参赛者找出并利用程序漏洞解决问题。\n \n简单说,pwn的本质就是“找到漏洞并借此控制目标”。", + "计算机科普/科普-Nagle 算法.md": "> [!NOTE]\n> ***Nagle算法是TCP协议中用于优化网络传输效率的一种流量控制算法,其核心目的是减少网络中“小数据包”的数量,从而降低网络拥塞和协议开销。***\n\n\n### **核心问题:小数据包的弊端**\n在TCP通信中,如果应用程序频繁发送少量数据(比如每次只发几个字节),会导致网络中充斥着大量“小数据包”。每个TCP数据包都包含固定的头部信息(至少20字节),小数据包的“有效数据占比”极低,会浪费网络带宽,同时增加路由器等设备的处理压力,容易引发网络拥塞。\n\n\n### **算法原理:合并小数据包**\nNagle算法通过“延迟发送”和“合并数据”的方式减少小数据包,具体规则如下:\n1. 当发送方有数据要发送时,先检查当前是否有“未被确认的数据包”(即已发送但未收到接收方ACK的数据包)。\n2. 如果存在未确认的数据包,则暂时缓存当前要发送的小数据,等待以下两种情况之一发生时再统一发送:\n - 收到对之前数据包的ACK确认;\n - 缓存的数据量达到一定大小(通常是MSS,最大报文段长度)。\n3. 如果没有未确认的数据包,则立即发送当前数据(避免过度延迟)。\n\n\n### **提出背景**\n该算法由John Nagle于1984年提出,最初是为了解决早期ARPANET中“远程登录(Telnet)”场景的问题:用户每敲击一次键盘,应用程序就会发送一个包含单个字符的小数据包,导致网络效率极低。Nagle算法通过合并多次按键的字符,显著优化了这类场景的传输效率。\n\n\n### **适用场景与局限性**\n- **适用场景**:适用于对实时性要求不高,但需要减少网络开销的场景(如文件传输、普通数据交互)。\n- **局限性**:在对实时性要求高的场景(如在线游戏、实时视频/语音、远程控制),Nagle算法可能导致延迟(因为需要等待ACK或数据积累)。例如,游戏中按键操作的小数据可能被延迟发送,影响响应速度。\n\n\n### **与其他机制的关联**\nNagle算法可能与TCP的“延迟确认(Delayed ACK)”机制产生叠加延迟: \n延迟确认是接收方为了合并ACK而延迟发送确认(通常延迟200ms以内),若发送方等待接收方的ACK才能发送下一批数据,两者结合可能导致数据发送延迟进一步增加(即“Nagle+延迟ACK”的叠加效应)。\n\n\n### **如何禁用Nagle算法**\n在需要低延迟的场景(如游戏、实时通信),可通过设置TCP选项`TCP_NODELAY`(大多数编程语言/系统都支持)禁用Nagle算法,强制TCP立即发送数据,牺牲部分带宽效率换取实时性。\n\n\n### **总结:**\nNagle算法是TCP为平衡效率与开销设计的优化机制,通过合并小数据包减少网络负担,但需根据应用场景权衡实时性需求决定是否启用。\n\n[^1]: \n", + "计算机网络/TCP的三次握手四次握手.md": "**TCP连接建立过程:**\n首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源。Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。\n\n**TCP连接断开过程:**\n假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说\"我Client端没有数据要发给你了\",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,\"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息\"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,\"告诉Client端,好了,我这边数据发完了,准备好关闭连接了\"。Client端收到FIN报文后,\"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。\",Server端收到ACK后,\"就知道可以断开连接了\"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!\n\n**为什么要三次握手?**\n\n在只有两次\"握手\"的情形下,假设Client想跟Server建立连接,但是却因为中途连接请求的数据报丢失了,故Client端不得不重新发送一遍;这个时候Server端仅收到一个连接请求,因此可以正常的建立连接。但是,有时候Client端重新发送请求不是因为数据报丢失了,而是有可能数据传输过程因为网络并发量很大在某结点被阻塞了,这种情形下Server端将先后收到2次请求,并持续等待两个Client请求向他发送数据...问题就在这里,Cient端实际上只有一次请求,而Server端却有2个响应,极端的情况可能由于Client端多次重新发送请求数据而导致Server端最后建立了N多个响应在等待,因而造成极大的资源浪费!所以,\"三次握手\"很有必要!\n\n**为什么要四次挥手?**\n\n试想一下,假如现在你是客户端你想断开跟Server的所有连接该怎么做?第一步,你自己先停止向Server端发送数据,并等待Server的回复。但事情还没有完,虽然你自身不往Server发送数据了,但是因为你们之前已经建立好平等的连接了,所以此时他也有主动权向你发送数据;故Server端还得终止主动向你发送数据,并等待你的确认。其实,说白了就是保证双方的一个合约的完整执行!\n\n使用TCP的协议:FTP(文件传输协议)、Telnet(远程登录协议)、SMTP(简单邮件传输协议)、POP3(和SMTP相对,用于接收邮件)、HTTP协议等。", + "计算机网络/网络层次划分.md": "著名的OSI/RM模型(Open System Interconnection/Reference Model)。它将计算机网络体系结构的通信协议划分为七层,自下而上依次为:\n物理层(Physics Layer)、\n数据链路层(Data Link Layer)、\n网络层(Network Layer)、\n传输层(Transport Layer)、\n会话层(Session Layer)、\n表示层(Presentation Layer)、\n应用层(Application Layer)。\n其中第四层完成数据传送服务,上面三层面向用户。\n\n除了标准的OSI七层模型以外,常见的网络层次划分还有TCP/IP四层协议以及TCP/IP五层协议", + "面试八股/Nacos功能与应用场景详解.md": "Nacos 是阿里巴巴开源的 **动态服务发现、配置管理与服务治理平台**,旨在简化微服务架构的构建、交付和管理。\n\n---\n\n## 🚀 核心功能\n\n| 功能 | 主要作用 |\n|------|----------|\n| 🎯 **服务注册与发现** | 服务提供者注册自身信息,服务消费者动态发现和调用其他服务。 |\n| ⚙️ **动态配置管理** | 集中管理所有环境的配置,支持实时推送变更,无需重启应用。 |\n| 🔍 **服务健康监测** | 定期检查服务实例健康状况,自动隔离不健康实例,保障系统稳定性。 |\n| 🚦 **动态DNS与流量管理** | 支持权重路由,助力灰度发布、蓝绿部署等高级流量管理策略。 |\n\n---\n\n## 🎯 服务发现与健康检查\n\n- **服务注册**:实例启动时向 Nacos 注册自身元数据(服务名、IP、端口等)。 \n- **服务发现**:消费者通过服务名查询健康实例,实现通信而无需关心具体地址。 \n- **健康检查**:支持客户端上报与服务端主动探测,自动剔除不健康实例,保障可靠性。 \n\n---\n\n## ⚙️ 动态配置管理\n\n- **集中化管理**:统一存储数据库连接、开关、限流阈值等配置。 \n- **动态刷新**:配置变更实时推送,应用可在运行中直接生效(热更新)。 \n- **版本控制与回滚**:支持历史版本,一键回滚,降低变更风险。 \n\n---\n\n## 🚦 动态DNS与服务治理\n\n- **动态DNS服务**:支持权重路由、流量控制和简易内网 DNS 解析。 \n- **服务与元数据管理**:统一管理服务描述、依赖关系、健康状态、流量及安全策略。 \n\n---\n\n## 💡 主要应用场景\n\n- **数据库配置集中化管理**:提升安全性与合规性。 \n- **限流与降级开关**:结合 Sentinel 等组件实现运行时动态调整。 \n- **多环境与多数据中心**:基于 Namespace 与 Group 实现隔离与灵活部署。 \n\n---\n\n## 📊 与其他组件对比\n\n- ✅ **功能更全面**:Nacos = 服务发现 + 配置管理;Eureka 仅支持服务发现。 \n- ✅ **健康检查机制更强**:优于 Eureka 心跳检测。 \n- ✅ **社区与生态活跃**:Eureka 已停止维护,而 Nacos 持续迭代。 \n- ✅ **多数据中心支持优越**:原生支持多数据中心部署。 \n\n---\n\n## 📚 总结\n\nNacos 集 **服务发现、配置管理、服务治理** 于一体, \n极大简化了微服务架构复杂性,提升了 **开发效率**、**可维护性** 和 **系统弹性**。\n\n---", + "面试八股/计算机面试经典八股.md": "+好的!计算机面试中最经典、最高频的“八股文”主要围绕以下几个核心领域展开。掌握这些基础知识和原理是通关技术面试的关键:\n\n## 🧠 一、 数据结构与算法\n\n1. **基础数据结构:**\n * **数组 vs 链表:** 内存结构、访问/插入/删除时间复杂度、适用场景。\n * **栈(Stack) & 队列(Queue):** LIFO/FIFO 原理、实现方式(数组/链表)、应用场景(函数调用栈、BFS/DFS)。\n * **哈希表(Hash Table):** 原理(哈希函数、冲突解决-开放寻址/链地址法)、时间复杂度分析、负载因子、扩容机制。\n * **堆(Heap) / 优先队列(Priority Queue):** 结构(通常是二叉堆)、操作(插入、删除堆顶、堆化)、应用(Top K、中位数、Dijkstra)。\n * **树(Tree):**\n * 二叉树(Binary Tree):遍历(前序、中序、后序、层序)- 递归与非递归实现。\n * 二叉搜索树(BST):定义、查找、插入、删除、中序遍历有序性。\n * 平衡二叉搜索树(AVL / 红黑树):平衡因子/红黑规则、旋转操作、为什么需要(避免BST退化成链表)、应用(Java HashMap的TreeBin/TreeMap)。\n * **图(Graph):** 表示方法(邻接矩阵、邻接表)、遍历算法(BFS、DFS)、常见算法(拓扑排序、最短路径-Dijkstra/Bellman-Ford/Floyd、最小生成树-Prim/Kruskal)。\n\n2. **基础算法思想:**\n * **排序算法:**\n * 比较排序:**快速排序**(分治、选基准、partition过程、时间复杂度-最好O(nlogn)/最坏O(n²)/平均、空间复杂度、稳定性❌)、**归并排序**(分治、稳定✅、时间复杂度O(nlogn)、空间复杂度O(n))、**堆排序**(建堆O(n)、排序O(nlogn)、不稳定❌)、插入排序、冒泡排序、选择排序(原理、时间复杂度)。\n * 非比较排序:计数排序、桶排序、基数排序(思想、适用场景)。\n * **搜索算法:** **二分查找**(前提有序、循环/递归实现、变种问题-找第一个/最后一个/旋转数组)。\n * **递归 & 分治:** 思想、经典问题(斐波那契、汉诺塔、归并/快排)。\n * **贪心算法(Greedy):** 思想(局部最优->全局最优?)、适用场景(活动选择、霍夫曼编码、最小生成树-Prim/Kruskal)、与动态规划区别。\n * **动态规划(DP):** **核心思想**(最优子结构、重叠子问题、状态转移方程)、**解题步骤**(定义状态、状态转移、初始化、边界、输出)、**经典问题**(斐波那契、爬楼梯、背包问题01/完全、最长公共子序列LCS、最长递增子序列LIS、编辑距离、股票买卖系列)。\n * **回溯(Backtracking):** 思想(试错、DFS+剪枝)、经典问题(N皇后、全排列、组合、子集、数独)。\n * **双指针(Two Pointers):** 应用(有序数组两数之和、滑动窗口-最小覆盖子串/最长无重复子串、快慢指针-链表判环/找中点)。\n * **位运算(Bit Manipulation):** 常用操作(与、或、异或、非、移位)、常见技巧(判断奇偶、交换两数、找出只出现一次的数字、位1的个数)。\n\n## 🖥 二、 操作系统\n\n1. **进程与线程:**\n * 进程 vs 线程(定义、资源分配、切换开销、通信方式)。\n * **进程间通信(IPC):** 管道、命名管道、信号、消息队列、共享内存、信号量、套接字。\n * **线程同步机制:** **互斥锁(Mutex)**、**信号量(Semaphore)**、**条件变量(Condition Variable)**、读写锁(Read-Write Lock)、自旋锁(Spin Lock)(原理、适用场景、死锁避免)。\n * **死锁(Deadlock):** 必要条件(互斥、请求与保持、不可剥夺、环路等待)、预防策略、避免策略(银行家算法)、检测与恢复。\n2. **内存管理:**\n * **虚拟内存(Virtual Memory):** 为什么需要?分页(Paging)机制(页表、TLB快表)、分段(Segmentation)机制。\n * **页面置换算法:** **最佳置换(OPT)**、**先进先出(FIFO)**、**最近最久未使用(LRU)**、时钟算法(Clock) 的原理和优缺点。\n * **内存分配:** 伙伴系统(Buddy System)、Slab分配器。\n3. **文件系统:** 文件描述符(File Descriptor)、inode结构、文件存储方式(连续、链式、索引)、目录结构。\n4. **CPU调度:** 调度算法(FCFS、SJF、优先级、RR轮转、多级反馈队列)的目标和特点。\n5. **I/O模型:** 阻塞I/O、非阻塞I/O、I/O多路复用(select/poll/epoll)、信号驱动I/O、异步I/O(AIO) 的区别和比较(特别是epoll的优势)。\n\n## 🌐 三、 计算机网络\n\n1. **网络模型:** **OSI七层模型** 和 **TCP/IP四层模型** 各层功能、对应协议。\n2. **核心协议:**\n * **TCP vs UDP:** 根本区别(连接、可靠性、有序性、流量控制、拥塞控制)、头部结构、应用场景。\n * **TCP可靠传输:** 序号/确认号、超时重传、滑动窗口机制。\n * **TCP连接管理:** **三次握手**(详细过程、为什么是三次?)、**四次挥手**(详细过程、为什么是四次?TIME_WAIT状态的作用?)。\n * **TCP流量控制:** 滑动窗口机制。\n * **TCP拥塞控制:** 慢启动(Slow Start)、拥塞避免(Congestion Avoidance)、快速重传(Fast Retransmit)、快速恢复(Fast Recovery) 算法原理。\n * **HTTP:**\n * 请求方法(GET/POST/PUT/DELETE等区别)、状态码(1xx/2xx/3xx/4xx/5xx常见状态码含义)。\n * **HTTP/1.0 vs HTTP/1.1 vs HTTP/2 vs HTTP/3:** 主要改进(连接复用、头部压缩、服务器推送、QUIC协议)。\n * **HTTPS:** SSL/TLS协议作用、加密过程(非对称加密交换对称密钥、对称加密通信)、数字证书作用。\n * **DNS:** 作用、查询过程(递归、迭代)、记录类型(A、AAAA、CNAME、MX、NS)。\n3. **网络安全基础:**\n * **对称加密 vs 非对称加密:** 原理、优缺点、代表算法(AES、RSA)。\n * **数字签名 & 数字证书:** 作用、原理(私钥签名,公钥验签;CA中心颁发证书)。\n * 常见攻击:XSS、CSRF、SQL注入、DDoS、中间人攻击的原理和基本防御措施。\n4. **网络层:** IP协议、IP地址分类/子网划分/CIDR、ARP协议、路由协议(RIP、OSPF、BGP基本思想)。\n5. **传输层与应用层:** 端口号作用、Socket编程基础。\n\n## 🗃 四、 数据库(以关系型数据库 MySQL 为主)\n\n1. **SQL基础:** 常用语句(SELECT, INSERT, UPDATE, DELETE, JOIN, GROUP BY, HAVING, ORDER BY, LIMIT)、多表连接(INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN)。\n2. **索引(Index):**\n * **为什么需要索引?** 加速查询。\n * **数据结构:** **B+树**(为什么比B树更适合数据库?)、哈希索引(适用场景)。\n * **聚簇索引(Clustered Index) vs 非聚簇索引(Non-Clustered Index / Secondary Index):** 根本区别(叶子节点是否存储完整行数据)、InnoDB实现。\n * **索引优化:** 覆盖索引、最左前缀原则、索引下推(ICP)。\n * **索引失效场景:** 函数操作、类型转换、`LIKE '%xx'`、OR条件(部分情况)、不等于(!=, <>)、索引列计算。\n3. **事务(Transaction):**\n * **ACID特性:** 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability) 的含义。\n * **隔离级别(Isolation Level):** **读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read - MySQL默认)、串行化(Serializable)**。每个级别能解决哪些并发问题(脏读、不可重复读、幻读)?\n * **并发问题:** 脏读、不可重复读、幻读的定义。\n * **MVCC(多版本并发控制):** 原理(Undo Log、Read View)、如何实现RC和RR级别(特别是RR如何解决幻读?)。\n4. **锁(Locking):** 共享锁(S锁/读锁)、排他锁(X锁/写锁)、意向锁、行锁、表锁、间隙锁(Gap Lock)、临键锁(Next-Key Lock)的作用和应用场景(特别是InnoDB如何解决幻读)。\n5. **日志(Logging):**\n * **Redo Log(重做日志):** 作用(保证持久性、Crash-Safe)、Write-Ahead Logging(WAL)机制。\n * **Undo Log(回滚日志):** 作用(保证原子性、实现MVCC)。\n * **Binlog(归档日志):** 作用(主从复制、数据恢复)、格式(Statement/Row/Mixed)。\n6. **数据库设计:** 三大范式(1NF, 2NF, 3NF)基本概念、反范式化设计场景。\n7. **性能优化:** Explain分析SQL执行计划、慢查询优化思路。\n\n## 📐 五、 系统设计(面向中高级岗位)\n\n1. **设计原则:** KISS, YAGNI, DRY, SOLID (尤其是单一职责、开闭原则)。\n2. **方法论:**\n * 需求澄清(功能需求、非功能需求-性能/可用性/扩展性/一致性/容错性/安全性)。\n * 估算(QPS、TPS、存储量、带宽)。\n * 抽象与模块化。\n * 核心组件设计(API、数据模型、存储方案、算法)。\n * 深入细节(扩展性、可靠性、性能优化)。\n3. **常见组件与模式:**\n * 负载均衡(LB: Nginx, HAProxy, LVS)。\n * 缓存(Cache: Redis, Memcached)- 缓存策略(Cache Aside, Read/Write Through, Write Behind)、缓存穿透/击穿/雪崩及解决方案。\n * 消息队列(MQ: Kafka, RabbitMQ, RocketMQ)- 解耦、异步、削峰填谷、保证最终一致性。\n * 数据库扩展:读写分离、分库分表(水平/垂直拆分)、分区。\n * 分布式ID生成(Snowflake算法)。\n * 分布式一致性协议:**CAP理论**、**BASE理论**、**Raft/Paxos**(选主、日志复制)基本原理(理解核心思想即可,不要求推导)。\n * 微服务架构:服务注册与发现(Eureka, Nacos, Consul)、API网关(Gateway)、配置中心、服务调用(RPC/REST)、熔断限流(Hystrix, Sentinel)。\n4. **经典系统设计题:** 设计Twitter/微博、设计短链系统、设计秒杀系统、设计分布式缓存、设计搜索引擎、设计聊天系统等。\n\n## 🐍 六、 编程语言特性(根据应聘语言选择)\n\n1. **面向对象(OOP):** 封装、继承、多态、抽象类 vs 接口、重载 vs 重写。\n2. **内存管理:** 垃圾回收(GC)原理(标记清除、复制、标记整理、分代收集-G1/ZGC)、引用类型(强引用、软引用、弱引用、虚引用)。\n3. **并发编程:** 线程生命周期、创建方式、线程池(核心参数、工作流程、拒绝策略)、锁(Synchronized底层原理、Lock/Condition)、并发容器(ConcurrentHashMap原理-CAS+synchronized+分段锁思想)、原子类(CAS操作、ABA问题)、线程间通信。\n4. **语言特性:** 如Java的JVM内存区域、类加载机制、反射、异常体系、集合框架(HashMap源码:put/get流程、扩容、JDK1.7 vs 1.8+);Python的GIL、装饰器、生成器、鸭子类型;Go的Goroutine、Channel、defer等。\n\n## 📌 关键点提醒\n\n1. **理解原理,而非死记硬背:** 面试官更关注你是否真正理解了背后的思想(为什么用这个?解决了什么问题?优缺点是什么?)。\n2. **联系实际:** 思考这些知识在实际系统/项目中是如何应用的。\n3. **清晰表达:** 能条理清晰、简洁准确地阐述概念和过程。\n4. **动手实践:** 算法题要动手写,数据库要会写SQL,系统设计要多思考多画图。\n5. **关注细节:** 很多问题会深入到具体实现细节(如HashMap冲突解决、ConcurrentHashMap分段锁演变、MySQL RR级别如何避免幻读、TCP TIME_WAIT)。\n6. **追踪发展:** 了解一些新技术趋势(如HTTP/3, QUIC, eBPF, 云原生, Serverless)的基本概念。\n\n这份清单涵盖了计算机面试中最核心、最高频的基础知识点。针对具体岗位(前端、后端、算法、运维、测试等)", + "首页.md": "\n## 引言\n你好,陌生人!这是我的学习笔记,用来展示我的一些学习路径\n欢迎和我一起讨论和交流学习!\n\n## 联系方式\nQQ:3205788256\n邮箱:3205788256@qq.com\n个人主页:shumengya.top\n作品集:work.shumengya.top" +} \ No newline at end of file diff --git a/public/data/stats.json b/public/data/stats.json new file mode 100644 index 0000000..5f84166 --- /dev/null +++ b/public/data/stats.json @@ -0,0 +1,6 @@ +{ + "totalFiles": 163, + "totalFolders": 34, + "generatedAt": "2025-10-02T01:36:14.347Z", + "sourceDirectory": "E:\\React\\markdown-to-web\\public\\mengyanote" +} \ No newline at end of file diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..95bfa8a Binary files /dev/null and b/public/logo.png differ diff --git a/public/mengyanote/.obsidian/appearance.json b/public/mengyanote/.obsidian/appearance.json index 8241d78..8ab5cb8 100644 --- a/public/mengyanote/.obsidian/appearance.json +++ b/public/mengyanote/.obsidian/appearance.json @@ -1,6 +1,6 @@ { "cssTheme": "Border", - "theme": "obsidian", + "theme": "moonstone", "monospaceFontFamily": "American Typewriter", "baseFontSize": 16 } \ No newline at end of file diff --git a/public/mengyanote/.obsidian/workspace.json b/public/mengyanote/.obsidian/workspace.json index b971563..735d23f 100644 --- a/public/mengyanote/.obsidian/workspace.json +++ b/public/mengyanote/.obsidian/workspace.json @@ -13,12 +13,26 @@ "state": { "type": "markdown", "state": { - "file": "编程语言/Android/Linux配置安卓Gradle构建环境.md", + "file": "Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "Linux配置安卓Gradle构建环境" + "title": "NapCat-QQ机器人框架" + } + }, + { + "id": "108d0380d5e0d36b", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "编程语言/C/C语言不设置临时变量交换x和y的值(方法).md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "C语言不设置临时变量交换x和y的值(方法)" } }, { @@ -35,7 +49,8 @@ "title": "Docker命令集合" } } - ] + ], + "currentTab": 1 } ], "direction": "vertical" @@ -184,45 +199,53 @@ "obsidian-livesync:Show Customization sync": false } }, - "active": "8304b0e105b08ed0", + "active": "108d0380d5e0d36b", "lastOpenFiles": [ - "编程语言/Android/安卓Gradle构建常用命令总结.md", - "树萌芽的小本本/目前已部署网站.md", - "树萌芽的小本本/网站小技巧.md", - "Docker/优秀好用的Docker镜像/FileCodeBox-文件快递柜.md", - "Docker/优秀好用的Docker镜像/Postgres数据库.md", - "Docker/优秀好用的Docker镜像/未命名.md", - "临时解决方案/2025年大一下暑假规划(大方向).md", - "树萌芽的小本本/树萌芽の编程想法.md", - "树萌芽的小本本/检测IP的网站.md", - "树萌芽的小本本/重要信息记录.md", - "Docker/优秀好用的Docker镜像/Gitea-私有化仓库部署.md", - "Docker/Docker命令集合.md", - "Docker/优秀好用的Docker镜像/MySQL数据库.md", - "Docker/优秀好用的Docker镜像/MongoDB数据库.md", - "Docker/优秀好用的Docker镜像/Redis数据库.md", - "Docker/Docker 镜像相关.md", - "Docker/优秀好用的Docker镜像", - "Docker", - "大萌芽-Debian13服务器.md", - "Docker/Docker镜像快速迁移.md", - "无线-HCIA 02.md", - "Linux相关/把Ubuntu镜像源切换到阿里云.md", - "临时解决方案/修改hosts方式来直连Github.md", - "临时解决方案/萌芽云剪切板.md", - "2025年9月紧急规划.md", - "树萌芽制作的小东西/网站/万象口袋/软件名字.md", - "树萌芽制作的小东西/网站/树萌芽API集合/功能详情.md", - "树萌芽制作的小东西/网站/树萌芽API集合/API目录.md", - "树萌芽制作的小东西/网站/树萌芽API集合", - "树萌芽制作的小东西/网站/万象口袋", - "编程语言/Golang", - "编程语言/CSharp", - "编程语言/C++", - "编程语言/C语言", - "编程语言", - "计算机网络", - "图片文件夹/Screenshot_20250717_225309.jpg", - "Screenshot_20250717_225309.jpg" + "面试八股/Nacos功能与应用场景详解.md", + "临时/快速开启一个http服务器.md", + "Linux/wlan0简单介绍.md", + "杂项/计算机刷题网站.md", + "杂项/markdown格式(没什么用).md", + "杂项/文本颜色测试.md", + "杂项/古诗.md", + "杂项/PTA好题-计算众数.md", + "杂项/PTA好题-英文单词排序.md", + "杂项/PTA万能代码.md", + "杂项/Markdown格式大全.md", + "杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md", + "杂项/10月23日大学英语笔记.md", + "杂项", + "华为ICT/杂项/计算机刷题网站.md", + "华为ICT/杂项/文本颜色测试.md", + "华为ICT/杂项/古诗.md", + "华为ICT/杂项/PTA好题-计算众数.md", + "华为ICT/杂项/PTA好题-英文单词排序.md", + "华为ICT/杂项/PTA万能代码.md", + "华为ICT/杂项/markdown格式(没什么用).md", + "华为ICT/杂项/Markdown格式大全.md", + "华为ICT/杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md", + "华为ICT/杂项/10月23日大学英语笔记.md", + "华为ICT/杂项", + "临时/灵创第15周周报.md", + "临时/灵创第14周个人汇报.md", + "临时/第16周灵创汇报.md", + "临时", + "游戏引擎/Unity/Unity代码片段", + "游戏引擎/Unreal", + "游戏引擎/新建文件夹", + "游戏引擎/Unity", + "Minecraft/基岩版服务器/NukkitLearn/images/5-04.png", + "Minecraft/基岩版服务器/NukkitLearn/images/5-03.png", + "Minecraft/基岩版服务器/NukkitLearn/images/5-02.png", + "Minecraft/基岩版服务器/NukkitLearn/images/5-01.png", + "Minecraft/基岩版服务器/NukkitLearn/images/2-01.png", + "Minecraft/基岩版服务器/NukkitLearn/images/1-10.png", + "Minecraft/基岩版服务器/NukkitLearn/images/1-09.png", + "Minecraft/基岩版服务器/NukkitLearn/images/1-08.png", + "Minecraft/基岩版服务器/NukkitLearn/images/1-07.png", + "Minecraft/基岩版服务器/NukkitLearn/images/1-06.png", + "Minecraft/基岩版服务器/NukkitLearn/_config.yml", + "Minecraft/基岩版服务器/NukkitLearn/images", + "Minecraft/基岩版服务器/NukkitLearn" ] } \ No newline at end of file diff --git a/public/mengyanote/.trash/0-00.png b/public/mengyanote/.trash/0-00.png new file mode 100644 index 0000000..d2d2cfd Binary files /dev/null and b/public/mengyanote/.trash/0-00.png differ diff --git a/public/mengyanote/.trash/1-01.png b/public/mengyanote/.trash/1-01.png new file mode 100644 index 0000000..f3236c3 Binary files /dev/null and b/public/mengyanote/.trash/1-01.png differ diff --git a/public/mengyanote/.trash/1-02.png b/public/mengyanote/.trash/1-02.png new file mode 100644 index 0000000..f1175a5 Binary files /dev/null and b/public/mengyanote/.trash/1-02.png differ diff --git a/public/mengyanote/.trash/1-03.png b/public/mengyanote/.trash/1-03.png new file mode 100644 index 0000000..0aa16da Binary files /dev/null and b/public/mengyanote/.trash/1-03.png differ diff --git a/public/mengyanote/.trash/1-04.png b/public/mengyanote/.trash/1-04.png new file mode 100644 index 0000000..7613a29 Binary files /dev/null and b/public/mengyanote/.trash/1-04.png differ diff --git a/public/mengyanote/.trash/1-05.png b/public/mengyanote/.trash/1-05.png new file mode 100644 index 0000000..75f5975 Binary files /dev/null and b/public/mengyanote/.trash/1-05.png differ diff --git a/public/mengyanote/.trash/1-06.png b/public/mengyanote/.trash/1-06.png new file mode 100644 index 0000000..d87a70e Binary files /dev/null and b/public/mengyanote/.trash/1-06.png differ diff --git a/public/mengyanote/.trash/1-07.png b/public/mengyanote/.trash/1-07.png new file mode 100644 index 0000000..f95bcb4 Binary files /dev/null and b/public/mengyanote/.trash/1-07.png differ diff --git a/public/mengyanote/.trash/1-08.png b/public/mengyanote/.trash/1-08.png new file mode 100644 index 0000000..88c2847 Binary files /dev/null and b/public/mengyanote/.trash/1-08.png differ diff --git a/public/mengyanote/.trash/1-09.png b/public/mengyanote/.trash/1-09.png new file mode 100644 index 0000000..2aa9a18 Binary files /dev/null and b/public/mengyanote/.trash/1-09.png differ diff --git a/public/mengyanote/.trash/1-10.png b/public/mengyanote/.trash/1-10.png new file mode 100644 index 0000000..5e6f9e8 Binary files /dev/null and b/public/mengyanote/.trash/1-10.png differ diff --git a/public/mengyanote/.trash/2-01.png b/public/mengyanote/.trash/2-01.png new file mode 100644 index 0000000..f4fe330 Binary files /dev/null and b/public/mengyanote/.trash/2-01.png differ diff --git a/public/mengyanote/.trash/5-01.png b/public/mengyanote/.trash/5-01.png new file mode 100644 index 0000000..b05b0b3 Binary files /dev/null and b/public/mengyanote/.trash/5-01.png differ diff --git a/public/mengyanote/.trash/5-02.png b/public/mengyanote/.trash/5-02.png new file mode 100644 index 0000000..c65626a Binary files /dev/null and b/public/mengyanote/.trash/5-02.png differ diff --git a/public/mengyanote/.trash/5-03.png b/public/mengyanote/.trash/5-03.png new file mode 100644 index 0000000..ae18359 Binary files /dev/null and b/public/mengyanote/.trash/5-03.png differ diff --git a/public/mengyanote/.trash/5-04.png b/public/mengyanote/.trash/5-04.png new file mode 100644 index 0000000..5d84c08 Binary files /dev/null and b/public/mengyanote/.trash/5-04.png differ diff --git a/public/mengyanote/.trash/PM格式化输出.md b/public/mengyanote/.trash/PM格式化输出.md new file mode 100644 index 0000000..715f652 --- /dev/null +++ b/public/mengyanote/.trash/PM格式化输出.md @@ -0,0 +1,6 @@ +```php +use pocketmine\utils\TextFormat; + +$this->getServer()->getLogger()->info(TextFormat::GREEN . "[刷矿机] 插件激活成功!"); +``` + diff --git a/public/mengyanote/.trash/README.md b/public/mengyanote/.trash/README.md new file mode 100644 index 0000000..c54e7e6 --- /dev/null +++ b/public/mengyanote/.trash/README.md @@ -0,0 +1,179 @@ +# 在阅读本教程前,务必阅读本Readme + +目前由官方承认的几个宣传贴 + +https://www.minebbs.com/threads/dreamserver-nukkit-nukkit.2912/#post-13183 + +https://www.mcplugin.cn/thread-1259-1-1.html + +https://www.mcbbs.net/forum.php?mod=viewthread&tid=927009&page=1#pid15854025 + +https://www.mcbbs.net/forum.php?mod=viewthread&tid=930861&mobile=2 + +# 史上最详细的Nukkit教程 +#### Learning Nukkit Whoever you are! + + +- [中文(简体)](README.md) +- [English](README_en.md) + +#### 说明 + +您可以在这里作为一本书观看教程: http://noyark.net/ + +本教程遵循[发现者小组公约](LICENSE) + +#### 友情项目 + +[基于Java开发的SCPSL服务端](https://github.com/jsmod2-java-c/JSmod2-Core) + +#### 关于主要作者 + +事实上作者上已经退坑了,但是不影响写教程,只是有几点还请悉知: +- 不要问如何搭建服务器; +- 不要PM任何有关人员定制插件; +- 除了写这个教程,作者不会参与任何和Minecraft有关的活动和交易; +- 本教程需要一定的Java基础,请先做好预习功课,并且作者不会回答任何基础的问题; +- 作者目前是高中学生,因此时间并不充裕,更新速度请大家海涵; +- 如有任何疏漏或Bug的存在,还请指正; + +#### 作者的扯皮 + +Nukkit核心作为一个服务端开发框架,虽然性能优越,吸引了大批的开发者加入开发,但教程稀少,学习难度大,使很多小白 +望而却步,基于目前很多人对于教程的渴望,包括作者在初学的时候只能通过到处询问和看核心源码来了解如何使用一个东西, +但并不是所有的人都能安心去看核心源码或者到处询问问题。同时,本教程会重复强调一件事情: 打好基础,本教程已经列出 +您需要掌握的java基础,什么0基础直接学习nukkit都是骗人的,作者已经见过很多这样的初学者,很少的人通过这种方式 +学会(无疑是一种懒散的行为),nukkit事实上就是学习一个新的api,并无很大的入门难度,只要您学习了基础,就能很快从 +这里得到启发,并参与到nukkit的大家庭。 + +主作者其实很和蔼,但是对于简单的问题作者由于时间问题是不能回答的,也不能干刷屏之类的事情,再和蔼的人也会把你给 +屏蔽,当然,作者坚持开放原则,如果有相关问题,可以issues发表您的疑问。 + +同时,记得给项目一个star支持一下,并且将这个项目宣传给别人,在支持作者同时,造福他人。您的支持和宣传就是作者写下去的动力, +希望这个教程可以帮到您,我们由衷的感谢:) + +--- MagicLu550 + +#### 关于本教程 + +Nukkit官方说过: Nukkit是一款高性能的核能驱动的Minecraft基岩版服务器,它的 +速度更快,性能相比PocketMine更高。 +``` +Nukkit is nuclear-powered server software for Minecraft Bedrock Edition. It has a few key advantages over other server software: + +Written in Java, Nukkit is faster and more stable. +Having a friendly structure, it's easy to contribute to Nukkit's development and rewrite plugins from other platforms into Nukkit plugins. +Nukkit is under improvement yet, we welcome contributions. +``` + +目前,依托Java语言的健壮性,Nukkit形成了强大的生态,并且出现了很多分支,目前使用最广泛的分支是[NukkitX](http://nukkitx.com) + +感谢您能观看我们编写的教程。该教程在编写阶段,更新间隔可能会很长。 +请谅解。该教程是为了简化目前很多晦涩难懂的教程,使得有过Java语法基础的朋友 +能方便地了解Nukkit和学习Nukkit. 目前Nukkit的学习难度主要在于其资料过少。 +我们将会整理和参考其他相关资料来编写该教程,也感谢您参与编写,造福大家 + +同时,转发本教程应当附上GitHub原地址,不得任意转发和搬运,以及商业使用。 +本教程不涉及语法,只涉及Nukkit的各种库的解释以便于开发 +您所需要掌握的最基本的Java基础体系 +``` + --基础部分 + -- 语法 + -- 变量定义 + -- 方法定义 + -- 基本表达式 + -- 逻辑表达式 + -- 算数表达式 + -- 流程控制 + -- 条件语句 + -- 循环语句 + -- 选择语句 + -- 面向对象 + -- 类,对象的概念 + -- 定义类和声明对象 + -- 包的概念 + -- 匿名内部类 + -- 接口 + -- 抽象类,抽象方法 + -- lambda表达式 + -- 面向对象的三大特征 + -- 继承 + -- 封装 + -- 多态 + -- 枚举 + -- 注解 + -- 类库 + -- 反射 + -- 多线程 + -- 字符串操作 + -- 数字包装类 + -- io流 + -- bio + -- nio + -- 套接字Socket + -- udp + -- tcp + -- 时间类库 + -- 系统类库 + +``` +未来,我们会开发Nukkit-d,是对于Nukkit设计思想的整理和重新实现,以解决目前nukkit维护难的问题 +#### 关于我们 + +如果您有兴趣可以随时发送Pr等 +本教程不定期更新,大概寒假时期更新最快 +相关意见可以联系843983728@qq.com或者加QQ:843983728 + +QQ群: 931210534 + +![QQ群](images/0-00.png) + +#### 贡献标准和须知 + +1. 教程要求尽量自然,易懂,符合本项目所追求的"人人可以学习Nukkit"的宗旨 +2. 编写教程可以在参与编写者添加自己的名字,若没有可以自己手动加入,如第一章所同 +3. 照搬其他教程原文需要得到作者同意,并且在下面注明参考文献。 +4. 若发现侵权行为,与本项目领导者无关,但我们会积极配合找到侵权者 +5. 请尽量以第一章为范本编写您的内容。 +6. 如果有知识缺点,请在Readme里注明这个缺点出处,写在知识缺点里,知识缺点在章节中标注。 +7. 教程补充首要的是解决知识缺点 +8. 由于编写人数较少,教程不避免的会有错误,漏洞,不严谨,如果发现,可以发送pullRequest参与修改 + +#### 知识缺点: + - 关于fallBackPrefix的作用 - 第二章和第四章 [1] + +#### 专栏 + + - [填坑专栏](专栏-关于我们常见的那些坑.md) + + - [用指令设置玩家实体大小](章外篇之—-用指令设置玩家实体大小(简单版).md) + + - [多语言解决方案](章外篇之二-多语言解决方案.md) + +#### 目录 +- [第一部分 基础准备](第一部分前言.md) + - [X] [如何搭建开发环境](第一章-如何搭建环境.md) + - [X] [插件要素](第二章-插件要素.md) + - [X] [如何编写监听器](第三章-如何编写监听器.md) + - [X] [如何编写指令](第四章-如何编写命令.md) + - [X] [如何使用配置文件](第五章-如何使用配置文件.md) + - [X] [如何编写plugin.yml](第六章-如何编写plugin.yml.md) + - [X] [PluginBase类](第七章-PluginBase类.md) + - [X] [练习案例](第八章-案例玩家进入信息等效果.md) +- [第二部分 nukkit的工具和各种事件介绍](第二部分前言.md) + - [X] [主要的事件的介绍](第一章-主要的事件介绍.md) + - [ ] [事件相关方法](第二章-事件相关方法.md) + - [X] [计时器的介绍](第三章-计时器的介绍.md) + - [X] [Server类和PluginManager类](第四章-Server类和PluginManager类.md) + - [ ] [各种实体类的方法介绍](第五章-各种实体类的方法介绍.md) + - [ ] [各种工具类的介绍](第六章-各种工具类的介绍.md) + - [X] [如何发送数据包](第七章-如何发送数据包.md) +- 第三部分 nukkit相关实例 +- 第四部分 nukkit原理剖析 + + +#### 专栏状况 +```diff ++ 专题 ++ 提示信息 +``` diff --git a/public/mengyanote/.trash/_config.yml b/public/mengyanote/.trash/_config.yml new file mode 100644 index 0000000..2f7efbe --- /dev/null +++ b/public/mengyanote/.trash/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-minimal \ No newline at end of file diff --git a/public/mengyanote/.trash/专栏-关于我们常见的那些坑.md b/public/mengyanote/.trash/专栏-关于我们常见的那些坑.md new file mode 100644 index 0000000..43251fe --- /dev/null +++ b/public/mengyanote/.trash/专栏-关于我们常见的那些坑.md @@ -0,0 +1,12 @@ +# 填坑专栏 +#### 这里整理一些容易出现的坑,这里会有解决方案. +##### 大家可以把自己平时的坑写进去,写上解决方案 +##### 或者等待别人写上解决方案 + +1. ClassCastException + 这种是类转换问题的锅,可以查看下 +2. EventException: null +3. Main类名称指错的问题 +4. ClassNotFoundException的问题 +5. NullPointerException的常见问题 +6. 忘记注册监听器的坑 diff --git a/public/mengyanote/.trash/章外篇之—-用指令设置玩家实体大小(简单版).md b/public/mengyanote/.trash/章外篇之—-用指令设置玩家实体大小(简单版).md new file mode 100644 index 0000000..59ef58c --- /dev/null +++ b/public/mengyanote/.trash/章外篇之—-用指令设置玩家实体大小(简单版).md @@ -0,0 +1,57 @@ +## Nukkitlearn章外篇之---用指令设置玩家实体大小(简单版) + +本章外篇教程由zsy制作,本教程非常的简单,目的是为萌新们打开一个很好的思路 +如果你对本篇有任何合理地建议或者疑问,可以联系笔者QQ:910223023,笔者高三 可能回复不会及时,但看到后一定处理。 +1. 首先你需要按照章内的教程,创建一个项目,名称随意,我这里用的SetSize。配置好一系列的东西并创建好plugin.yml后,可以开始了。 + +2. 这是我的plugin.yml中的内容 +``` + name: SetSize + main: xyz.zsy.SetSize.SetSize + version: "1.0.0" + api: ["1.0.0"] + + load: POSTWORLD + + author: zsy + website: xyz.zsy +``` + + 这里再次强调一个坑,main中的路径应是主类的所在的位置,***精确到文件名***,我这里xyz.zsy.SetSize.SetSize的意思是xyz\zsy\SetSize目录下的SetSize.java,读者应该根据自己的包和主类名字修改!否则Nukkit不会加载到插件的主类,插件是无法运行的,因为Nukkit无从下手。 + +3.之后在主类中添加内容,添加的内容如下 + +```java + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + + if (command.getName().equals("ss")) { //判断斜杠后的指令名字 /ss,用法/ss 玩家名字 大小 + if (sender instanceof Player) { //判断发令者是否是玩家 + if (args.length>0) { //判断指令/ss 后是否有参数 + Player p = this.getServer().getPlayer(args[0]); //获取/ss 后的第一个参数,应该是String类 + if (args.length>1) { //同上 判断是否有第二个参数 也就是是否有 大小 这个参数,应该是个数字 + Float size = Float.parseFloat(args[1]); //获取大小,并将它转化为Float型,因为Nukkit中设置实体大小的方法,参数要求是Float + p.setScale(size); //调用setScale()方法来设置玩家大小 + return true; + } + } + } + } + return false; + } + +``` + +4.不要忘了在plugin.yml加入权限组,不然这个指令将会是非法的。 +```yaml +commands: + ss: + description: Set A Player's Size. + usage: "/ss [name] [size]" + permission: SetSize.ss +permissions: + SetSize.ss: + default: op +``` +5.检查没有丢步骤后,就可以编译并且测试了! 当然,设置的玩家大小,当玩家重新进入服务器或者死亡重生后将会变为正常大小,因为本篇设置的只是一个临时变量,实体消失后它也会一起被清理,如果想要永久的保存,则可以利用config储存下来大小,然后在进服和复活事件中进行设置,感兴趣的可以进一步咨询笔者,那么本教程就到此结束了!祝你在胜利之地越战越勇! diff --git a/public/mengyanote/.trash/章外篇之二-多语言解决方案.md b/public/mengyanote/.trash/章外篇之二-多语言解决方案.md new file mode 100644 index 0000000..5ac6dfe --- /dev/null +++ b/public/mengyanote/.trash/章外篇之二-多语言解决方案.md @@ -0,0 +1,477 @@ +# NukkitLearn章外篇之二-插件中的多语言解决方案 + +参与编写者: [innc11](https://github.com/innc11) + +##### 知识点: 配置文件、HashMap、枚举、文本替换、可变参数、正则表达式 + +本章外篇教程innc11制作,目的尽可能地简化插件开发过程中对多语言的处理。不得不说对多语言的支持是插件的一大加分项,特别是将插件发布到Nukkit的国际论坛上更是如此,如果有任何的疑问欢迎随时提issue。 + +## 0.HashMap + +所谓HashMap就是保存着一个个键值对的类,一个存储数据的类,形象的描述HashMap就相当于中药铺的药材柜子,柜子上有着数不清的小屉子,每个小屉子里都放着不同的药材,比如胖大海、金银花、荷叶等等(值),每个小屉子上都有一个标签,写着这个屉子里放着什么药材(键),这样就形成了一个关系,一个标签对应一个药材,这就是键值对的关系,一对一的关系,也是HashMap的存储结构,但也有一些限制,比如不能出现两个一模一样的标签,不然HashMap就无法判断到底需要哪一个小屉子的药材;但可以允许两个屉子里的东西一模一样;屉子可以是空的,但标签绝对不能为空。 + +HashMap能够处理一些数组无法处理的数据,比如一个统计玩家击杀数的插件,当某个玩家干掉10个怪物以后就给其发放奖励,这时候就需要对每个玩家进行记录,把玩家名作为标签,击杀数作为屉子里的东西,每次只需要根据玩家名把对应屉子打开,把里面的数据拿出来+1然后放回去关上屉子即可。这时候便出现了一个关系,每一个玩家名对应一个击杀数。 +``` +zhangsan = 5 +lisi = 3 +wangwu = 8 +``` +玩家名就是键,击杀数就是值,大致就是这个结构,可以随时根据玩家名获取到对应击杀数,这是HashMap的工作方式。 + +## 1. 原理 + +插件首先从配置文件加载所有语言到一个HashMap里,在需要时从这个HashMap里读出来,再进行相应变量替换后,显示给玩家。 + +## 2. 创建项目 + +1. 首先创建一个项目,在这里我使用一个当玩家破坏方块时,给玩家发送一个消息,告诉玩家破坏的方块的ID,这里插件名字就叫 Tips,配置好依赖后,首先是```plugin.yml``` + +```yaml +name: Tips +main: exam.miner.TipsPlugin +version: "1.0" +api: ["1.0.0"] +``` + +## 3. 使用语言类 + +3. 首先我们声明一个语言类,这个类非常简单,仅仅包含一个HashMap、构造方法、获取语言的方法 + +```lang```负责存储所有的语言文本,```String getLang()```负责从```lang```里面获取对应的文本并做参数替换,在构造方法里我们往```lang```里面添加2个语言,其中```BROKE_MESSAGE```和```PLACE_MESSAGE```是关键字,我们通过传递给```getLang()```一个关键字来获取对应的文本,```getLang()```会在```lang```里面用关键字去进行查找,并返回对应的文本 + +```java +public class MyLang +{ + HashMap lang = new HashMap(); + + public MyLang() + { + lang.put("BROKE_MESSAGE", "你破坏了一个方块"); + lang.put("PLACE_MESSAGE", "你放置了一个方块"); + } + + public String getLang(String key) + { + return lang.get(key); + } +} +``` + +接下来是主类: + +在主类中使用刚才的```MyLang```类,并注册监听器,当玩家在破坏或者放置一个方块时,去获取对应的文本,然后发送给玩家 + +```java +public class TipsPlugin extends PluginBase implements Listener +{ + MyLang lang; + + @Override + public void onEnable() + { + lang = new MyLang(); + + getServer().getPluginManager().registerEvents(this, this); + } + + @EventHandler + public void onPlayerBrokeBlock(BlockBreakEvent e) + { + String message = lang.getLang("BROKE_MESSAGE"); // 你放置了一个方块 + e.getPlayer().sendMessage(message); + } + + @EventHandler + public void onPlayerPlaceBlock(BlockPlaceEvent e) + { + String message = lang.getLang("PLACE_MESSAGE"); // 你破坏了一个方块 + e.getPlayer().sendMessage(message); + } + +} +``` + +这就是最简单的方式,但实际开发中语言往往是从配置文件进行加载的,而不是写死在代码里,接下来就是如何从yml文件进行读取加载 + +## 3. 从yaml配置文件加载语言 + +1. 我们使用language.yml文件用来保存语言文本 + +```yaml +# language.yml +PLACE_MESSAGE: "你放置了一个方块" +BROKE_MESSAGE: "你破坏了一个方块" +``` + +1. 接着我们需要修改我们的语言文件,使其从配置文件进行加载,首先需要在```MyLang```类里额外添加一个```Config config```变量,和一个```void reload()```方法,我们手动调用```reload()```方法来从配置文件加载语言文本。 + +2. 构造方法我们需要添加一个参数,用来告诉```MyLang```类应该读取哪一个yml文件,不建议在构造方法中立即调用```reload()```,因为当对象构造的时候```language.yml```可能根本就不存在。非常建议在插件主类中保存默认配置文件后手动调用```reload()``` + +3. 在新添加的```void reload()```方法中,首先是命令```config```(重新)加载一下,然后把```lang```中已经存在的数据全部删除掉,接着就是使用```getKeys(false)```来获取```config```中所有的key,就是上面yml中的```PLACE_MESSAGE```和```BROKE_MESSAGE```,这个方法会以```Set```的形式返回,我们使用foreach进行遍历即可,需要说明的是参数中的```false```指```boolean child```,我们只需要根节点上的key不需要子节点上的key,传```false```即可 +4. 在foreach中我们定义一个变量value来放置获取到的"key对应的值"也就是```你放置了一个方块```和```你破坏了一个方块```接下来我们需要进行一个判断,如果这个值是```String```类型的,我们就把它添加到```lang```里面,如果不是,比如```int```,```bool```,或者```list```类型,则跳过。 + +```java +public class MyLang +{ + Config config; + HashMap lang = new HashMap(); + + public MyLang(String languageFileName) + { + config = new Config(new File(getDataFolder(), languageFileName), Config.YAML); + } + + public void reload() + { + config.reload(); + lang.clear(); + + for(String key : config.getKeys(false)) + { + Object value = config.get(key.name()); + + if(value instanceof String) + { + lang.put(key, (String) value); + } + } + } + + public String getLang(String key) + { + return lang.get(key); + } +} +``` + +5. 主类需要在```new MyLang()```时传递文件名。当然也要把```language.yml```以前打包进插件里。在onEnable()里要调用```saveResource("language.yml", false)```把```language.yml```写入到插件**DataFolder**里 + +```java +public class TipsPlugin extends PluginBase implements Listener +{ + MyLang lang; + + @Override + public void onEnable() + { + saveResource("language.yml", false); + + lang = new MyLang("language.yml"); + lang.reload(); + + getServer().getPluginManager().registerEvents(this, this); + } + + @EventHandler + public void onPlayerBrokeBlock(BlockBreakEvent e) + { + String message = lang.getLang("BROKE_MESSAGE"); // 你放置了一个方块 + e.getPlayer().sendMessage(message); + } + + @EventHandler + public void onPlayerPlaceBlock(BlockPlaceEvent e) + { + String message = lang.getLang("PLACE_MESSAGE"); // 你破坏了一个方块 + e.getPlayer().sendMessage(message); + } + +} +``` + +7. 在实际使用中,我们只需要修改```language.yml```中文字,然后使用指令调用```MyLang.reload()```重新加载即可,但在复杂的插件中,只有这些功能时远远不够的,语言文件不能一成不变,有时候需要将文字中的一部分字符替换成各种实际数据,比如商店插件在交易完成时会显示这笔交易花费了多少多少钱,玩家死亡时会显示被谁谁谁干掉了,其中的"钱"和"击杀者"就是实际的数据,需要根据实际情景来决定具体应该是什么。这就涉及到参数化的问题,将文本中一部分文字使用实际数据进行替换。 + +## 4. 参数化 + +1. 参数化必然会涉及到**占位符**这个概念,拿一个例子来说 + +```yaml +PLACE_MESSAGE: "你放置了ID为 ${BLOCK_ID} 的方块" +``` + +其中的**${BLOCK_ID}**就是占位符,他只是给实际的数据占个位置而已,并不会被显示出来。当然风格可以自己定义,在这个例子中,我们使用```${占位符名字}```这种风格。 + +2. 我们修改我们的```MyLang```类的```getLang()```方法,使其可以动态替换占位符,具体的调用方式为```MyLang.getLang("PLACE_MESSAGE", "{BLOCK_ID}", String.valueOf(block.getId()));``` +3. 多个参数的调用方式 +``` +MyLang.getLang("PLACE_MESSAGE", + "{BLOCK_ID}", String.valueOf(block.getId(), + "{PLAYER_NAME}", player.getName(), + )); +``` +4. 无参数的调用方式 +``` +MyLang.getLang("PLACE_MESSAGE")); +``` +5. 后面的占位符和实际数据总是成双成对的出现,这可以大幅加快开发效率,当然这需要```MyLang.getLang()```具有对应的支持,具体看下面的示例代码。 + +```java +public class MyLang +{ + Config config; + HashMap lang = new HashMap(); + + public MyLang(String languageFileName) + { + config = new Config(new File(getDataFolder(), languageFileName), Config.YAML); + } + + public void reload() + { + config.reload(); + lang.clear(); + + for(String key : config.getKeys(false)) + { + Object value = config.get(key.name()); + + if(value instanceof String) + { + lang.put(key, (String) value); + } + } + } + + public String getLang(String key, String... argsPair) // 这里使用可变参数,当做数组一样处理即可 + { + String rawStr = lang.get(key); + + int argCount = argsPair.length / 2; // 计算出有多少"对"参数,末尾的孤立参数会被舍弃 + + for(int i=0;i 将MyLang.L作为键(key)以提高效率 + HashMap lang = new HashMap(); + + public MyLang(String languageFileName) + { + config = new Config(new File(getDataFolder(), languageFileName), Config.YAML); + } + + public void reload() + { + config.reload(); + lang.clear(); + + // 一个标志,如果有缺少的关键字,会被补全,然后保存config,以便调试 + boolean supplement = false; + + // 现在是以Lang.values()进行遍历,而不是config.getKeys(),注意 + for(L key : L.values()) + { + Object value = config.get(key.name()); + + // 如果这个关键字不存在,会自动补齐,并设置标志位 + if(v==null) + { + config.set(key.name(), key.getDefaultLangText()); + supplement = true; + lang.put(key, key.getDefaultLangText()); + } + + if(value instanceof String) + { + lang.put(key, (String) value); + } + } + + // 如果有补齐,则需要保存这个config,以便用户可以在config内查看到以定位问题 + if(supplement) + { + config.save(); + } + + } + + public String getLang(L key, String... argsPair) // 这里使用可变参数,当做数组一样处理即可 + { + String rawStr = lang.get(key); + + int argCount = argsPair.length / 2; // 计算出有多少"对"参数,末尾的孤立参数会被舍弃 + + for(int i=0;i + + releases + nukkitx-releases + https://repo.nukkitx.com/release + + + snapshots + nukkitx-snapshots + https://repo.nukkitx.com/snapshot + + + + + + nukkitx-repo + nukkitx-snapshot + https://repo.nukkitx.com/snapshot + + + + + + cn.nukkit + nukkit + 1.0-SNAPSHOT + + +``` + +如图所示 +![1-04](images/1-04.png) + +5. 接下来在程序上可以进行开发了 + +二. 项目结构 + +1.nukkit的基本项目结构为 +``` + + -- project + -- src + -- main-class + -- resources + -- plugin.yml +``` +因此我们需要创建主类和plugin.yml(插件配置文件) +转自snake1999: + + - 每个插件都有 plugin.yml 文件。 + - 这里介绍一些设置,说明这个文件的格式。 + - 插件没有这个文件,就不会被 Nukkit 识别和加载。 + - 这个文件的最基本的应该是类似这样的: + +```yaml + + name: FirstPlugin # nukkit运行时识别的插件名 + main: net.noyark.www.Example # 主类名称 + version: "0.0.1" # 版本号 + author: 你的名字,这里指作者名称 + api: ["1.0.8"] # 早期nukkit api为1.0.0, + # 目前大概为1.0.8 + description: My first plugin #介绍 +``` + +目前大概为这种结构 +![1-05](images/1-05.png) + +但是,我们项目目前这样是不够的,Example类需要继承PluginBase才可以成为真正可以加载的主类 + + +```java +package net.noyark.www; + +import cn.nukkit.plugin.PluginBase; + +public class Example extends PluginBase { + + /** + * 在服务器加载完成前执行一次 + */ + @Override + public void onLoad() { + + } + + /** + * 在服务器加载完成后执行一次 + */ + @Override + public void onEnable() { + + } + + /** + * 服务器即将关闭前执行一次 + */ + + @Override + public void onDisable() { + + } +} +``` + +三. 调试插件 + +其实调试插件很简单,这里我们需要这几个过程 + +- 编译,打包 +- 部署 +- 运行加载 +- 调试 + +1. 编译打包很简单,我们使用ideaIDE可以轻松的实现maven打包 + +PS:当然在打包之前,建议在pom.xml里加下这个,可以解决idea的编译器版本 +无效等一系列问题 +```xml + + + + net.alchim31.maven + scala-maven-plugin + 3.2.2 + + + scala-compile-first + process-resources + + add-source + compile + + + + scala-test-compile + process-test-resources + + testCompile + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + UTF-8 + + + + + +``` +当然项目是jdk8演示的,如果您不是jdk8,则需要修改一个地方 +jdk9 +```xml + + + + net.alchim31.maven + scala-maven-plugin + 3.2.2 + + + scala-compile-first + process-resources + + add-source + compile + + + + scala-test-compile + process-test-resources + + testCompile + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.9 + 1.9 + UTF-8 + + + + + +``` +jdk10 +```xml + + + + net.alchim31.maven + scala-maven-plugin + 3.2.2 + + + scala-compile-first + process-resources + + add-source + compile + + + + scala-test-compile + process-test-resources + + testCompile + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.10 + 1.10 + UTF-8 + + + + + +``` +以此类推.... + +如图所示添加这些标签 +![1-08](images/1-08.png) +如图中按钮所示(不要在意其中的项目) +![1-06](images/1-06.png) +之后我们找到其中的package,点击即可 +![1-07](images/1-07.png) +如图所示,出现"BUILD SUCCESS"我们就成功了 +![1-09](images/1-09.png) +一般的,目标jar包会产生在target文件夹中 +![1-10](images/1-10.png) + +2. 部署 + +之后把打包好的合法插件丢入plugins文件里就完美运行了,这里将不做图示 +这就是插件部署的过程。 + +3. 运行加载 + +如果出现了加载$(您的插件名字)成功之类的字样,说明您的插件成功了。 + +4. 之后进入游戏测试您的插件是否符合您的需求,根据您插件出现的各种问题 +进行再次调试,修改,打包等 + +[下一章](第二章-插件要素.md) + +参考文献 +- [[教程] [官方] 使用Maven配置Nukkit开发环境的方法(部分)](https://www.mcbbs.net/thread-706178-1-1.html) +- [Nukkit插件从0开始](https://www.cnblogs.com/xtypr/p/nukkit_plugin_start_from_0.html) +- [[教程] [转载] 如何开始制作 Nukkit 插件? Fromgate 的插件教程来了! [长文|多图] ](https://www.mcbbs.net/forum.php?mod=viewthread&tid=552265&page=1&authorid=100001) diff --git a/public/mengyanote/.trash/第一部分前言.md b/public/mengyanote/.trash/第一部分前言.md new file mode 100644 index 0000000..d92a475 --- /dev/null +++ b/public/mengyanote/.trash/第一部分前言.md @@ -0,0 +1,17 @@ +# 第一部分 基础准备 + +本部分将讲解nukkit插件的基础部分,学习完这一部分,你就可以独自实现一个 +自己的插件了,感谢您开始观看这个教程。 + +本部分分为八个章节 + + - [如何搭建开发环境](第一章-如何搭建环境.md) + - [插件要素](第二章-插件要素.md) + - [如何编写监听器](第三章-如何编写监听器.md) + - [如何编写指令](第四章-如何编写命令.md) + - [如何使用配置文件](第五章-如何使用配置文件.md) + - [如何编写plugin.yml](第六章-如何编写plugin.yml.md) + - [PluginBase类](第七章-PluginBase类.md) + - [练习案例](第八章-案例玩家进入信息等效果.md) + +每个章节都具有关联性,必须看完第一个才可以进行下一个,这样才能条理的学习 \ No newline at end of file diff --git a/public/mengyanote/.trash/第七章-PluginBase类.md b/public/mengyanote/.trash/第七章-PluginBase类.md new file mode 100644 index 0000000..a1c07a4 --- /dev/null +++ b/public/mengyanote/.trash/第七章-PluginBase类.md @@ -0,0 +1,376 @@ +[上一章](第六章-如何编写plugin.yml.md) [下一章](第八章-案例玩家进入信息等效果.md) +# 第一部分 第七章 PluginBase类 +参与编写者: MagicLu550 +#### 建议学习时间: 60分钟 +##### 学习要点: 了解PluginBase的方法 + +这里将会详细的介绍PluginBase类的常用方法。 + +PluginBase实现了Plugin接口,是插件运行的委托父类。它的子类被认定为服务端的运行类,它有 +三个运行方法,在[第一章](第一章-如何搭建环境.md)已经提到,它的很多方法都是开发过程最常用的, +也是一切api调用的入口和途径 + +PluginBase.java +```java +package cn.nukkit.plugin; + +import cn.nukkit.Server; +import cn.nukkit.command.Command; +import cn.nukkit.command.CommandSender; +import cn.nukkit.command.PluginIdentifiableCommand; +import cn.nukkit.utils.Config; +import cn.nukkit.utils.Utils; +import com.google.common.base.Preconditions; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedHashMap; + +/** + * 一般的Nukkit插件需要继承的类。
+ * A class to be extended by a normal Nukkit plugin. + * + * @author MagicDroidX(code) @ Nukkit Project + * @author 粉鞋大妈(javadoc) @ Nukkit Project + * @see cn.nukkit.plugin.PluginDescription + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ +abstract public class PluginBase implements Plugin { + + private PluginLoader loader; + + private Server server; + + private boolean isEnabled = false; + + private boolean initialized = false; + + private PluginDescription description; + + private File dataFolder; + private Config config; + private File configFile; + private File file; + private PluginLogger logger; + + + public void onLoad() { + + } + + public void onEnable() { + + } + + public void onDisable() { + + } + + public final boolean isEnabled() { + return isEnabled; + } + + /** + * 加载这个插件。
+ * Enables this plugin. + *

+ *

如果你需要卸载这个插件,建议使用{@link #setEnabled(boolean)}
+ * If you need to disable this plugin, it's recommended to use {@link #setEnabled(boolean)}

+ * + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public final void setEnabled() { + this.setEnabled(true); + } + + /** + * 加载或卸载这个插件。
+ * Enables or disables this plugin. + *

+ *

插件管理器插件常常使用这个方法。
+ * It's normally used by a plugin manager plugin to manage plugins.

+ * + * @param value {@code true}为加载,{@code false}为卸载。
{@code true} for enable, {@code false} for disable. + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public final void setEnabled(boolean value) { + if (isEnabled != value) { + isEnabled = value; + if (isEnabled) { + onEnable(); + } else { + onDisable(); + } + } + } + + public final boolean isDisabled() { + return !isEnabled; + } + + public final File getDataFolder() { + return dataFolder; + } + + public final PluginDescription getDescription() { + return description; + } + + /** + * 初始化这个插件。
+ * Initialize the plugin. + *

+ *

这个方法会在加载(load)之前被插件加载器调用,初始化关于插件的一些事项,不能被重写。
+ * Called by plugin loader before load, and initialize the plugin. Can't be overridden.

+ * + * @param loader 加载这个插件的插件加载器的{@code PluginLoader}对象。
+ * The plugin loader ,which loads this plugin, as a {@code PluginLoader} object. + * @param server 运行这个插件的服务器的{@code Server}对象。
+ * The server running this plugin, as a {@code Server} object. + * @param description 描述这个插件的{@code PluginDescription}对象。
+ * A {@code PluginDescription} object that describes this plugin. + * @param dataFolder 这个插件的数据的文件夹。
+ * The data folder of this plugin. + * @param file 这个插件的文件{@code File}对象。对于jar格式的插件,就是jar文件本身。
+ * The {@code File} object of this plugin itself. For jar-packed plugins, it is the jar file itself. + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public final void init(PluginLoader loader, Server server, PluginDescription description, File dataFolder, File file) { + if (!initialized) { + initialized = true; + this.loader = loader; + this.server = server; + this.description = description; + this.dataFolder = dataFolder; + this.file = file; + this.configFile = new File(this.dataFolder, "config.yml"); + this.logger = new PluginLogger(this); + } + } + + public PluginLogger getLogger() { + return logger; + } + + /** + * 返回这个插件是否已经初始化。
+ * Returns if this plugin is initialized. + * + * @return 这个插件是否已初始化。
if this plugin is initialized. + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public final boolean isInitialized() { + return initialized; + } + + /** + * TODO: FINISH JAVADOC + */ + public PluginIdentifiableCommand getCommand(String name) { + PluginIdentifiableCommand command = this.getServer().getPluginCommand(name); + if (command == null || !command.getPlugin().equals(this)) { + command = this.getServer().getPluginCommand(this.description.getName().toLowerCase() + ":" + name); + } + + if (command != null && command.getPlugin().equals(this)) { + return command; + } else { + return null; + } + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + return false; + } + + @Override + public InputStream getResource(String filename) { + return this.getClass().getClassLoader().getResourceAsStream(filename); + } + + @Override + public boolean saveResource(String filename) { + return saveResource(filename, false); + } + + @Override + public boolean saveResource(String filename, boolean replace) { + return saveResource(filename, filename, replace); + } + + @Override + public boolean saveResource(String filename, String outputName, boolean replace) { + Preconditions.checkArgument(filename != null && outputName != null, "Filename can not be null!"); + Preconditions.checkArgument(filename.trim().length() != 0 && outputName.trim().length() != 0, "Filename can not be empty!"); + + File out = new File(dataFolder, outputName); + if (!out.exists() || replace) { + try (InputStream resource = getResource(filename)) { + if (resource != null) { + File outFolder = out.getParentFile(); + if (!outFolder.exists()) { + outFolder.mkdirs(); + } + Utils.writeFile(out, resource); + + return true; + } + } catch (IOException e) { + Server.getInstance().getLogger().logException(e); + } + } + return false; + } + + @Override + public Config getConfig() { + if (this.config == null) { + this.reloadConfig(); + } + return this.config; + } + + @Override + public void saveConfig() { + if (!this.getConfig().save()) { + this.getLogger().critical("Could not save config to " + this.configFile.toString()); + } + } + + @Override + public void saveDefaultConfig() { + if (!this.configFile.exists()) { + this.saveResource("config.yml", false); + } + } + + @Override + public void reloadConfig() { + this.config = new Config(this.configFile); + InputStream configStream = this.getResource("config.yml"); + if (configStream != null) { + DumperOptions dumperOptions = new DumperOptions(); + dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yaml = new Yaml(dumperOptions); + try { + this.config.setDefault(yaml.loadAs(Utils.readFile(this.configFile), LinkedHashMap.class)); + } catch (IOException e) { + Server.getInstance().getLogger().logException(e); + } + } + } + + @Override + public Server getServer() { + return server; + } + + @Override + public String getName() { + return this.description.getName(); + } + + /** + * 返回这个插件完整的名字。
+ * Returns the full name of this plugin. + *

+ *

一个插件完整的名字由{@code 名字+" v"+版本号}组成。比如:
+ * A full name of a plugin is composed by {@code name+" v"+version}.for example:

+ *

{@code HelloWorld v1.0.0}

+ * + * @return 这个插件完整的名字。
The full name of this plugin. + * @see cn.nukkit.plugin.PluginDescription#getFullName + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public final String getFullName() { + return this.description.getFullName(); + } + + /** + * 返回这个插件的文件{@code File}对象。对于jar格式的插件,就是jar文件本身。
+ * Returns the {@code File} object of this plugin itself. For jar-packed plugins, it is the jar file itself. + * + * @return 这个插件的文件 {@code File}对象。
The {@code File} object of this plugin itself. + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + protected File getFile() { + return file; + } + + @Override + public PluginLoader getPluginLoader() { + return this.loader; + } +} + +``` +当然我们从这里面可以抓住几个要点: + +- 运行方法: onLoad(),onEnable(),onDisable() +- 获得方法: boolean isEnabled() + ,boolean isDisabled(), + File getDataFolder(), + PluginDescription getDescription(), + PluginLogger getLogger(), + boolean isInitialized(), + PluginIdentifiableCommand getCommand(String name), + Config getConfig(), + Server getServer(), + String getName(), + String getFullName(), + File getFile(), + PluginLoader getPluginLoader() +- 设置的方法: setEnabled(boolean enabled) +- 初始化的方法: init(PluginLoader loader, Server server, PluginDescription description, File dataFolder, File file) +- 命令方法: boolean onCommand(CommandSender sender, Command command, String label, String[] args) +- 产生配置文件方法: InputStream getResource(String filename), + boolean saveResource(String filename), + boolean saveResource(String filename, boolean replace), + boolean saveResource(String filename, String outputName, boolean replace), + void saveConfig(), + void saveDefaultConfig(), + void reloadConfig() + +这里介绍一下常用的方法 + +1. isEnabled和isDisabled分别是查看插件是否执行过onEnable方法和isDisable方法,插件状态为isEnabled时,方可进行注册监听器等操作 + +2. setEnabled()是强行执行onEnabled,调用它会执行一次onEnabled,无参数方法默认将isEnabled改为true + +3. getDataFolder() 获得插件的附属文件夹,文件路径为plugins/插件名称 + +4. getDescription() 得到插件plugin.yml的相关信息 + +5. getLogger() 得到日志对象,可以通过它进行日志输出的操作 + +6. isInitialized() 返回这个插件是否已经初始化 + +7. getCommand(String name) 获得插件的指定名称的指令对象 # 这个不太明确 + +8. getConfig() 获得默认的配置文件对象 + +9. getServer() 获得服务端对象 + +10.getName() 获得插件名称,在plugin.yml标记的 + +11.getFullName() 获得插件完整的名字,一个插件完整的名字由"名字+v+版本号"组成 + +12.getFile() 获得插件文件的对象 + +13.getPluginLoader() 获得插件加载器对象 + +14.init(...) 当插件开始被加载读取时,调用该方法初始化插件的基本内容 + +15.onCommand(...) 执行plugin.yml中定义的命令 + +16.getResource(...) 见[第五章](第五章-如何使用配置文件.md) + +17.saveConfig() saveDefaultConfig()保存默认配置文件 + +18.reloadConfig()重新加载配置文件,使得里面信息程序可以读取到 + +[上一章](第六章-如何编写plugin.yml.md) [下一章](第八章-案例玩家进入信息等效果.md) \ No newline at end of file diff --git a/public/mengyanote/.trash/第七章-如何发送数据包.md b/public/mengyanote/.trash/第七章-如何发送数据包.md new file mode 100644 index 0000000..8e5fa00 --- /dev/null +++ b/public/mengyanote/.trash/第七章-如何发送数据包.md @@ -0,0 +1,224 @@ +[上一章](第六章-各种工具类的介绍.md) [下一章]() +# 第二部分 第七章 如何发送数据包 +参与编写者: MagicLu550 +#### 建议学习时间: 40分钟 +##### 学习要点: 了解数据包和主要的发送形式 + +一. 概述 + +Nukkit实现客户端与服务端交互,是通过发送和接收数据包实现的.数据包在nukkit +的工作过程是占有很重的分量,包括玩家的移动等,都是由一个个数据包接连不断的实现这一 +功能.实现收发数据包的机制是RakNet,通过UDP实现的这些功能.RakNet实现的基础是 +Netty框架,如下文可以看到 + + +cn/nukkit/raknet/server/UDPServerSocket.java +``` +package cn.nukkit.raknet.server; + +import cn.nukkit.utils.ThreadedLogger; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelOption; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollDatagramChannel; +import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * author: MagicDroidX + * Nukkit Project + */ +public class UDPServerSocket extends ChannelInboundHandlerAdapter { + +``` + +RakNetServer.java +``` +@Override + public void run() { + this.setName("RakNet Thread #" + Thread.currentThread().getId()); + Runtime.getRuntime().addShutdownHook(new ShutdownHandler()); + UDPServerSocket socket = new UDPServerSocket(this.getLogger(), port, this.interfaz); + try { + new SessionManager(this, socket); + } catch (Exception e) { + Server.getInstance().getLogger().logException(e); + } + } +``` + +二. Netty框架 + +[Netty框架](https://github.com/netty/netty)是使用最广泛的java-nio框架之一,由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具, +用以快速开发高性能、高可靠1性的网络服务器和客户端程序。Netty相当于简化和流线化了网络应用的编程开发过程. + +如果你想要更深入研究这个框架可以参见[Netty框架的github](https://github.com/netty/netty) + +三. Nukkit的发包机制 + +1. Nukkit 数据包的结构 + +Nukkit的数据包类的继承结构是 +``` +BinaryStream +|------- DataPacket + |-------- 我们主要操作的数据包 +``` + +pid() 一般为数据包的NETWORK_ID,在Player,Server,RakNetInterface,DataPacket类中被调用过 + +DataPacket的主要方法是decode()和encode(),数据包的传输过程中,通过这两个方法实现解码和 +编码,使得数据包在服务端与客户端间相互识别. + +decode() 是解码方法,一般是客户端发来的数据包,解码到对象的具体属性,之后在服务端中使用这些数据, + +即 客户端 -> 服务端 + +如代码中这样 + +CameraPacket.java +``` +package cn.nukkit.network.protocol; + +import lombok.ToString; + +@ToString +public class CameraPacket extends DataPacket { + + public long cameraUniqueId; + public long playerUniqueId; + + @Override + public byte pid() { + return ProtocolInfo.CAMERA_PACKET; + } + + @Override + public void decode() { + this.cameraUniqueId = this.getVarLong(); + this.playerUniqueId = this.getVarLong(); + } + +``` + +encode() 是编码方法,会在发包时被调用,将在服务端设置的数据值写入发出到客户端 + +即 服务端 -> 客户端 + +如代码这样 + +CameraPacket.java +``` +@Override + public void encode() { + this.reset(); + this.putEntityUniqueId(this.cameraUniqueId); + this.putEntityUniqueId(this.playerUniqueId); + } +``` + +从这里,我们就可以引入接下来的发包环节,事实上,它很简单 + +2. 事件 + +发送数据包和接收数据包的时候会触发几种事件,我们可以通过这几种事件进行 +抓包 +我们比较常用的是这几种 + - BatchPacketsEvent: 批处理数据包事件 + - DataPacketReceiveEvent: 数据包接收事件 + - DataPacketSendEvent: 数据包发送事件 +这里我们主要介绍Receive和Send + +DataPacketSendEvent主要触发在服务端向客户端发送数据包的时候 + +Player.java +``` +public int dataPacket(DataPacket packet, boolean needACK) { + if (!this.connected) { + return -1; + } + + try (Timing timing = Timings.getSendDataPacketTiming(packet)) { + //There!!!!! + DataPacketSendEvent ev = new DataPacketSendEvent(this, packet); + this.server.getPluginManager().callEvent(ev); + if (ev.isCancelled()) { + return -1; + } +``` + +DataPacketReceiveEvent主要触发在客户端向服务端发送数据包并且服务端接收到的时候. + +Player.java + +``` +public void handleDataPacket(DataPacket packet) { + if (!connected) { + return; + } + + try (Timing timing = Timings.getReceiveDataPacketTiming(packet)) { + //There!!!!!!!!! + DataPacketReceiveEvent ev = new DataPacketReceiveEvent(this, packet); + this.server.getPluginManager().callEvent(ev); + if (ev.isCancelled()) { + return; + } + +``` +3. 发包 + +Nukkit提供了友好的数据包机制,我们可以通过需求定义,发送数据包 + +Nukkit提供了发送数据包的方法,并允许开发者直接发送数据包和监听数据包的收发 +一般的,发送数据包的方式都是使用玩家对象的dataPacket实现 +`player.dataPacket(DataPacket)`,这是一个最常用的方式。 + +当然,先前的Server类也提到了批量发包的方法(Server类) + + * batchPackets​(Player[], DataPacket[]) 批量发送数据包 + * broadcastPacket​(Player[], DataPacket) 向所有玩家广播数据包 + +这三个方法就是发包所常使用的方法了。 + +这里我们用dataPacket方法做案例 + +这里用MovePlayerPacket做一个样例 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; +import cn.nukkit.network.protocol.MovePlayerPacket; + +public class TestListener implements Listener { + + @EventHandler + public void onPlayer(PlayerJoinEvent e){ + //1. 定义数据包对象 + MovePlayerPacket packet = new MovePlayerPacket(); + //2. 设置数据包数值,这里我随便写了几个值 + packet.x = 0; + packet.y = 100; + packet.z = 1000; + //3.发出 + e.getPlayer().dataPacket(packet); + } +} +``` + +四. 常用数据包的解释 + +[上一章](第六章-各种工具类的介绍.md) [下一章]() diff --git a/public/mengyanote/.trash/第三章-如何编写监听器.md b/public/mengyanote/.trash/第三章-如何编写监听器.md new file mode 100644 index 0000000..8296cd9 --- /dev/null +++ b/public/mengyanote/.trash/第三章-如何编写监听器.md @@ -0,0 +1,249 @@ +[上一章](第二章-插件要素.md) [下一章](第四章-如何编写命令.md) +# 第一部分 第三章 如何编写监听器 +参与编写者: MagicLu550,innc11 +#### 建议学习时间: 30分钟 +##### 学习要点: 学习如何构建一个简单的监听器,和自己构造事件 + +其实看一看这章,没有啥可讲的。监听器的内容很简单,很多人认识它的困难主要是概念上, +而不是使用上。 + +注册监听器有两个步骤: 1.定义监听器 2.注册监听器 + +nukkit监听器的构成: 事件监听和优先级 + +nukkit的监听器是通过 **反射(reflect)** 实现的,因此基于它,开发者容易上手,且上手 +更简便。nukkit的监听器设计形同bukkit,也易于bukkit上手 + +nukkit声明一个事件的监听管理器是通过注解实现的,即@EventHandler + +@EventHandler的源码如图 +```java +package cn.nukkit.event; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 定义一个事件的处理器的注解。
+ * Annotation that defines a handler. + * + *

一个处理器的重要程度被称作处理器的优先级,优先级高的处理器有更多的决定权。参见:{@link #priority()}
+ * The importance of a handler is called its priority, handlers with higher priority speaks louder then + * lower ones. See: {@link #priority()}

+ * + *

处理器可以选择忽略或不忽略被取消的事件,这种特性可以在{@link #ignoreCancelled()}中定义。
+ * A handler can choose to ignore a cancelled event or not, that can be defined in {@link #ignoreCancelled()}.

+ * + * @author MagicDroidX(code) @ Nukkit Project + * @author 粉鞋大妈(javadoc) @ Nukkit Project + * @see cn.nukkit.event.Listener + * @see cn.nukkit.event.Event + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface EventHandler { + /** + * 定义这个处理器的优先级。
+ * Define the priority of the handler. + * + *

Nukkit调用处理器时会按照优先级从低到高的顺序调用,这样保证了高优先级的监听器能覆盖低优先级监听器做出的处理。 + * 调用的先后顺序如下:

+ * When Nukkit calls all handlers, ones with lower priority is called earlier, + * that make handlers with higher priority can replace the decisions made by lower ones. + * The order that Nukkit call handlers is from the first to the last as: + *
    + *
  1. EventPriority.LOWEST + *
  2. EventPriority.LOW + *
  3. EventPriority.NORMAL + *
  4. EventPriority.HIGH + *
  5. EventPriority.HIGHEST + *
  6. EventPriority.MONITOR + *
+ * + * @return 这个处理器的优先级。
The priority of this handler. + * @see cn.nukkit.event.EventHandler + */ + EventPriority priority() default EventPriority.NORMAL; + + /** + * 定义这个处理器是否忽略被取消的事件。
+ * Define if the handler ignores a cancelled event. + * + *

如果为{@code true}而且事件发生,这个处理器不会被调用,反之相反。
+ * If ignoreCancelled is {@code true} and the event is cancelled, the method is + * not called. Otherwise, the method is always called.

+ * + * @return 这个处理器是否忽略被取消的事件。
Whether cancelled events should be ignored. + * @see cn.nukkit.event.EventHandler + */ + boolean ignoreCancelled() default false; +} + +``` +第一个是优先级,第二个是是否忽略事件被取消 + +默认的优先级是normal,从注释可以知道,这是他们的先后顺序,LOWEST会最先被调用,其次是LOW,最后是MONITOR,如果在LOWEST监听器中调用了Event.setCancelled(true),Nukkit则会忽略掉后面的 ignoreCancelled 被设置为true或者保持默认的优先级更高的监听器 + +- EventPriority.LOWEST + +- EventPriority.LOW + +- EventPriority.NORMAL + +- EventPriority.HIGH + +- EventPriority.HIGHEST + +- EventPriority.MONITOR + +而实现监听器的优先级标记是通过 **枚举(Enum)** 实现的 + +优先级的目的是为了保证监听器按照顺序执行,以使得一个监听器操作完会 +进入下一个监听器继续执行,以确保执行的有序性。下一个监听器的相同操作 +会覆盖之前监听器的相同操作。 + +同时,事件可以被我手动取消的,但是有时候事件虽然取消,但依然需要操作, +那么ignoreCancelled可以发挥作用了,当然默认是忽略掉取消的事件,也就是 +说取消的事件默认不会被监听(这里可能有所错误,我这个不太常用) + +一个EventHandler基本都是监听一个事件的(我只尝试过一个事件的),代码中 +这样使用 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; + +public class OtherListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent e){ + //执行代码 + } +} + +``` +这里的意思就是当玩家进入服务器时,就会触发PlayerJoinEvent事件,服务器会 +形成一个PlayerJoinEvent对象,并且调用先前注册的有关PlayerJoinEvent的 +EventHandler,将对象传入,这样就实现了一个 **事件的调用** +获取对象的内容,则通过e调用即可,我们不需要很明白它的具体细节,只需要知道, +使用EventHandler注解的方法(且有一个Event的子类类型参数,并且它所在的监听器被注册), +就会在事件发生时,相应的被调用,如上文所讲,这里的代码案例就是当发生玩家加入时, +这个onPlayerJoin方法会被服务端调用。 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; + +public class OtherListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent e){ + e.getPlayer().sendMessage("你好 "+e.getPlayer()); + } +} +``` +例如这个代码,在玩家加入时,将会向玩家发送一个"你好 玩家的名字",这就是 +我们监听器的作用 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.EventPriority; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; + +public class OtherListener implements Listener { + + @EventHandler(priority = EventPriority.HIGH,ignoreCancelled = true) + public void onPlayerJoin(PlayerJoinEvent e){ + e.getPlayer().sendMessage("你好 "+e.getPlayer()); + } +} +``` +如果要使用我们之前所说的参数,则这样使用。 + +事实上,监听器的基本使用方式也就这些,nukkit也提供了很多事件给予我们使用,也允许我们 +自己制作事件自己使用,在第二部分中,我们将会讲解提供了哪些事件 + +如何自己定义一个事件 + +事实上,nukkit的事件是通过callEvent调用的,所以,我们同样可以通过callEvent实现我们自己 +的事件。 +``` + this.getServer().getPluginManager().callEvent(Event e); +``` +首先我们先定义一个事件类 +```java +package net.noyark.www; + +import cn.nukkit.event.Event; + +public class MyEvent extends Event { +} + +``` +之后,我们在监听器使用我们的事件 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; + + +public class OtherListener implements Listener { + + @EventHandler + public void onMy(MyEvent e){ + + } +} +``` +之后[注册监听器](第二章-插件要素.md),我们就可以使用我们的事件了。 +``` + this.getServer().getPluginManager().registerEvents(new OtherListener(),this); +``` +如何触发我们的事件? +事件的触发则通过callEvent触发,假如,我们写一个玩家假如时,如果他的 +名字叫abc,就触发MyEvent事件 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; + + +public class OtherListener implements Listener { + + @EventHandler + public void onMy(MyEvent e){ + + } + + @EventHandler + public void onPLayerJoin(PlayerJoinEvent e){ + if("abc".equals(e.getPlayer().getName())){ + Example.getPlugin().getServer() + .getPluginManager() + .callEvent(new MyEvent()); + } + } +} + +``` +这里,我们完成了我们的自定义事件 + +假如我们要注册一个EventHandler,不去注册其他的该如何。 +事实上,可以实现这个,nukkit提供了registerEvent方法, +可以注册单个EventHandler,但不太常用,我这里也不会再过多 +阐述了,如果想了解,可以发issue,我将会添加这方面的内容 + +[上一章](第二章-插件要素.md) [下一章](第四章-如何编写命令.md) diff --git a/public/mengyanote/.trash/第三章-计时器的介绍.md b/public/mengyanote/.trash/第三章-计时器的介绍.md new file mode 100644 index 0000000..f10a068 --- /dev/null +++ b/public/mengyanote/.trash/第三章-计时器的介绍.md @@ -0,0 +1,343 @@ +[上一章](第二章-事件相关方法.md) [下一章](第四章-Server类和PluginManager类.md) +# 第二部分 第三章 计时器的介绍 +参与编写者:`zzz1999` +#### 建议学习时间:3分钟 +##### 学习要点:了解计时器的功能以及如何使用 + +一.概念 +1.计时器的作用是 __立即,延时,循环或延时循环__ 某些任务,通过计时器我们可以实现例如 *在线奖励* , *倒计时* 等插件功能, 是一些复杂插件中经常用到的功能之一. + +2.执行计时器代码块的单元叫做任务,我们可以编写任务代码来使用计时器的功能. + +3.任务执行分为两种类型,一种是同步,一种是异步.同步通过主线程所调度管理执行,异步通过主线程调度管理,异步线程池执行.所以,太多的任务会导致服务器卡顿. + +4.计时器的功能以`minecraft刻`(tick)作为单位,一刻为现实时间的0.05秒,现实时间的1秒为20刻,服务器每秒刻数由TPS决定,最高为20. + + +二.代码 + +我们先来看一下nukkit的[Task](https://github.com/NukkitX/Nukkit/blob/master/src/main/java/cn/nukkit/scheduler/Task.java)类. + +```java +package cn.nukkit.scheduler; + +import cn.nukkit.Server; + +/** + * 表达一个任务的类。
A class that describes a task. + * + *

一个任务可以被Nukkit服务器立即,延时,循环或延时循环执行。参见:{@link ServerScheduler}
+ * A task can be executed by Nukkit server with a/an express, delay, repeat or delay&repeat. + * See:{@link ServerScheduler}

+ * + *

对于插件开发者,为确保自己任务能够在安全的情况下执行(比如:在插件被禁用时不执行), + * 建议让任务继承{@link PluginTask}类而不是这个类。
+ * For plugin developers: To make sure your task will only be executed in the case of safety + * (such as: prevent this task from running if its owner plugin is disabled), + * it's suggested to use {@link PluginTask} instead of extend this class.

+ * + * @author MagicDroidX(code) @ Nukkit Project + * @author 粉鞋大妈(javadoc) @ Nukkit Project + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ +public abstract class Task implements Runnable { + private TaskHandler taskHandler = null; + + public final TaskHandler getHandler() { + return this.taskHandler; + } + + public final int getTaskId() { + return this.taskHandler != null ? this.taskHandler.getTaskId() : -1; + } + + public final void setHandler(TaskHandler taskHandler) { + if (this.taskHandler == null || taskHandler == null) { + this.taskHandler = taskHandler; + } + } + + /** + * 这个任务被执行时,会调用的过程。
+ * What will be called when the task is executed. + * + * @param currentTick 服务器从开始运行到现在所经过的tick数,20ticks = 1秒,1tick = 0.05秒。
+ * The elapsed tick count from the server is started. 20ticks = 1second, 1tick = 0.05second. + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public abstract void onRun(int currentTick); + + @Override + public final void run() { + this.onRun(taskHandler.getLastRunTick()); + } + + public void onCancel() { + + } + + public void cancel() { + try { + this.getHandler().cancel(); + } catch (RuntimeException ex) { + Server.getInstance().getLogger().critical("Exception while invoking onCancel", ex); + } + } + +} +``` + +我们可以捕捉到几个关键信息,首先我们可以看到`onRun(int)`方法,它是一个抽象方法并且nk开发者很贴心的写上了注释示意我们这是Task中会被运行到代码块. + +还有`onCancel()`和`cancel()`方法,onCancel()内部是一个空代码块,当Task被取消的时候(被任务调度器取消或者手动调用cancel()取消都会触发),这段代码块会被调用 + +比较常见的用途比如小游戏时间到的时候,一些判定胜负,给予奖励,关闭房间的一些代码可以用Task来实现或者调用. + +我们还可以使用`cancel()`方法来强制取消一个Task,例如你想要写一个登录插件,每个玩家进入服务器时创建一个Task循环发送提示登录的信息,如果玩家输入了正确的密码并且登录成功才会取消掉这个Task.这时候就可以使用cancel方法了(仅举例,实际生产环境中,每个玩家进入创一个计时器是很费资源的,不会使用这种方法) + +Handler是服务器调度Task所用到的一些东西,可以不懂,不妨碍计时器的使用. + +开发者可以使用`PluginBase#getServer()`方法获取到Server对象,然后使用`Server#getSchedule()`获取到计时器的实例类. +```java +public class Main extends PluginBase{ + @Override + public void onEnable(){ + ServerScheduler scheduler = this.getServer().getScheduler(); + } +} +``` +获取到后,可以创建 __立即,延时,循环或延时循环__ 类型的计时器 +立即(ServerSchedule#scheduleTask) +延时(ServerSchedule#scheduleDelayedTask) +循环(ServerSchedule#scheduleRepeatingTask) +延时循环(ServerSchedule#scheduleDelayedRepeatingTask) + +计时器是需要一个被触发的时间间隔的,以tick为单位,如果是循环计时器,则是每次循环的时间,如果是延时,则是延迟多少tick才被触发,如果是延迟循环,则会要求填写延迟间隔与循环间隔. + +举例将会在下一小节讲到 + +3.使用 + +下面会使用到`PluginTask`类,你需要对`PluginTask`类的方法做一个初步的了解,以及知道它继承了Task类. +```java +package cn.nukkit.scheduler; + + +import cn.nukkit.plugin.Plugin; + +/** + * 插件创建的任务。
Task that created by a plugin. + * + *

对于插件作者,通过继承这个类创建的任务,可以在插件被禁用时不被执行。
+ * For plugin developers: Tasks that extend this class, won't be executed when the plugin is disabled.

+ * + *

另外,继承这个类的任务可以通过{@link #getOwner()}来获得这个任务所属的插件。
+ * Otherwise, tasks that extend this class can use {@link #getOwner()} to get its owner.

+ * + * 下面是一个插件创建任务的例子:
An example for plugin create a task: + *
+ *     public class ExampleTask extends PluginTask<ExamplePlugin>{
+ *         public ExampleTask(ExamplePlugin plugin){
+ *             super(plugin);
+ *         }
+ *
+ *        {@code @Override}
+ *         public void onRun(int currentTick){
+ *             getOwner().getLogger().info("Task is executed in tick "+currentTick);
+ *         }
+ *     }
+ * 
+ * + *

如果要让Nukkit能够延时或循环执行这个任务,请使用{@link ServerScheduler}。
+ * If you want Nukkit to execute this task with delay or repeat, use {@link ServerScheduler}.

+ * + * @param 这个任务所属的插件。
The plugin that owns this task. + * @author MagicDroidX(code) @ Nukkit Project + * @author 粉鞋大妈(javadoc) @ Nukkit Project + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ +public abstract class PluginTask extends Task { + + protected final T owner; + + /** + * 构造一个插件拥有的任务的方法。
Constructs a plugin-owned task. + * + * @param owner 这个任务的所有者插件。
The plugin object that owns this task. + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public PluginTask(T owner) { + this.owner = owner; + } + + /** + * 返回这个任务的所有者插件。
+ * Returns the owner of this task. + * + * @return 这个任务的所有者插件。
The plugin that owns this task. + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + public final T getOwner() { + return this.owner; + } + +} +``` + +我们可以通过创建一个继承PluginTask的类来创建一个PluginTask(为什么不直接继承Task类?,因为这个类添加了`getOwner()`方法,可以通过构造方法传入一份主类或任意你需要类实例的引用,方便编写代码) + +```java + +package net.noyark.NukkitLearn; + +import cn.nukkit.scheduler.PluginTask; + +public class NukkitLearnExampleTask extends PluginTask
{ + public NukkitLearnExampleTask(Main owner) { + super(owner); + } + + @Override + public void onRun(int i) { + + } +} + + +``` + +上面代码是一个简单Task类的样例,我们现在带入一个插件情境进一步说明计时器的用法. +> 小明是一个服主,他非常喜欢玩家来他的服务器玩并且希望玩家每玩45分钟能够停下来休息一下保护视力.于是他想要开发一个插件,当玩家单次进入服务器并且呆了45分钟后,能够发送一条信息提示(Player#sendMessage(String)玩家休息一会) + +于是我们来头脑风暴一下,我们知道计时器有4种类型,不知道你还能不能想得起来 + + + + ##### 立即(ServerSchedule#scheduleTask) + ##### 延时(ServerSchedule#scheduleDelayedTask) + ##### 循环(ServerSchedule#scheduleRepeatingTask) + ##### 延时循环(ServerSchedule#scheduleDelayedRepeatingTask) + +> 小明火速写好了一个Task类 + +```java +package net.noyark.NukkitLearn; + +import cn.nukkit.Player; +import cn.nukkit.scheduler.PluginTask; + +public class PresentationRestTask extends PluginTask
{ + + private Player player; + + public PresentationRestTask(Main owner, Player player) { + super(owner); + this.player = player; + } + + @Override + public void onRun(int i) { + player.sendMessage("你已经玩了45分钟了,快下线休息一下眼睛吧!"); + } +} + +``` + +> 以及一个主类 + +```java + +package net.noyark.NukkitLearn; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.EventPriority; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; +import cn.nukkit.plugin.PluginBase; + +public class Main extends PluginBase implements Listener { + + @EventHandler(priority = EventPriority.LOW,ignoreCancelled = true) + public void onJoin(PlayerJoinEvent event){ + + } + +} + +``` + +### 思考过程 + * 使用立刻类型的计时器 + - 使用立刻类型的计时器,在主类onJoin方法中填写入代码 + > this.getServer().getScheduler().scheduleTask(new PresentationRestTask(this,event.getPlayer())); + > 小明找了个玩家小红进入服务器,小红刚进入服务器,左上角就被发了消息:"你已经玩了45分钟了,快下线休息一下眼睛吧!". + * 使用延迟类型的计时器 + - 使用延时类型的计时器,在主类onJoin方法中填写入代码 + > this.getServer().getScheduler().scheduleDelayedTask(new PresentationRestTask(this,event.getPlayer()),54000); + > 小明找了个玩家小红进入服务器,小红刚进入服务器45分钟后,左上角才被发了消息:"你已经玩了45分钟了,快下线休息一下眼睛吧!". + * 使用循环类型的计时器 + - 似乎这很不符合我们的常理,并且增加了很多不必要的开销 + - 修改Task,加入时间作为判断依据 + > + ```java + package net.noyark.NukkitLearn; + + import cn.nukkit.Player; + import cn.nukkit.scheduler.PluginTask; + + public class PresentationRestTask extends PluginTask
{ + + private Player player; + private long stp; + + public PresentationRestTask(Main owner, Player player,long stp) { + super(owner); + this.player = player; + this.stp = stp; + } + + @Override + public void onRun(int i) { + if (System.currentTimeMillis() >= stp) { + player.sendMessage("你已经玩了45分钟了,快下线休息一下眼睛吧!"); + this.cancel(); + } + } + } + + ``` + - 使用循环类型的计时器,在主类onJoin方法中填写入代码 + > this.getServer().getScheduler().scheduleRepeatingTask(new PresentationRestTask(this,event.getPlayer(),System.currentTimeMillis() + (45 * 60 * 1000)),60*20); + > 可以达成效果,但是实在是`太麻烦` + - 使用延时循环类型的计时器,在主类onJoin方法中填写入代码 + > this.getServer().getScheduler().scheduleDelayedRepeatingTask(new PresentationRestTask(this,event.getPlayer()),45 * 60 * 20,0); + > 同时计时器也需要修改,否则就会45分钟一到就会无尽发送消息 + > + ```java + package net.noyark.NukkitLearn; + + import cn.nukkit.Player; + import cn.nukkit.scheduler.PluginTask; + + public class PresentationRestTask extends PluginTask
{ + + private Player player; + + public PresentationRestTask(Main owner, Player player) { + super(owner); + this.player = player; + } + + @Override + public void onRun(int i) { + player.sendMessage("你已经玩了45分钟了,快下线休息一下眼睛吧!"); + this.cancel(); + } + } + + ``` +> 最终从各种角度来看,小明更应该使用`第二种`方法 + + + +[上一章](第二章-事件相关方法.md) [下一章](第四章-Server类和PluginManager类.md) diff --git a/public/mengyanote/.trash/第二章-事件相关方法.md b/public/mengyanote/.trash/第二章-事件相关方法.md new file mode 100644 index 0000000..3132cd6 --- /dev/null +++ b/public/mengyanote/.trash/第二章-事件相关方法.md @@ -0,0 +1,3 @@ +[上一章](第一章-主要的事件介绍.md) [下一章](第三章-计时器的介绍.md) + +[上一章](第一章-主要的事件介绍.md) [下一章](第三章-计时器的介绍.md) \ No newline at end of file diff --git a/public/mengyanote/.trash/第二章-插件要素.md b/public/mengyanote/.trash/第二章-插件要素.md new file mode 100644 index 0000000..618c029 --- /dev/null +++ b/public/mengyanote/.trash/第二章-插件要素.md @@ -0,0 +1,224 @@ +[上一章](第一章-如何搭建环境.md) [下一章](第三章-如何编写监听器.md) + +# 第一部分 第二章 插件要素 +参与编写者: MagicLu550 +#### 建议学习时间: 50分钟 +##### 学习要点: 了解nukkit的项目结构,认识一些普通组件的定义和注册 + +插件要素这章会概括性的介绍nukkit的一些主要组件,后面的章节将会对他们系统的介绍。 + +所有的插件式编程都有它的一套运行标准,如maven插件,PocketMine插件,以及我们的nukkit插件等。 + +我称插件的规则元素为一个**插件的要素**,主要是运行的主类所依托的父类或一个动作所依托的父类(PluginBase等),它 +用于对服务器阅读的参数表(如web.xml,plugin.yml等),以及执行一系列动作的附件(如监听器,Servlet,过滤器,命令等) + +nukkit的插件以**PluginBase**的代表,以plugin.yml为运行依据,以监听器等附件为动作,这些动作基于在PluginBase里 +注册,所以nukkit的结构主要为这些 +``` + 1. plugin.yml [必须有] + 2. 继承于PluginBase的主类 [必须有] + 3. Listener(监听器),Command(命令),Timer(计时器) + +``` +nukkit允许主类和监听器重叠,当我们制作简单的插件,为避免复杂,可以一个类担当主类和监听器的角色 +并且我们也可以使用简单的方式来执行我们的命令。复杂项目中,我们不建议这么做 + +1. 注册一个监听器 +```java +package net.noyark.www; + +import cn.nukkit.event.Listener; +import cn.nukkit.plugin.PluginBase; + +/** + * 实现一个Listener代表了一个监听器,注册时,监听器才真正生效 + * 另外,Listener是一个接口,我们需要实现(implements)它 + */ +public class Example extends PluginBase implements Listener { + + @Override + public void onEnable() { + //插件的管理由PluginManager实现,后期会讲解这个组件 + //listener为一个监听器对象,这里我们将服务器事先生成的主类对象传入 + //若要调用服务器生成的PluginBase对象,我们必须要传入this而不是再new一个 + //当然,注册监听器时您可以再new一个,但是不建议这么做 + //第二个plugin对象是主类对象,这个必须要传入this的 + //可能有人疑惑,那在其他类里该怎么调用之前生成的对象呢?这个疑惑将会在接下来代码实现 + this.getServer().getPluginManager().registerEvents(this,this); + } +} + +``` + +如果跨类如何做这件事? +我们这里定义了一个Example类和一个OtherListener类。 +OtherListener实现了Listener接口。 +如图所示实现了跨类的注册 +![2-01](images/2-01.png) +那么如何实现在监听器使用实现注册好的主类对象? +下面代码解决了这个问题,要注意,plugin = this这段代码 +要定义在监听器对象被定义之前,这样定义一个getPlugin方法就可以在监听器获取到了 + +```java +package net.noyark.www; + + +import cn.nukkit.plugin.PluginBase; + +public class Example extends PluginBase{ + + private static Example plugin; + @Override + public void onEnable() { + plugin = this; + this.getServer().getPluginManager().registerEvents(new OtherListener(),this); + } + + public static Example getPlugin() { + return plugin; + } +} +``` +在监听器中调用 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; + +public class OtherListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent e){ + Example.getPlugin().getServer(); + } +} +``` +[监听器具体内容](第三章-如何编写监听器.md)将在后面讲解 + +2. 注册一个[命令](第四章-如何编写命令.md) +其实注册个命令就很简单,如何跨类等等和上面基本一样,但是主类是不能注册一个命令对象的 +(因为命令是继承Command对象) +但是也有简便的方法 + +第一种: +[1] +```java +package net.noyark.www; + + +import cn.nukkit.command.Command; +import cn.nukkit.command.CommandSender; +import cn.nukkit.plugin.PluginBase; + +public class Example extends PluginBase{ + + private static Example plugin; + @Override + public void onEnable() { + plugin = this; + this.getServer().getPluginManager().registerEvents(new OtherListener(),this); + } + + public static Example getPlugin() { + return plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + //这里返回true代表执行成功,false则不成功 + //sender 是发送命令的对象 + //command 命令对象 + // [1] + //label 是标签,如果注册命令时label为null,就会默认为命令名,label的组成是fallBackPrefix+:+label + //label这个地方其实也不是很懂。一般注册时都是""或者null + //通过源码推测label和fallBackPrefix的组合是命令的唯一标识 + // + //args 命令参数,比如/hello 1 2的参数为1和2,存储在数组中 + //这里使用命令通过equals + //如何得到指令名称个人习惯原因 + if("hello".equals(command.getName())){ + //执行相关操作 + return true;//最好加上 + } + //这种方式虽然方便,但是命令多,且命令功能复杂时会难以维护 + //少部分命令可以使用它 + return true; + } +} +``` +当然第一种方式,命令要真正被监听,我们还要在plugin.yml里声明 +```yaml +permissions: #这个标签我们只写一次就ok了 + plugin.hello: + description: 你好 + default: op #权限组,后期会讲到 +commands: #这个标签我们只写一次就ok了 + hello: + description: 你好 + usage: "/hello" + permission: plugin.hello +``` +第二种是创建命令类 +这个其实不用多说,和前面一样使用 +```java +package net.noyark.www; + +import cn.nukkit.command.Command; +import cn.nukkit.command.CommandSender; + +public class MyCommand extends Command { + + //hello为指令名字,后面description是它的介绍,其他功能将后期讲解 + public MyCommand() { + super("hello","一个测试指令"); + } + + @Override + public boolean execute(CommandSender commandSender, String label, String[] strings) { + return true; + } +} +``` +注册很简单,第一个参数后面会讲解 +```java +package net.noyark.www; + +import cn.nukkit.plugin.PluginBase; + +public class Example extends PluginBase{ + + @Override + public void onEnable() { + this.getServer().getCommandMap().register("",new MyCommand()); + } + +} +``` + +3.[计时器部分](第三章-计时器的介绍.md)我们将在后面讲解,它的体系较复杂一些 + +计时器主要形同java的Runnable,线程池等等,他们本质也是实现多线程。 +也是开发者使用最广泛的一类组件。 + +4. 如何写plugin.yml + plugin.yml第一章提到过,plugin.yml最主要的是 + + ```yaml + name: FirstPlugin + main: net.noyark.www.Example + version: "0.0.1" + author: myName + api: ["1.0.8"] + description: My first plugin + ``` +snake1999曾说: 缺少他们的插件是不被nukkit运行的。 +这些都是不能缺少的,在接下来章节中,将会系统的介绍里面常用的标签 +目前从现在的维护者知悉,api写什么其实并不重要,因为nukkit向下兼容,不像 +pocketMine一样变动很大,nukkit会淘汰掉过时的函数,不会删除,因此 +可以保证老插件运行,但值得注意的是,不代表淘汰函数会完美运行,能 +运行插件不代表不会出现bug,但这也是相对pocketMine最方便的优势了。 + + +[上一章](第一章-如何搭建环境.md) [下一章](第三章-如何编写监听器.md) \ No newline at end of file diff --git a/public/mengyanote/.trash/第二部分前言.md b/public/mengyanote/.trash/第二部分前言.md new file mode 100644 index 0000000..1d119f5 --- /dev/null +++ b/public/mengyanote/.trash/第二部分前言.md @@ -0,0 +1,15 @@ +# 第二部分 高级应用 + +本部分将讲解nukkit插件的高级应用部分,学习完这一部分,你就可以独自实现一个 +自己的复杂的插件了,感谢您开始观看这个教程。 + +本部分分为七个章节 + + - [主要的事件的介绍](第一章-主要的事件介绍.md) + - [事件相关方法](第二章-事件相关方法.md) + - [计时器的介绍](第三章-计时器的介绍.md) + - [Server类和PluginManager类](第四章-Server类和PluginManager类.md) + - [各种实体类的方法介绍](第五章-各种实体类的方法介绍.md) + - [各种工具类的介绍](第六章-各种工具类的介绍.md) + - [如何发送数据包](第七章-如何发送数据包.md) +每个章节都具有关联性,必须看完第一个才可以进行下一个,这样才能条理的学习 \ No newline at end of file diff --git a/public/mengyanote/.trash/第五章-各种实体类的方法介绍.md b/public/mengyanote/.trash/第五章-各种实体类的方法介绍.md new file mode 100644 index 0000000..7956835 --- /dev/null +++ b/public/mengyanote/.trash/第五章-各种实体类的方法介绍.md @@ -0,0 +1,3 @@ +[上一章](第四章-Server类和PluginManager类.md) [下一章](第六章-各种工具类的介绍.md) + +[上一章](第四章-Server类和PluginManager类.md) [下一章](第六章-各种工具类的介绍.md) \ No newline at end of file diff --git a/public/mengyanote/.trash/第五章-如何使用配置文件.md b/public/mengyanote/.trash/第五章-如何使用配置文件.md new file mode 100644 index 0000000..1304e9c --- /dev/null +++ b/public/mengyanote/.trash/第五章-如何使用配置文件.md @@ -0,0 +1,223 @@ +[上一章](第四章-如何编写命令.md) [下一章](第六章-如何编写plugin.yml.md) +# 第一部分 第五章 如何编写配置文件 +参与编写者: MagicLu550 +#### 建议学习时间: 40分钟 +##### 学习要点: 了解如何创建配置文件,了解使用SimpleConfig + +配置文件用于存储插件的配置信息,供用户自定义和修改,以及存储一些永久数据,我们称 +配置文件属于 **持久层**。 + +nukkit提供了多种配置文件格式,如yaml,json,properties等,其中最常用的是yaml, +我们主要讲解这个配置文件格式,其他如果想要了解,可以发送issues,我们可以补充。 + +一. 关于yaml + +nukkit的yaml框架基于[snakeYaml](https://github.com/bmoliveira/snake-yaml)实现的, +snakeYaml是一款使用广泛的yaml解析库,我们可以从它的[官网](https://yaml.org/type/index.html)了解 +他们的语法,在nukkit开发中,我们更多使用key: value的映射形式 + +这是一个yaml的文件案例 +```yaml +server: + name: 12 + player: + - nihao + - xiaoming + - xiaogang + time: + year: 2019 +``` +yaml的标准语法是使用空格来划分级别,前面为键,后面为值,且值和冒号之间有空格, +虽然yaml的语法不止如此简单,但是我们最常用的也就这些很简单的东西。 + +yaml的数组有两个表示形式 +```yaml +array1: ["1","2"] #yaml的注释 +array2: [1,2] #yaml不允许有重复的键 +array3: + - 1 + - 2 + - 3 + +``` +如果还要了解其他,可以上yaml官网查看他们语法,这里只讲解这些语法 + +二. 如何使用nukkit的配置文件库 + +原本的snakeYaml使用起来比较复杂,因此nukkit官方提供了简化,同一 +使用Config对象来表达和操作。 + +使用默认的配置 + +默认配置文件为config.yml,可以通过saveDefaultConfig()方法来实现, +前提是你的resources下面要创建一个config.yml,这个方法会默认在 +plugins/${你的插件名字}下创建一个config.yml,并且会把resources下面的那个 +config.yml内容复制过来. +![5-01](images/5-01.png) +之后我们调用这个方法即可 +![5-02](images/5-02.png) +我们这里打开一个服务器,做一个实验可以看看,插件名为FirstPlugin +![5-03](images/5-03.png) +我们插件被加载成功,我们看看我们的文件夹 +![5-04](images/5-04.png) +发现.../plugins/FirstPlugin下面出现了一模一样的config.yml + +使用自定义的配置 + +自定义配置有两种方式,一种是已经初始化的文件,一种是空白文件,元素后期添加 + +1. 初始化的文件 +saveResource(String fileName, boolean replace) + +第一个是文件名称,默认是this.getDataFolder()+"/"+fileName的路径 +getDataFolder()为.../plugins/你的插件名 ,不包含后面的"/",使用时记得注意 +假如你的插件名称为abc,那么路径为.../plugins/abc + +第二个是是否替换文件,每次重新启动服务器时,会把文件内容重新更新,如果为false, +则不会更新。或者已经存在config,将不会换掉。如果为true,那么就会换掉它。之前修改 +的内容就会被替换(实际上加了true就是把文件删掉重新创建一遍) + +而文件初始化的来源和之前的config.yml一样,我们可以看看saveDefaultConfig()源码会发现, +它的本质也是saveResource + +PluginBase.java +``` + @Override + public void saveDefaultConfig() { + if (!this.configFile.exists()) { + this.saveResource("config.yml", false); + } + } + +``` +2. 空白文件 +空白文件的文件默认没有getDataFolder(),它的默认路径是和nukkit.jar同一级别的文件目录. +``` +Config config = new Config(this.getDataFolder()+"/myConfig.yml",Config.YAML); +config.save();//保存文件,文件不存在就会创建 +``` +Config可以实现对文件的操作,例如先前的config.yml,我们想对其实现操作,可以 +``` +Config config = new Config(this.getDataFolder()+"/config.yml",Config.YAML); +config.set("me","12");//将me修改为12,如果me不存在将创建me +config.save(); +``` +当然值得注意,每次重新运行,set都会修改一次me,所以如果手动修改了me,就会被还原。 +所以你可以做一个条件判断来避免还原的问题,比如判断文件是否存在。 +当然这是初始化文件出现的问题,我还是建议初始化文件使用saveResource来初始化 + +Config的常用方法 +1.构造方法 + +我们可以看官方源码 + +Config.java +``` +/** + * Constructor for Config instance with undefined file object + * + * @param type - Config type + */ + public Config(int type) { + this.type = type; + this.correct = true; + this.config = new ConfigSection(); + } + + /** + * Constructor for Config (YAML) instance with undefined file object + */ + public Config() { + this(Config.YAML); + } + + public Config(String file) { + this(file, Config.DETECT); + } + + public Config(File file) { + this(file.toString(), Config.DETECT); + } + + public Config(String file, int type) { + this(file, type, new ConfigSection()); + } + + public Config(File file, int type) { + this(file.toString(), type, new ConfigSection()); + } + + +``` +file为文件名称,默认路径为nukkit的根目录 +type为类型,主要使用的类型是 + +Config.java +``` + public static final int DETECT = -1; //Detect by file extension + public static final int PROPERTIES = 0; // .properties + public static final int CNF = Config.PROPERTIES; // .cnf + public static final int JSON = 1; // .js, .json + public static final int YAML = 2; // .yml, .yaml + //public static final int EXPORT = 3; // .export, .xport + //public static final int SERIALIZED = 4; // .sl + public static final int ENUM = 5; // .txt, .list, .enum + public static final int ENUMERATION = Config.ENUM; + + +``` +我们主要使用yaml,json.properties,其他大家可以自行查询。 + +如何实现动态内容 + +比如一些插件可以这样做 +```yaml +message: ${player}加入了信息 +``` + +其实可以使用replace做到 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; + + +public class OtherListener implements Listener { + + @EventHandler + public void onPLayerJoin(PlayerJoinEvent e){ + String message; + //获取到内容后... + e.getPlayer().sendMessage(message.replace("${player}",e.getPlayer().getName())); + } +} +``` +当然我们也可以基于反射做一个简单的解析工具 + +```java +class Utils{ + String[] vals = {"player","ip"}; + Map map = new HashMap(){ + { + put("player","getName"); + put("ip","getAddress"); + } + }; + public String translate(Event e,String message){ + try{ + Set> entries = map.entrySet(); + for(Map.Entry e1:entries){ + message = message.replace("${"+e1.getKey()+"}",e.getClass().getDeclaredMethod(e1.getValue()).invoke(e).toString()); + } + }catch (Exception e2){ + e2.printStackTrace(); + } + return message; + } +} + +``` + +[上一章](第四章-如何编写命令.md) [下一章](第六章-如何编写plugin.yml.md) \ No newline at end of file diff --git a/public/mengyanote/.trash/第八章-案例玩家进入信息等效果.md b/public/mengyanote/.trash/第八章-案例玩家进入信息等效果.md new file mode 100644 index 0000000..295549b --- /dev/null +++ b/public/mengyanote/.trash/第八章-案例玩家进入信息等效果.md @@ -0,0 +1,199 @@ +[上一章](第七章-PluginBase类.md) [下一章](第一章-主要的事件介绍.md) +# 第一部分 第八章 案例课:玩家进入案例演示 +参与编写者: MagicLu550 +#### 建议学习时间: 30分钟 +##### 学习要点: 对于之前知识的巩固和加深认识 + +这个项目的需求很简单.实现一个玩家加入自定义提示信息,可以手动取消信息的功能 +我们列举下步骤 +- 创建项目 +- 导入nukkit包 +- 创建初始化配置文件set-info.yml +- 创建plugin.yml +- 创建主类 + - 创建配置 + +- 创建监听器 + - 读取配置内容 + - 发送玩家信息 +- 创建命令 + -判断 +- 注册监听器和命令 +- 完成 + +1.第一到二步请自己完成 +2.set-inf的内容 +```yaml +message: 欢迎${player}加入了服务器 +``` +3.我的plugin.yml的内容 +```yaml +name: MyJoin +main: net.noyark.www.MyJoin +version: "0.0.1" +author: magiclu550 +api: ["1.0.9"] +description: My first plugin +#当采用注册时,控制权限需要在这里声明 +commands: + set: + permission: myjoin.set +permissions: + myjoin.set: + default: op +``` +4.创建主类 MyJoin +```java +package net.noyark.www; + +import cn.nukkit.plugin.PluginBase; + + +public class MyJoin extends PluginBase { + + private Map cancel; + + private static MyJoin instance; + + @Override + public void onLoad() { + this.getLogger().info("插件开始加载"); + } + + @Override + public void onEnable() { + instance = this; + this.saveDefaultConfig(); + this.getLogger().info("插件初始化完毕"); + + } + + @Override + public void onDisable() { + this.getLogger().info("插件已经关闭"); + } + + public static MyJoin getInstance() { + return instance; + } + + public void setCancel(String name,boolean isCancel) { + cancel.put(name,isCancel); + } + + public Map getCancel() { + return cancel; + } +} + +``` +5.创建监听器 +```java +package net.noyark.www; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.player.PlayerJoinEvent; + +public class MyJoinListener implements Listener { + + @EventHandler + public void onJoin(PlayerJoinEvent e){ + Boolean isCancel = MyJoin.getInstance().getCancel().get(e.getPlayer().getName()); + if(isCancel!=null&&!isCancel) { + String message = MyJoin.getInstance().getConfig().getString("message"); + e.setJoinMessage(message.replace("${player}", e.getPlayer().getName())); + }else{ + MyJoin.getInstance().getCancel().put(e.getPlayer().getName(),true); + } + } + +} + +``` +6.创建命令 +```java +package net.noyark.www; + +import cn.nukkit.command.Command; +import cn.nukkit.command.CommandSender; + +public class MyCommand extends Command { + + public MyCommand() { + super("set","设置是否改变加入信息","/set"); + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + if(args.length!=0) + MyJoin.getInstance().getCancel().put(sender.getName(),Boolean.valueOf(args[0])); + else + //这行代码可能会吓到你,不要担心,他只是一个找玩家名字来找到是否取消 + //如果为空,则默认取消,如果不是空,则把玩家之前的状态取反 + MyJoin.getInstance().getCancel().put(sender.getName(), + MyJoin.getInstance().getCancel().get( + sender.getName() + )==null?false:!MyJoin.getInstance() + .getCancel() + .get(sender.getName() + ) + ); + return true; + } +} +``` +7. 注册 +```java +package net.noyark.www; + +import cn.nukkit.plugin.PluginBase; + +import java.util.Map; + + +public class MyJoin extends PluginBase { + + private Map cancel; + private static MyJoin instance; + + @Override + public void onLoad() { + this.getLogger().info("插件开始加载"); + } + + @Override + public void onEnable() { + instance = this; + this.saveDefaultConfig(); + //一定在它的后面注册!!否则会出现一系列奇怪问题... + this.getServer().getCommandMap().register("",new MyCommand()); + this.getServer().getPluginManager().registerEvents(new MyJoinListener(),this); + this.getLogger().info("插件初始化完毕"); + + } + + @Override + public void onDisable() { + this.getLogger().info("插件已经关闭"); + } + + public static MyJoin getInstance() { + return instance; + } + + public void setCancel(String name,boolean isCancel) { + cancel.put(name,isCancel); + } + + public Map getCancel() { + return cancel; + } +} + +``` + +这大概是这个项目的流程,很简单,但是大家可以练一练,扎实基本功,我们马上开始推入下一章 +感谢你们的支持 + +[上一章](第七章-PluginBase类.md) [下一章](第一章-主要的事件介绍.md) \ No newline at end of file diff --git a/public/mengyanote/.trash/第六章-各种工具类的介绍.md b/public/mengyanote/.trash/第六章-各种工具类的介绍.md new file mode 100644 index 0000000..da599cf --- /dev/null +++ b/public/mengyanote/.trash/第六章-各种工具类的介绍.md @@ -0,0 +1,3 @@ +[上一章](第五章-各种实体类的方法介绍.md) [下一章](第七章-如何发送数据包.md) + +[上一章](第五章-各种实体类的方法介绍.md) [下一章](第七章-如何发送数据包.md) \ No newline at end of file diff --git a/public/mengyanote/.trash/第六章-如何编写plugin.yml.md b/public/mengyanote/.trash/第六章-如何编写plugin.yml.md new file mode 100644 index 0000000..bf5c313 --- /dev/null +++ b/public/mengyanote/.trash/第六章-如何编写plugin.yml.md @@ -0,0 +1,81 @@ +[上一章](第五章-如何使用配置文件.md) [下一章](第七章-PluginBase类.md) +# 第一部分 第六章 如何编写plugin.yml +参与编写者: SmallasWater MagicLu550 +#### 建议学习时间: 10分钟 +##### 学习要点: 了解plugin.yml内容 + +1. 关于plugin.yml + +plugin.yml 是 nukkit加载插件的主要文件 在加载插件前必先加载plugin.yml + +在[第二章](第二章-插件要素.md)中已经介绍了其大致的结构 + +2. plugin.yml构成 + +```yaml +name: FirstPlugin # nukkit运行时识别的插件名 +main: net.noyark.www.Example # 主类名称,不能以cn.nukkit开头 +version: "0.0.1" # 版本号 +author: 你的名字,这里指作者名称 +api: ["1.0.9"] # 早期nukkit api为1.0.0, +# 目前大概为1.0.9 +depend: ["EconomyAPI"] # 依赖的插件名称 添加后如果Plugins文件夹不存在添加的插件则关闭本插件 +loadbefore: ["EconomyAPI"] # 在xx插件之后加载 一般用作解决调用依赖库出现的ClassCastExpection +description: My first plugin # 介绍 +commands: # Commands指令列表 + fp: # 指令名称 不要加 / + usage: "/fp help" # 指令的用法 当onCommand返回false时 输出 usage内容 + description: "指令介绍" # 指令的介绍 + permission: FirstPlugin.fp # 指令权限 如果你希望插件仅允许 op执行 可以尝试这个 + aliases: [] # 指令别名 可以增加中文名称 +permissions: + FirstPlugin.fp: # 权限名称 + description: "" # 权限的介绍 + default: op # 权限限制 op / notop notop为非op可执行 op 为仅限op执行 +``` +3. 其他构成 + +我们通过拆解PluginDescription类,可以知道 + +PluginDescription.java +``` + private String name; + private String main; + private List api; + private List depend = new ArrayList<>(); + private List softDepend = new ArrayList<>(); + private List loadBefore = new ArrayList<>(); + private String version; + private Map commands = new HashMap<>(); + private String description; + private final List authors = new ArrayList<>(); + private String website; + private String prefix; + private PluginLoadOrder order = PluginLoadOrder.POSTWORLD; +``` +其中load属性分为POSTWORLD和STARTUP,他们区别官方在注释说明了 + +PluginLoadOrder.java +``` +/** + * 表示这个插件在服务器启动时就开始加载。
+ * Indicates that the plugin will be loaded at startup. + * + * @see cn.nukkit.plugin.PluginLoadOrder + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + STARTUP, + /** + * 表示这个插件在第一个世界加载完成后开始加载。
+ * Indicates that the plugin will be loaded after the first/default world was created. + * + * @see cn.nukkit.plugin.PluginLoadOrder + * @since Nukkit 1.0 | Nukkit API 1.0.0 + */ + POSTWORLD +``` +config里有一个load,分别为STARUP与POSTWORLD,前者使插件加载在地图之前,后者为使插件加载在地图之后,如果对地图加载有需求的话,必须填写POSTWORLD,否则将无法获取level + +您也可以添加自己的网站: website属性 + +[上一章](第五章-如何使用配置文件.md) [下一章](第七章-PluginBase类.md) diff --git a/public/mengyanote/.trash/第四章-Server类和PluginManager类.md b/public/mengyanote/.trash/第四章-Server类和PluginManager类.md new file mode 100644 index 0000000..28dd893 --- /dev/null +++ b/public/mengyanote/.trash/第四章-Server类和PluginManager类.md @@ -0,0 +1,97 @@ +[上一章](第三章-计时器的介绍.md) [下一章](第五章-各种实体类的方法介绍.md) +# 第二部分 第四章 Server类和PluginManager类 +参与编写者: MagicLu550 +#### 建议学习时间: 20分钟 +##### 学习要点: 了解Server类和PluginManager类 + +一. Server + +1.概述 + +Server类是插件几乎所有接口的入口,几乎一切的接口都是基于这个类获得的,而在nukkit中,Server类 +是作为一个对象单独存在,Server的实例化意味着nukkit服务器的启动,并且不允许外部调用其构造方法,但可以根据getInstance方法或者插件主类提供的 +getServer方法可以获得,这里我们提到了两个获得Server的方法 +``` + Server.getInstance(); + this.getServer();//this.getClass() == mainClass +``` +Server对象是在Nukkit类里完成初始化的,所以我们不需要担心Server对象是否存在的问题.加载插件 +前,Server对象已经存在.一切启动的初始化操作都在Server的构造方法中完成.对于Server的复杂原理, +这里不过多赘述,可以参见第四部分的内容 + +Nukkit.java Line. 108-115 +``` + + try { + if (TITLE) { + System.out.print((char) 0x1b + "]0;Nukkit is starting up..." + (char) 0x07); + } + new Server(PATH, DATA_PATH, PLUGIN_PATH, language); + } catch (Throwable t) { + log.throwing(t); + } +``` +2. Server类的常用方法 + * addOp(String) 可以添加op管理员的名称,name是玩家名称 + * addWhitelist(String) 可以添加白名单 + * batchPackets​(Player[], DataPacket[]) 批量发送数据包,后面[数据包发送篇](第七章-如何发送数据包.md)详细讲解 + * broadMessage(String) 发送服务器广播信息,所有玩家可见 + * addRecipe​(Recipe) 添加配方,这个配方指包括合成、炉子、炼药台等使用的配方。 + * broadcastPacket​(Player[], DataPacket) 向所有玩家广播数据包 + * forceShutdown() 强制关闭服务端 + * doAutoSave() 自动保存 + * generateLevel​(String) 产生一个level(世界),String为名字,返回创建是否成功 + * getAllowFlight() 获得这个服务器是否是允许飞行的 + * getApiVersion() 获取插件api的版本 + * getCommandAliases() 将返回以(一个指令名对应着多个别名)为一对的Map集合 + * getCommandMap() 获取指令Map,通过它可以注册一些命令,[前面已经说到过](第四章-如何编写命令.md) + * getDataPath() 获取服务端的数据目录 + * getDefaultGamemode() 获取服务端的默认模式(如创造模式等) + * getDefaultLevel() 获取默认的世界对象,如World + * getDifficulty() 获得游戏难度,如和平模式等 + * getIp() 获得服务端的ip地址 + * getIpBans() 获得封禁的信息(ban) + * getLanguage() 获得服务端默认语言(如zh等) + * getLevelByName(String) 通过世界名称获得世界对象 + * getMaxPlayers() 获得最大人数 + * getMotd() 获得服务端的motd + * getName() 获得服务端的名称 + * getNameBans() 获得迸封禁的玩家表 + * getOfflinePlayer(String) 通过玩家名称得到不在线玩家 + * getOnlinePlayers() 获得在线玩家,UUID都是唯一的标识符 + * getPlayerExact(String) 通过名称获得一个确切的玩家​ + * getPluginManager() 获得插件管理器 + * getOps() 获得管理员清单 + * getPort() 获得端口 + * getPluginPath() 获得插件文件夹的位置 + * getScheduler() 获得任务表,可以注册有关多线程之类的东西 + * getSubMotd() 获得附属的motd + * hasWhitelist() 是否有白名单 + * isOp​(String) 判断一个玩家是否是op,String为玩家名称 + * reload() 重启服务端 + * reloadWhitelist() 重新加载白名单 + * removeOnlinePlayer​(Player) 删除在线玩家 + * removeOp​(String) 删除指定管理员 + * removeWhitelist​(String) 删除一个玩家的白名单 + * shutdown() 关闭服务端 + * unloadLevel​(Level) 卸载一个世界 + +二. PluginManager +1. 概述 +PluginManager是插件管理器,很多的插件加载和数据储存都在这里进行,如监听器 +的注册等 +使用这个类也可以实现动态加载插件等一系列的操作,PluginManager的加载基于JavaPluginLoader + +2. 常用的方法 + * addPermission(Permission) 添加Permission对象 + * callEvent(Event) 触发一个事件 + * clearPlugins() 清空插件 + * disablePlugin(Plugin) 停止一个插件,这个插件会提前调用onDisable + 并卸载 + * getPlugin​(String) 得到其他插件的插件对象 + * loadPlugin​(File) 加载一个插件,路径默认为服务端根目录 + * loadPlugins​(File) 加载一个文件夹的插件 + * registerEvents​(Listener, Plugin) 注册监听器 + * removePermission​(String) 删除一个Permission + +[上一章](第三章-计时器的介绍.md) [下一章](第五章-各种实体类的方法介绍.md) diff --git a/public/mengyanote/.trash/第四章-如何编写命令.md b/public/mengyanote/.trash/第四章-如何编写命令.md new file mode 100644 index 0000000..7e8004b --- /dev/null +++ b/public/mengyanote/.trash/第四章-如何编写命令.md @@ -0,0 +1,237 @@ +[上一章](第三章-如何编写监听器.md) [下一章](第五章-如何使用配置文件.md) +# 第一部分 第四章 如何编写命令 +参与编写者: MagicLu550 +#### 建议学习时间: 30分钟 +##### 学习要点: 学习自己创建一个简易的命令,了解指令和指令映射,了解SimpleCommand的使用 + +其实创建一个简易的命令很简单,创建的过程也不必多讲,先前我在 +[第二章](第二章-插件要素.md)已经提到了如何创建它,大家可以参考 + +nukkit的原生命令也是很多基于Command创建的.很多项目是需求指令 +以使得用户和您的项目操作,也就是作为一个 **接口(Interface)** , +接下来在基于[第二章](第二章-插件要素.md)的命令注册后,我们介绍 +以下nukkit的命令。 +nukkit的命令的父类是Command,它有很多的构造方法 +``` + public Command(String name) { + this(name, "", null, new String[0]); + } + + public Command(String name, String description) { + this(name, description, null, new String[0]); + } + + public Command(String name, String description, String usageMessage) { + this(name, description, usageMessage, new String[0]); + } + + public Command(String name, String description, String usageMessage, String[] aliases) { + this.commandData = new CommandData(); + this.name = name.toLowerCase(); // Uppercase letters crash the client?!? + this.nextLabel = name; + this.label = name; + this.description = description; + this.usageMessage = usageMessage == null ? "/" + name : usageMessage; + this.aliases = aliases; + this.activeAliases = aliases; + this.timing = Timings.getCommandTiming(this); + this.commandParameters.put("default", new CommandParameter[]{new CommandParameter("args", CommandParamType.RAWTEXT, true)}); + } +``` +我们可以知道,nukkit的命令都是toLowerCase的,即小写,也就是说,命令不区分大小写。 +对于命令如何存储,服务端如何识别一个命令,我们从源码中找到以下资料: + +-- + +命令的区分标识是fallBackPrefix+:+label,默认为指令的名称,一般fallBackPrefix都写"" + +这一块知识缺点将会有其他人补充[1] + +代码依据 - SimpleCommandMap.java +``` +159 private boolean registerAlias(Command command, boolean isAlias, String fallbackPrefix, String label) { +160 this.knownCommands.put(fallbackPrefix + ":" + label, command); + +``` +-- + + +存储指令的容器是实现CommandMap接口的,即SimpleCommandMap,我们可以通过 +``` + this.getServer().getCommandMap(); +``` +得到CommandMap. + +Command,CommandMap有很多方法 + +1. Command + 1. 根构造方法的参数为 + ``` + String name, String description, String usageMessage, String[] aliases + + 第一个name是指令名称,最终会转换为全小写 + + 第二个description是指令介绍,用于给玩家查看使用的 + + 第三个usageMessage就是当玩家对命令使用错误,返回的信息 + + 第四个aliases就是指令的别名,指令可以有多个别名 + ``` + 当然,也有简化的构造方法,可以根据你的需求任意调用,这里不多阐述,其他的都是为默认值 + 2. Command的主要属性 + 如同command的构造方法一样,command我们需要了解的属性基本也就是这四个。其他属性将会 + 在nukkit原理解析的时候讲解 + 3. Command的比较常用的方法 + 1. boolean execute(CommandSender commandSender, String label, String[] strings) + + 这个方法是需要开发者自行实现的方法,当指令被触发,就会执行execute里的代码 + 它的参数我们在[第二章](第二章-插件要素.md)提到了 + + 2. String getName() + + 这个可以获取指令的名称 + + 其余方法我们将会在后期附件讲解到,如果有想要知悉的其他方法,我们会另外在这里做补充, + 或者您认为常用的,也可以pull request添加进去 + +2. CommandMap + 1. boolean register(String fallbackPrefix, Command command) + 可以注册指令,fallbackPrefix是前缀,用于服务端存储命令对象的标识 + nukkit的本地命令的fallbackPrefix为nukkit + command则为你的自定义命令对象 + 2. void registerAll(String fallbackPrefix, List commands) + 这个可以一次性注册多个指令 + 3. boolean dispatch(CommandSender sender, String cmdLine) + 这个调用一个命令,cmdLine就是日常所输入的命令 + 4. void registerSimpleCommands(Object object) + 这个是调用简单指令,通过注解实现的指令对象,我们后面将会演示如何使用它。 + +nukkit官方后来推出一系列简化操作,如SimpleCommand,SimpleConfig等,我们这里解释以下SimpleCommand + +SimpleCommand运用了注解,同样通过 **反射** 实现的,我们可以看到官方的源码来探讨它的使用 + +SimpleCommandMap.java +``` +@Override + public void registerSimpleCommands(Object object) { + for (Method method : object.getClass().getDeclaredMethods()) { + cn.nukkit.command.simple.Command def = method.getAnnotation(cn.nukkit.command.simple.Command.class); + if (def != null) { + SimpleCommand sc = new SimpleCommand(object, method, def.name(), def.description(), def.usageMessage(), def.aliases()); + + Arguments args = method.getAnnotation(Arguments.class); + if (args != null) { + sc.setMaxArgs(args.max()); + sc.setMinArgs(args.min()); + } + + CommandPermission perm = method.getAnnotation(CommandPermission.class); + if (perm != null) { + sc.setPermission(perm.value()); + } + + if (method.isAnnotationPresent(ForbidConsole.class)) { + sc.setForbidConsole(true); + } + + CommandParameters commandParameters = method.getAnnotation(CommandParameters.class); + if (commandParameters != null) { + Map map = Arrays.stream(commandParameters.parameters()) + .collect(Collectors.toMap(Parameters::name, parameters -> Arrays.stream(parameters.parameters()) + .map(parameter -> new CommandParameter(parameter.name(), parameter.type(), parameter.optional())) + .distinct() + .toArray(CommandParameter[]::new))); + + sc.commandParameters.putAll(map); + } + + this.register(def.name(), sc); + } + } + } +``` +很显然,简易命令必须要有@Command注解在方法上,方法上标记一些内容,当然,最终只是把一个类拆解,分为多个命令 +对象注册(SimpleCommand),最终也继承自Command。SimpleCommand提供了对于参数最大和最小的限制。 + +SimpleCommand.java +``` +@Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + if (this.forbidConsole && sender instanceof ConsoleCommandSender) { + this.sendInGameMessage(sender); + return false; + } else if (!this.testPermission(sender)) { + return false; + } else if (this.maxArgs != 0 && args.length > this.maxArgs) { + this.sendUsageMessage(sender); + return false; + } else if (this.minArgs != 0 && args.length < this.minArgs) { + this.sendUsageMessage(sender); + return false; + } + + boolean success = false; + + try { + //这里执行我们的命令 + success = (Boolean) this.method.invoke(this.object, sender, commandLabel, args); + } catch (Exception exception) { + Server.getInstance().getLogger().logException(exception); + } + + if (!success) { + this.sendUsageMessage(sender); + } + + return success; + } +``` +这段代码我们可以知道方法的参数有规范要求的 + Object object,CommandSender sender,String label,String[] args +object就是我们的命令对象了,通过registerSimpleCommand注册进去的命令对象 +其他显而易见,不再多讲,具体如何使用,其实很简单 +```java +package net.noyark.www; + + +import cn.nukkit.command.CommandSender; +import cn.nukkit.command.simple.Arguments; +import cn.nukkit.command.simple.Command; + +public class MySimpleCommand { + + @Command(name = "hello",description = "233",usageMessage = "/hello") + @Arguments(max = 10,min = 0) + public void onHelloCommand(Object object, CommandSender sender, String label, String[] args){ + //这里写指令处理代码 + } +} +``` +最终通过registerSimpleCommand注册即可.事实上是对Command的封装 + +command的用户组(这里参考自snake1999的文章) + +```yaml +permissions: #这个标签我们只写一次就ok了 + plugin.hello: + description: 你好 + default: op #权限组,后期会讲到 +commands: #这个标签我们只写一次就ok了 + hello: + description: 你好 + usage: "/hello" + permission: plugin.hello +``` +这里我们发现了default,这个的选项有以下几种 + +- op,代表服务器管理员,在ops.txt中规定。 +- notop,代表除服务器管理员外的所有玩家。 +- true,代表所有玩家。 +- false,代表空集。如果某个命令对应这个权限,那就没有人能够使用这个命令(控制台除外)。 + +大家可以根据这些选项来控制指令的使用范围了 + +参考文献: +- [Nukkit插件从0开始](https://www.cnblogs.com/xtypr/p/nukkit_plugin_start_from_0.html) + +[上一章](第三章-如何编写监听器.md) [下一章](第五章-如何使用配置文件.md) diff --git a/public/mengyanote/AI大语言模型玩法/AI提示词工程/AI绘画提示词.md b/public/mengyanote/AI/AI提示词工程/AI绘画提示词.md similarity index 100% rename from public/mengyanote/AI大语言模型玩法/AI提示词工程/AI绘画提示词.md rename to public/mengyanote/AI/AI提示词工程/AI绘画提示词.md diff --git a/public/mengyanote/AI大语言模型玩法/AI提示词工程/开发前后端分离网站提示词.md b/public/mengyanote/AI/AI提示词工程/开发前后端分离网站提示词.md similarity index 100% rename from public/mengyanote/AI大语言模型玩法/AI提示词工程/开发前后端分离网站提示词.md rename to public/mengyanote/AI/AI提示词工程/开发前后端分离网站提示词.md diff --git a/public/mengyanote/AI大语言模型玩法/Qwen-Code命令行安装使用教程.md b/public/mengyanote/AI/Qwen-Code命令行安装使用教程.md similarity index 100% rename from public/mengyanote/AI大语言模型玩法/Qwen-Code命令行安装使用教程.md rename to public/mengyanote/AI/Qwen-Code命令行安装使用教程.md diff --git a/public/mengyanote/AI大语言模型玩法/Qwen-Code官方文档使用教程.md b/public/mengyanote/AI/Qwen-Code官方文档使用教程.md similarity index 100% rename from public/mengyanote/AI大语言模型玩法/Qwen-Code官方文档使用教程.md rename to public/mengyanote/AI/Qwen-Code官方文档使用教程.md diff --git a/public/mengyanote/AI大语言模型玩法/大语言模型的API key.md b/public/mengyanote/AI/大语言模型的API key.md similarity index 100% rename from public/mengyanote/AI大语言模型玩法/大语言模型的API key.md rename to public/mengyanote/AI/大语言模型的API key.md diff --git a/public/mengyanote/AI大语言模型玩法/大语言模型的API 调用.md b/public/mengyanote/AI/大语言模型的API 调用.md similarity index 100% rename from public/mengyanote/AI大语言模型玩法/大语言模型的API 调用.md rename to public/mengyanote/AI/大语言模型的API 调用.md diff --git a/public/mengyanote/AI大语言模型玩法/阿里云百炼平台模型API调用示例.md b/public/mengyanote/AI/阿里云百炼平台模型API调用示例.md similarity index 100% rename from public/mengyanote/AI大语言模型玩法/阿里云百炼平台模型API调用示例.md rename to public/mengyanote/AI/阿里云百炼平台模型API调用示例.md diff --git a/public/mengyanote/Docker/优秀好用的Docker镜像/MongoDB数据库.md b/public/mengyanote/Docker/优秀好用的Docker镜像/MongoDB-数据库.md similarity index 100% rename from public/mengyanote/Docker/优秀好用的Docker镜像/MongoDB数据库.md rename to public/mengyanote/Docker/优秀好用的Docker镜像/MongoDB-数据库.md diff --git a/public/mengyanote/Docker/优秀好用的Docker镜像/MySQL数据库.md b/public/mengyanote/Docker/优秀好用的Docker镜像/MySQL-数据库.md similarity index 100% rename from public/mengyanote/Docker/优秀好用的Docker镜像/MySQL数据库.md rename to public/mengyanote/Docker/优秀好用的Docker镜像/MySQL-数据库.md diff --git a/public/mengyanote/Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md b/public/mengyanote/Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md new file mode 100644 index 0000000..4b3a637 --- /dev/null +++ b/public/mengyanote/Docker/优秀好用的Docker镜像/NapCat-QQ机器人框架.md @@ -0,0 +1,20 @@ + +```bash +docker run -d \ + --name filecodebox \ + --restart=always \ + -p 12345:12345 \ + -v /shumengya/docker/storage/filecodebox:/app/data \ + lanol/filecodebox:beta + +``` + +```bash +#典型的非关系型数据库(json) +docker pull lanol/filecodebox:beta +``` + +``` +docker stop lanol/filecodebox:beta +docker rm lanol/filecodebox:beta +``` \ No newline at end of file diff --git a/public/mengyanote/Docker/优秀好用的Docker镜像/Ntfy-萌芽通知.md b/public/mengyanote/Docker/优秀好用的Docker镜像/Ntfy-萌芽通知.md new file mode 100644 index 0000000..02d465f --- /dev/null +++ b/public/mengyanote/Docker/优秀好用的Docker镜像/Ntfy-萌芽通知.md @@ -0,0 +1,32 @@ + +```bash +docker run -d \ + --name ntfy \ + --restart=always \ + -e TZ="Asia/Shanghai" \ + -e NTFY_BASE_URL="https://ntfy.shumengya.top" \ + -e NTFY_CACHE_FILE="/var/cache/ntfy/cache.db" \ + -e NTFY_AUTH_FILE="/var/lib/ntfy/auth.db" \ + -e NTFY_AUTH_DEFAULT_ACCESS="deny-all" \ + -e NTFY_BEHIND_PROXY="true" \ + -e NTFY_ATTACHMENT_CACHE_DIR="/var/lib/ntfy/attachments" \ + -e NTFY_ENABLE_LOGIN="true" \ + -v /shumengya/docker/storage/ntfy/cache:/var/cache/ntfy \ + -v /shumengya/docker/storage/ntfy/etc:/etc/ntfy \ + -v /shumengya/docker/storage/ntfy/lib:/var/lib/ntfy \ + -p 82:80 \ + binwiederhier/ntfy:latest \ + serve + + +``` + +```bash +#典型的非关系型数据库(json) +docker pull binwiederhier/ntfy:latest +``` + +``` +docker stop binwiederhier/ntfy:latest +docker rm binwiederhier/ntfy:latest +``` \ No newline at end of file diff --git a/public/mengyanote/Docker/优秀好用的Docker镜像/Postgres数据库.md b/public/mengyanote/Docker/优秀好用的Docker镜像/Postgres-数据库.md similarity index 100% rename from public/mengyanote/Docker/优秀好用的Docker镜像/Postgres数据库.md rename to public/mengyanote/Docker/优秀好用的Docker镜像/Postgres-数据库.md diff --git a/public/mengyanote/Docker/优秀好用的Docker镜像/Redis数据库.md b/public/mengyanote/Docker/优秀好用的Docker镜像/Redis-内存数据库.md similarity index 100% rename from public/mengyanote/Docker/优秀好用的Docker镜像/Redis数据库.md rename to public/mengyanote/Docker/优秀好用的Docker镜像/Redis-内存数据库.md diff --git a/public/mengyanote/Github相关/Github仓库公共API总结.md b/public/mengyanote/Github/Github仓库公共API总结.md similarity index 100% rename from public/mengyanote/Github相关/Github仓库公共API总结.md rename to public/mengyanote/Github/Github仓库公共API总结.md diff --git a/public/mengyanote/Github相关/Github获取仓库密钥.md b/public/mengyanote/Github/Github获取仓库密钥.md similarity index 100% rename from public/mengyanote/Github相关/Github获取仓库密钥.md rename to public/mengyanote/Github/Github获取仓库密钥.md diff --git a/public/mengyanote/Github相关/Linux下使用git探索.md b/public/mengyanote/Github/Linux下使用git探索.md similarity index 100% rename from public/mengyanote/Github相关/Linux下使用git探索.md rename to public/mengyanote/Github/Linux下使用git探索.md diff --git a/public/mengyanote/Github相关/linux常用git命令.md b/public/mengyanote/Github/linux常用git命令.md similarity index 100% rename from public/mengyanote/Github相关/linux常用git命令.md rename to public/mengyanote/Github/linux常用git命令.md diff --git a/public/mengyanote/LeetCode 刷题/力扣-两数之和详解.md b/public/mengyanote/LeetCode/力扣-两数之和详解.md similarity index 100% rename from public/mengyanote/LeetCode 刷题/力扣-两数之和详解.md rename to public/mengyanote/LeetCode/力扣-两数之和详解.md diff --git a/public/mengyanote/LeetCode 刷题/力扣1-两数相加问题.md b/public/mengyanote/LeetCode/力扣1-两数相加问题.md similarity index 100% rename from public/mengyanote/LeetCode 刷题/力扣1-两数相加问题.md rename to public/mengyanote/LeetCode/力扣1-两数相加问题.md diff --git a/public/mengyanote/LeetCode 刷题/力扣2-两数之和.md b/public/mengyanote/LeetCode/力扣2-两数之和.md similarity index 100% rename from public/mengyanote/LeetCode 刷题/力扣2-两数之和.md rename to public/mengyanote/LeetCode/力扣2-两数之和.md diff --git a/public/mengyanote/Linux/Git常用命令.md b/public/mengyanote/Linux/Git常用命令.md new file mode 100644 index 0000000..4c1dcbd --- /dev/null +++ b/public/mengyanote/Linux/Git常用命令.md @@ -0,0 +1,14 @@ +```shell +git remote add origin +git remote add origin https://github.com/shumengya6666666/Pixel-plane-wars.git +git remote add origin git@github.com:shumengya6666666/Pixel-plane-wars.git +git remote set-url origin git@github.com:shumengya6666666/Pixel-plane-wars.git +git clone git@github.com:shumengya6666666/Pixel-plane-wars.git +git remote add origin git@github.com:shumengya6666666/Pixel-Odyssey.git +git push -u origin main +git remote add origin git@github.com:shumengya6666666/Sprout-Farm.git +git remote set-url origin git@github.com:shumengya6666666/Sprout-Farm.git +git push -u origin master +git remote add origin git@github.com:shumengya6666666/Pixel-plane-wars.git +``` + diff --git a/public/mengyanote/Linux相关/Linux zip 命令总结.md b/public/mengyanote/Linux/Linux zip 命令总结.md similarity index 100% rename from public/mengyanote/Linux相关/Linux zip 命令总结.md rename to public/mengyanote/Linux/Linux zip 命令总结.md diff --git a/public/mengyanote/Linux/Linux一些奇奇怪怪的命令.md b/public/mengyanote/Linux/Linux一些奇奇怪怪的命令.md new file mode 100644 index 0000000..276af9b --- /dev/null +++ b/public/mengyanote/Linux/Linux一些奇奇怪怪的命令.md @@ -0,0 +1,22 @@ +打开终端tmoe面板: +curl -LO https://gitee.com/mo2/linux/raw/2/2.awk +awk -f 2.awk + +ubuntu和deepin系统安装宝塔面板: +wget -O install.sh https://download.bt.cn/install/install_lts.sh && sudo bash install.sh ed8484bec + +重启宝塔面板: +bt restart + +开启宝塔面板: +bt default + +安装和运行casaos轻量nas系统: +curl -fsSL https://get.casaos.io | sudo bash + +安装和运行1panel面板: +curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh + +连接ssh示例 + +ssh root@192.168.25.151 -p 6003 \ No newline at end of file diff --git a/public/mengyanote/Linux/Linux下的scp命令总结.md b/public/mengyanote/Linux/Linux下的scp命令总结.md new file mode 100644 index 0000000..45c4484 --- /dev/null +++ b/public/mengyanote/Linux/Linux下的scp命令总结.md @@ -0,0 +1,50 @@ +Linux scp 命令总结 +用途:安全复制文件/目录到本地或远程主机(基于 SSH 协议)。 + +基本语法 + +scp [选项] 源文件 目标路径 +  + +常用选项 + +选项 说明 + -r  递归复制目录及子目录 + -P   指定 SSH 端口(注意大写 P) + -i   使用指定的私钥文件认证 + -C  压缩传输数据 + -p  保留文件属性(时间戳、权限等) + -v  显示详细传输过程 + +典型示例 + +1. 本地文件 → 远程主机 + +scp local_file.txt user@remote_host:/path/to/remote_dir/ +  +2. 远程文件 → 本地 + +scp user@remote_host:/path/to/remote_file.txt ~/local_dir/ +  +3. 复制目录(需加  -r ) + +scp -r local_dir/ user@remote_host:/path/to/remote_dir/ +  +4. 远程主机间复制(通过本地中转) + +scp user1@host1:/file.txt user2@host2:/path/ +  +5. 指定端口(如非默认 22 端口) + +scp -P 2222 local_file.txt user@remote_host:/remote_path/ +  +6. 使用私钥认证 + +scp -i ~/.ssh/id_rsa local_file.txt user@remote_host:/remote_path/ +  + +注意事项 + +- 远程路径需以  user@host:  开头。 +- 目标路径不存在时会自动创建(目录需  -r )。 +- 若提示权限问题,检查私钥文件权限(需  chmod 600 )。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Linux不同格式解压命令.md b/public/mengyanote/Linux/Linux不同格式解压命令.md new file mode 100644 index 0000000..46511ca --- /dev/null +++ b/public/mengyanote/Linux/Linux不同格式解压命令.md @@ -0,0 +1,27 @@ +在 Linux 中解压不同格式的压缩文件,可使用以下命令: + +1. tar.gz 文件 + +tar -xzf filename.tar.gz +  + +- 说明: + x  表示解压, z  调用 gzip 解压, f  指定文件名。 + +2. tar.zst 文件 + +tar --zstd -xf filename.tar.zst +  + +- 说明: + --zstd  明确使用 zstd 解压, x  解压, f  指定文件名。需确保系统已安装  zstd  工具。 + +3. tar.xz 文件 + +tar -xJf filename.tar.xz +  + +- 说明: + J  调用 xz 解压, x  解压, f  指定文件名。 + +补充:若需解压时显示详细过程,可添加  -v  参数(如  tar -xvzf filename.tar.gz )。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Linux后台运行程序.md b/public/mengyanote/Linux/Linux后台运行程序.md new file mode 100644 index 0000000..201ccd9 --- /dev/null +++ b/public/mengyanote/Linux/Linux后台运行程序.md @@ -0,0 +1,127 @@ +在 Linux 系统中,让服务一直保持在后台运行有多种方法,下面为你详细介绍: + +### 1. 使用 `&` 符号 +在命令后面加上 `&` 符号可以让命令在后台运行。 + +#### 示例 +```bash +python my_script.py & +``` +上述命令会让 `my_script.py` 脚本在后台运行。 + +#### 注意事项 +- 这种方式虽然简单,但当你关闭当前终端会话时,该进程可能会收到 `SIGHUP` 信号而终止。 +- 你可以使用 `jobs` 命令查看当前终端中后台运行的作业,使用 `fg` 命令将后台作业调回到前台。 + +### 2. 使用 `nohup` 命令 +`nohup` 命令可以让程序忽略 `SIGHUP` 信号,从而在你关闭终端后继续运行。 + +#### 示例 +```bash +nohup python my_script.py > output.log 2>&1 & +``` +- `nohup`:用于忽略 `SIGHUP` 信号。 +- `> output.log`:将标准输出重定向到 `output.log` 文件。 +- `2>&1`:将标准错误输出也重定向到标准输出,即同样写入 `output.log` 文件。 +- `&`:让命令在后台运行。 + +#### 查看运行状态 +使用 `ps` 命令可以查看进程是否还在运行: +```bash +ps -ef | grep my_script.py +``` + +### 3. 使用 `screen` 工具 +`screen` 是一个全屏窗口管理器,它可以创建多个虚拟终端会话,即使你断开连接,会话中的进程仍然会继续运行。 + +#### 安装 `screen` +在 Debian 或 Ubuntu 系统上: +```bash +sudo apt-get install screen +``` +在 CentOS 或 RHEL 系统上: +```bash +sudo yum install screen +``` + +#### 使用步骤 +1. 启动一个新的 `screen` 会话: +```bash +screen +``` +2. 在 `screen` 会话中运行你的命令,例如: +```bash +python my_script.py +``` +3. 按下 `Ctrl + A` 然后再按下 `D` 组合键,将当前 `screen` 会话分离,此时会话会在后台继续运行。 +4. 如果你想重新连接到该会话,可以使用以下命令: +```bash +screen -r +``` + +### 4. 使用 `tmux` 工具 +`tmux` 也是一个类似 `screen` 的终端复用工具,功能更强大。 + +#### 安装 `tmux` +在 Debian 或 Ubuntu 系统上: +```bash +sudo apt-get install tmux +``` +在 CentOS 或 RHEL 系统上: +```bash +sudo yum install tmux +``` + +#### 使用步骤 +1. 启动一个新的 `tmux` 会话: +```bash +tmux new -s mysession +``` +这里的 `mysession` 是会话的名称,你可以自定义。 +2. 在 `tmux` 会话中运行你的命令,例如: +```bash +python my_script.py +``` +3. 按下 `Ctrl + B` 然后再按下 `D` 组合键,将当前 `tmux` 会话分离。 +4. 如果你想重新连接到该会话,可以使用以下命令: +```bash +tmux attach -t mysession +``` + +### 5. 使用系统服务管理工具(如 `systemd`) +对于需要长期稳定运行的服务,推荐使用系统服务管理工具,如 `systemd`(大多数现代 Linux 发行版都使用 `systemd`)。 + +#### 创建服务文件 +创建一个新的服务文件,例如 `/etc/systemd/system/my_script.service`: +```ini +[Unit] +Description=My Python Script Service +After=network.target + +[Service] +ExecStart=/usr/bin/python /path/to/my_script.py +WorkingDirectory=/path/to/working/directory +Restart=always +User=your_username + +[Install] +WantedBy=multi-user.target +``` +- `Description`:服务的描述信息。 +- `After`:指定服务在网络服务启动后再启动。 +- `ExecStart`:指定要执行的命令。 +- `WorkingDirectory`:指定工作目录。 +- `Restart`:设置为 `always` 表示服务崩溃或停止后会自动重启。 +- `User`:指定运行服务的用户。 + +#### 启动和管理服务 +```bash +# 重新加载 systemd 管理器配置 +sudo systemctl daemon-reload +# 启动服务 +sudo systemctl start my_script.service +# 设置服务开机自启 +sudo systemctl enable my_script.service +# 查看服务状态 +sudo systemctl status my_script.service +``` \ No newline at end of file diff --git a/public/mengyanote/Linux相关/Linux命令风格解析.md b/public/mengyanote/Linux/Linux命令风格解析.md similarity index 100% rename from public/mengyanote/Linux相关/Linux命令风格解析.md rename to public/mengyanote/Linux/Linux命令风格解析.md diff --git a/public/mengyanote/Linux/Linux复制文件命令.md b/public/mengyanote/Linux/Linux复制文件命令.md new file mode 100644 index 0000000..5b6b661 --- /dev/null +++ b/public/mengyanote/Linux/Linux复制文件命令.md @@ -0,0 +1,36 @@ +在 Linux 中,可以使用 `cp` 命令将某个路径的文件复制到另一个位置。命令格式如下: + +```bash +cp 源文件路径 目标路径 +``` + +### 示例 +假设要将 `/home/user/file.txt` 复制到 `/home/user/documents/`,命令如下: + +```bash +cp /home/user/file.txt /home/user/documents/ +``` + +### 选项 +- **`-r`**:复制目录及其内容。 +- **`-i`**:覆盖前提示确认。 +- **`-v`**:显示复制进度。 + +### 示例 +1. **复制目录**: + ```bash + cp -r /home/user/folder /home/user/documents/ + ``` + +2. **覆盖前提示**: + ```bash + cp -i /home/user/file.txt /home/user/documents/ + ``` + +3. **显示进度**: + ```bash + cp -v /home/user/file.txt /home/user/documents/ + ``` + +### 总结 +`cp` 命令用于复制文件或目录,常用选项包括 `-r`、`-i` 和 `-v`。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Linux安装ollama.md b/public/mengyanote/Linux/Linux安装ollama.md new file mode 100644 index 0000000..5dd95bb --- /dev/null +++ b/public/mengyanote/Linux/Linux安装ollama.md @@ -0,0 +1,5 @@ +apt install tur-repo +apt install ollama +ollama serve +重新开启个会话 +安装各种开源模型 diff --git a/public/mengyanote/Linux相关/Linux常用软件包安装.md b/public/mengyanote/Linux/Linux常用软件包安装.md similarity index 100% rename from public/mengyanote/Linux相关/Linux常用软件包安装.md rename to public/mengyanote/Linux/Linux常用软件包安装.md diff --git a/public/mengyanote/Linux/Linux查看无线网口.md b/public/mengyanote/Linux/Linux查看无线网口.md new file mode 100644 index 0000000..fe90696 --- /dev/null +++ b/public/mengyanote/Linux/Linux查看无线网口.md @@ -0,0 +1,17 @@ +在Debian系统中,可以通过以下几种方法查看使用的无线网卡的名称: + +### 使用命令行工具`ifconfig` +1. 打开终端,输入命令`ifconfig -a`。 +2. 该命令会列出系统中所有的网络接口,包括有线网卡、无线网卡等。通常无线网卡的名称会以`wlan`开头,如`wlan0`、`wlan1`等。你可以根据网卡的相关信息(如MAC地址、IP地址等)来确定具体使用的无线网卡。 + +### 使用`iwconfig`命令 +1. 在终端中输入`iwconfig`。 +2. 此命令主要用于配置无线网卡,它会显示出系统中的无线接口信息,包括无线网卡的名称、频率、信号强度等。通过识别无线网卡的相关参数,能找到正在使用的无线网卡名称。 + +### 查看`/sys/class/net/`目录 +1. 打开终端,输入命令`ls /sys/class/net/`。 +2. 该目录下列出了系统中所有的网络设备接口文件,无线网卡的名称通常也以`wlan`开头,通过查看该目录可以找到无线网卡的名称。 + +### 使用`nmcli`命令 +1. 确保`NetworkManager`服务已安装并运行,然后在终端中输入`nmcli device status`。 +2. 该命令会显示系统中网络设备的状态信息,包括设备名称、设备类型、状态等。在设备类型为`wifi`的行中,可以找到无线网卡的名称。 \ No newline at end of file diff --git a/public/mengyanote/Linux相关/Linux的Proc目录解析.md b/public/mengyanote/Linux/Linux的Proc目录解析.md similarity index 100% rename from public/mengyanote/Linux相关/Linux的Proc目录解析.md rename to public/mengyanote/Linux/Linux的Proc目录解析.md diff --git a/public/mengyanote/Linux/Linux软件包存放地址.md b/public/mengyanote/Linux/Linux软件包存放地址.md new file mode 100644 index 0000000..6356848 --- /dev/null +++ b/public/mengyanote/Linux/Linux软件包存放地址.md @@ -0,0 +1,40 @@ +在 Linux 系统中,安装的软件包通常会放置在以下几个目录中,具体路径取决于软件包的类型和安装方式。 + +### 1. **二进制文件(可执行文件)** + - **`/usr/bin/`**:大多数用户安装的软件的二进制文件都会安装在此目录下。这些是常见的应用程序和命令(例如 `ls`, `cp`, `git` 等)。 + - **`/bin/`**:存放一些最基本的系统命令,这些命令在系统的任何时候都需要可用,通常在恢复模式下也能使用。 + - **`/usr/local/bin/`**:用户自己安装的软件(通常是通过源代码编译安装的软件)会放在这个目录下。它优先级高于 `/usr/bin/`,因此用户安装的命令会覆盖系统自带的软件。 + - **`/sbin/` 和 `/usr/sbin/`**:这些目录通常存放的是系统管理工具,需要管理员权限来使用。比如 `ifconfig`, `mount` 等。 + +### 2. **库文件** + - **`/lib/`**:包含了系统启动和运行时所必需的共享库(例如 C 库)。 + - **`/usr/lib/`**:用于存放大多数安装的软件包的共享库,支持应用程序的运行。 + - **`/usr/local/lib/`**:与 `/usr/local/bin/` 类似,这是存放用户手动安装的程序和库的地方。 + +### 3. **配置文件** + - **`/etc/`**:这是系统和应用程序的全局配置文件所在的目录。几乎所有的配置文件都可以在这里找到。例如 `/etc/passwd` 存放用户信息,`/etc/ssh/sshd_config` 存放 SSH 配置等。 + - **`/usr/local/etc/`**:对于用户自己安装的软件包,它的配置文件一般会放在此目录下。 + +### 4. **文档和帮助文件** + - **`/usr/share/`**:存放共享的数据文件,包括应用程序的文档、帮助文件、图标等。例如 `/usr/share/doc/` 目录存放着已安装软件包的文档和许可证。 + - **`/usr/local/share/`**:用户自己安装的软件的共享数据文件通常存放在此目录。 + +### 5. **临时文件** + - **`/tmp/`**:这个目录用于存放临时文件,系统或应用程序运行时会使用这个目录来存放临时数据。通常,`/tmp/` 目录中的文件会在系统重启后被删除。 + - **`/var/tmp/`**:类似于 `/tmp/`,但 `/var/tmp/` 中的文件不会在系统重启时被清除,适用于需要较长时间存储的临时文件。 + +### 6. **日志文件** + - **`/var/log/`**:存放系统和应用程序的日志文件。比如 `/var/log/syslog` 记录了系统日志,`/var/log/auth.log` 记录了认证相关的日志等。 + +### 7. **其他相关目录** + - **`/opt/`**:这个目录通常用于存放大型的第三方软件包,特别是那些由供应商提供的独立应用程序(例如 Google Chrome 或 Oracle Java)通常会安装在这个目录。 + - **`/home/`**:每个用户的个人目录会在 `/home/` 目录下(例如 `/home/user/`),其中可能包含用户安装的软件或自定义的程序。 + +### 总结 +- **二进制文件**:`/bin/`、`/usr/bin/`、`/usr/local/bin/` +- **库文件**:`/lib/`、`/usr/lib/`、`/usr/local/lib/` +- **配置文件**:`/etc/`、`/usr/local/etc/` +- **共享数据文件**:`/usr/share/`、`/usr/local/share/` +- **日志文件**:`/var/log/` +- **临时文件**:`/tmp/`、`/var/tmp/` +- **软件包**:`/opt/`(大型第三方应用) diff --git a/public/mengyanote/Linux/QQ机器人napcat命令.md b/public/mengyanote/Linux/QQ机器人napcat命令.md new file mode 100644 index 0000000..a5a5314 --- /dev/null +++ b/public/mengyanote/Linux/QQ机器人napcat命令.md @@ -0,0 +1,9 @@ +输入 xvfb-run -a qq --no-sandbox 命令启动。 +保持后台运行 请输入 screen -dmS napcat bash -c "xvfb-run -a qq --no-sandbox" +后台快速登录 请输入 screen -dmS napcat bash -c "xvfb-run -a qq --no-sandbox -q QQ号码" +Napcat安装位置 /opt/QQ/resources/app/app_launcher/napcat +WEBUI_TOKEN 请自行查看/opt/QQ/resources/app/app_launcher/napcat/config/webui.json文件获取 +注意, 您可以随时使用 screen -r napcat 来进入后台进程并使用 ctrl + a + d 离开(离开不会关闭后台进程)。 +停止后台运行 + + screen -S napcat -X quit \ No newline at end of file diff --git a/public/mengyanote/Linux/SSH服务端配置.md b/public/mengyanote/Linux/SSH服务端配置.md new file mode 100644 index 0000000..19febdb --- /dev/null +++ b/public/mengyanote/Linux/SSH服务端配置.md @@ -0,0 +1,202 @@ +配置 SSH 服务端(`sshd_config`)是确保服务器安全性和功能性的关键步骤。以下是基于您提供的默认配置文件的详细配置指南,包括关键选项的解释和安全建议。 + +### 1. 基本配置 + +#### 端口设置 +默认情况下,SSH 使用端口 22。为了提高安全性,您可以更改为其他端口。 + +```bash +Port 22 +``` + +**建议**:修改为非标准端口(如 `Port 2222`)可以减少被自动扫描攻击的风险。 + +```bash +Port 2222 +``` + +#### 监听地址 +默认配置监听所有 IPv4 地址。 + +```bash +ListenAddress 0.0.0.0 +#ListenAddress :: +``` + +**建议**:如果服务器有多个网络接口,您可以指定特定的 IP 地址来监听。例如,仅监听内部网络: + +```bash +ListenAddress 192.168.1.100 +``` + +### 2. 主机密钥 + +主机密钥用于验证服务器的身份。确保这些密钥存在并且安全。 + +```bash +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_ecdsa_key +#HostKey /etc/ssh/ssh_host_ed25519_key +``` + +**建议**:取消注释需要的密钥类型,确保至少启用一种强加密算法(如 Ed25519)。 + +```bash +HostKey /etc/ssh/ssh_host_ed25519_key +``` + +### 3. 身份验证 + +#### 禁止 root 登录 +出于安全考虑,建议禁止 root 用户通过 SSH 登录。 + +```bash +#PermitRootLogin prohibit-password +``` + +**建议**:将其设置为 `no` 或 `prohibit-password`,推荐使用密钥认证。 + +```bash +PermitRootLogin no +``` + +#### 密码认证 +启用或禁用密码认证。为了更高的安全性,建议使用密钥认证并禁用密码认证。 + +```bash +#PasswordAuthentication yes +PasswordAuthentication no +``` + +#### 公钥认证 +确保启用公钥认证,并配置 `AuthorizedKeysFile`。 + +```bash +PubkeyAuthentication yes +AuthorizedKeysFile .ssh/authorized_keys +``` + +**建议**:保持默认配置,确保每个用户的 `~/.ssh/authorized_keys` 文件中包含正确的公钥。 + +#### 键盘交互认证 +如果只使用密钥认证,禁用键盘交互认证。 + +```bash +KbdInteractiveAuthentication no +``` + +### 4. 使用 PAM + +PAM(可插拔认证模块)用于增强认证机制。 + +```bash +UsePAM yes +``` + +**建议**:保持启用,但确保其他认证方法(如密码认证)根据需要进行配置。 + +### 5. 限制用户和组 + +通过 `AllowUsers` 或 `AllowGroups` 限制可以通过 SSH 登录的用户或组。 + +```bash +# Allow only specific users +#AllowUsers user1 user2 + +# Allow only specific groups +#AllowGroups sshusers +``` + +**建议**:根据需要取消注释并配置,限制访问范围。 + +```bash +AllowUsers alice bob +``` + +### 6. 其他安全设置 + +#### 禁用空密码登录 + +```bash +#PermitEmptyPasswords no +PermitEmptyPasswords no +``` + +**确保**:禁止使用空密码登录。 + +#### 启用防火墙和限制连接数 + +配置防火墙(如 `ufw` 或 `iptables`)仅允许必要的端口和 IP 地址访问。同时,可以设置 `MaxAuthTries` 和 `MaxSessions` 来限制尝试次数和并发会话数。 + +```bash +MaxAuthTries 3 +MaxSessions 2 +``` + +### 7. 日志和监控 + +设置合适的日志级别以监控 SSH 活动。 + +```bash +LogLevel VERBOSE +``` + +**建议**:根据需要设置日志级别,如 `INFO` 或 `VERBOSE`,并定期检查日志文件(通常位于 `/var/log/auth.log` 或 `/var/log/secure`)。 + +### 8. 重启 SSH 服务 + +在完成配置后,重新启动 SSH 服务以应用更改。 + +```bash +sudo systemctl restart sshd +``` + +**检查配置是否正确**: + +在重新启动之前,最好检查配置文件是否有语法错误: + +```bash +sudo sshd -t +``` + +如果没有输出,说明配置语法正确。否则,按照错误提示进行修正。 + +### 9. 其他推荐配置 + +- **启用双因素认证(2FA)**:增加登录的安全性。 +- **限制 SSH 登录时间**:通过 `sshd_config` 或使用其他工具限制用户的登录时间。 +- **使用 Fail2Ban**:防止暴力破解攻击,通过监控日志文件并动态更新防火墙规则。 + +### 示例优化后的 `sshd_config` + +以下是根据上述建议优化后的配置示例: + +```bash +Port 2222 +ListenAddress 0.0.0.0 +HostKey /etc/ssh/ssh_host_ed25519_key + +PubkeyAuthentication yes +AuthorizedKeysFile .ssh/authorized_keys + +PermitRootLogin no +PasswordAuthentication no +KbdInteractiveAuthentication no + +UsePAM yes + +AllowUsers alice bob + +LogLevel VERBOSE + +MaxAuthTries 3 +MaxSessions 2 + +AcceptEnv LANG LC_* + +Subsystem sftp /usr/lib/openssh/sftp-server +``` + +### 总结 + +正确配置 SSH 服务端对于保障服务器的安全至关重要。请根据您的具体需求和环境,结合上述指南进行配置。同时,定期审查和更新配置,以应对潜在的安全威胁。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Termux-SSH相关.md b/public/mengyanote/Linux/Termux-SSH相关.md new file mode 100644 index 0000000..428d7ae --- /dev/null +++ b/public/mengyanote/Linux/Termux-SSH相关.md @@ -0,0 +1,77 @@ +Termux更改终端密码: + +``` +passwd +``` + +重启SSH服务 + +``` +pkill sshd +sshd +``` + +查看本机IP + +``` +ifconfig +``` + +生成SSH主机密钥 + +``` +ssh-keygen -A +``` + +更新Termux包 + +``` +pkg update && pkg upgrade +``` + +Termux退出chroot容器 + +``` +exit +``` + +Termux安装软件 + +``` +pkg install +``` + +查看终端用户名 + +``` +whoami +``` + + + + + + + + + + + + + +妈的旧手机termux终端用户名 + +u0_a143 + +爸的旧手机termux终端用户名 + +u0_a135 + +Termux执行sh脚本 + +``` +bash 脚本名.sh +``` + + + diff --git a/public/mengyanote/Linux/Termux/Termux-api用法总结/弹窗.md b/public/mengyanote/Linux/Termux/Termux-api用法总结/弹窗.md new file mode 100644 index 0000000..acb39a1 --- /dev/null +++ b/public/mengyanote/Linux/Termux/Termux-api用法总结/弹窗.md @@ -0,0 +1,37 @@ +`termux-toast` 命令用于在 Android 设备上显示一个短暂的消息(Toast)。这个消息会在屏幕上弹出,并在几秒钟后自动消失。它的基本用法如下: + +### 基本用法 + +```bash +termux-toast [选项] <消息文本> +``` + +### 常用选项 + +- `-s` 或 `--short`:使用短时间显示消息(默认选项)。 +- `-l` 或 `--long`:使用较长时间显示消息。 +- `-g` 或 `--gravity`:设置消息显示的位置。可选值为 `top`、`middle` 和 `bottom`(默认是 `bottom`)。 +- `-b` 或 `--background`:设置背景颜色,使用十六进制颜色代码。 +- `-c` 或 `--color`:设置文本颜色,使用十六进制颜色代码. + +### 示例 + +1. **显示一个默认的短消息**: + + ```bash + termux-toast "Hello, World!" + ``` + +3. **在屏幕顶部显示消息**: + + ```bash + termux-toast -g top "This message is at the top." + ``` + +4. **设置背景和文本颜色**: + + ```bash + termux-toast -b "#FF0000" -c "#FFFFFF" "Red background with white text." + ``` + +这些命令可以在脚本中使用,以便在某些事件发生时通知用户。请注意,由于 Toast 本质上是短暂的通知类型,它们不适合显示需要用户交互或长时间关注的重要信息。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Termux/Termux-api用法总结/录音.md b/public/mengyanote/Linux/Termux/Termux-api用法总结/录音.md new file mode 100644 index 0000000..c85dcf8 --- /dev/null +++ b/public/mengyanote/Linux/Termux/Termux-api用法总结/录音.md @@ -0,0 +1,57 @@ +当然!以下是一些使用 `termux-microphone-record` 命令的示例,展示了如何利用不同的参数来满足不同的录音需求: + +1. **使用默认设置开始录音**: + ```bash + termux-microphone-record -d + ``` + 这将使用默认设置开始录音,并保存到默认文件。 + +2. **录制到指定文件**: + ```bash + termux-microphone-record -f /sdcard/my_recording.wav + ``` + 这会将录音保存到 `/sdcard/my_recording.wav` 文件中。 + +3. **限制录音时间为 30 秒**: + ```bash + termux-microphone-record -f /sdcard/my_recording.wav -l 30 + ``` + 这将录制 30 秒的音频,并保存到指定文件。 + +4. **使用特定编码器(例如 AAC)录音**: + ```bash + termux-microphone-record -f /sdcard/my_recording.aac -e aac + ``` + 这会使用 AAC 编码器进行录音。 + +5. **指定比特率为 128 kbps**: + ```bash + termux-microphone-record -f /sdcard/my_recording.wav -b 128 + ``` + 这将以 128 kbps 的比特率进行录音。 + +6. **使用特定采样率(例如 44100 Hz)录音**: + ```bash + termux-microphone-record -f /sdcard/my_recording.wav -r 44100 + ``` + 这会以 44100 Hz 的采样率录音。 + +7. **使用双声道录音**: + ```bash + termux-microphone-record -f /sdcard/my_recording.wav -c 2 + ``` + 这会以双声道(立体声)进行录音。 + +8. **获取当前录音的信息**: + ```bash + termux-microphone-record -i + ``` + 这将显示有关当前录音的详细信息。 + +9. **停止当前录音**: + ```bash + termux-microphone-record -q + ``` + 这会停止当前正在进行的录音。 + +这些示例展示了如何使用 `termux-microphone-record` 的不同参数来调整录音的输出。你可以根据需要组合这些参数来实现更复杂的录音配置。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Termux/Termux-api用法总结/所有支持的api.md b/public/mengyanote/Linux/Termux/Termux-api用法总结/所有支持的api.md new file mode 100644 index 0000000..9102463 --- /dev/null +++ b/public/mengyanote/Linux/Termux/Termux-api用法总结/所有支持的api.md @@ -0,0 +1,40 @@ +Termux API 是一个提供设备功能访问的工具,允许在 Termux 环境中通过命令行接口访问 Android 设备的各种硬件和系统功能。以下是这些 Termux API 的简单介绍: + +1. **termux-api-start/stop**:启动或停止 Termux API 服务。 +2. **termux-audio-info**:获取设备的音频信息。 +3. **termux-battery-status**:获取设备的电池状态信息。 +4. **termux-brightness**:设置或获取屏幕亮度。 +5. **termux-call-log**:访问设备的通话记录。 +6. **termux-camera-info**:获取设备相机信息。 +7. **termux-camera-photo**:使用设备相机拍照。 +8. **termux-clipboard-get/set**:获取或设置设备的剪贴板内容。 +9. **termux-contact-list**:获取设备的联系人列表。 +10. **termux-dialog**:显示对话框。 +11. **termux-download**:下载文件。 +12. **termux-fingerprint**:使用指纹传感器进行身份验证。 +13. **termux-infrared-frequencies/transmit**:获取红外频率信息或发送红外信号。 +14. **termux-job-scheduler**:安排一个任务在特定时间运行。 +15. **termux-keystore**:访问或管理密钥存储。 +16. **termux-location**:获取设备的地理位置信息。 +17. **termux-media-player**:播放媒体文件。 +18. **termux-media-scan**:扫描媒体文件。 +19. **termux-microphone-record**:录制音频。 +20. **termux-nfc**:访问 NFC 功能。 +21. **termux-notification/channel/list/remove**:管理通知,包括创建、列出和移除通知。 +22. **termux-saf-create/dirs/ls/managedir/mkdir/read/rm/stat/write**:通过 Storage Access Framework (SAF) 访问和管理文件系统。 +23. **termux-sensor**:访问设备的传感器数据。 +24. **termux-share**:共享文件或文本。 +25. **termux-sms-inbox/list/send**:访问和管理短信,包括查看收件箱和发送短信。 +26. **termux-speech-to-text**:将语音转换为文本。 +27. **termux-storage-get**:从设备存储中获取文件。 +28. **termux-telephony-call/cellinfo/deviceinfo**:拨打电话或获取设备的电话信息。 +29. **termux-toast**:显示一个短暂的消息。 +30. **termux-torch**:控制设备的手电筒。 +31. **termux-tts-engines/speak**:获取 TTS 引擎信息或合成语音。 +32. **termux-usb**:访问 USB 设备。 +33. **termux-vibrate**:控制设备的振动。 +34. **termux-volume**:获取或设置音量。 +35. **termux-wallpaper**:设置设备的壁纸。 +36. **termux-wifi-connectioninfo/enable/scaninfo**:管理 Wi-Fi 连接,获取连接信息或扫描 Wi-Fi 网络。 + +这些 API 提供了丰富的功能,可以让用户通过脚本自动化许多任务或访问设备的硬件功能。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Termux/Termux-api用法总结/闪光灯.md b/public/mengyanote/Linux/Termux/Termux-api用法总结/闪光灯.md new file mode 100644 index 0000000..aa573bb --- /dev/null +++ b/public/mengyanote/Linux/Termux/Termux-api用法总结/闪光灯.md @@ -0,0 +1,29 @@ +`termux-torch` 命令用于控制 Android 设备的手电筒(通常是相机闪光灯)。可以通过此命令打开或关闭手电筒。它的基本用法如下: + +### 基本用法 + +```bash +termux-torch <状态> +``` + +### 参数 + +- `<状态>`:指定手电筒的状态,可以是 `on` 或 `off`。 + - `on`:打开手电筒。 + - `off`:关闭手电筒。 + +### 示例 + +1. **打开手电筒**: + + ```bash + termux-torch on + ``` + +2. **关闭手电筒**: + + ```bash + termux-torch off + ``` + +这些命令可以在脚本中使用,以便在特定情况下自动打开或关闭手电筒,比如在黑暗环境中需要光源时。使用这些命令时,请确保授予 Termux 应用程序相应的权限,以便访问设备的相机闪光灯功能。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Termux/shell2HTTP软件简单总结.md b/public/mengyanote/Linux/Termux/shell2HTTP软件简单总结.md new file mode 100644 index 0000000..f4fa98a --- /dev/null +++ b/public/mengyanote/Linux/Termux/shell2HTTP软件简单总结.md @@ -0,0 +1,126 @@ +以下是 `shell2http` 项目的详细中文总结: + +--- + +### **项目概述** +`shell2http` 是一个用 Go 编写的轻量级 HTTP 服务器,核心功能是通过 HTTP 请求触发执行预定义的 Shell 命令,并将结果返回给客户端。它适用于开发调试、原型设计、远程控制等场景,支持快速将 Shell 脚本暴露为 HTTP 接口。 + +--- + +### **核心功能** +1. **简单易用** + - 通过命令行参数直接绑定 URL 路径与 Shell 命令,例如: + ```shell + shell2http /date "date" /ps "ps aux" + ``` + - 支持 GET、POST 等多种 HTTP 方法(通过 `METHOD:/path` 语法指定)。 + +2. **请求处理模式** + - **普通模式**:直接执行命令,返回标准输出(stdout)。 + - **表单模式(`-form`)**:解析查询参数和上传文件,生成环境变量供脚本使用: + - `$v_参数名`:来自 URL 查询参数的值(如 `?id=123` → `$v_id`)。 + - `$filepath_字段名`:上传文件的临时路径。 + - `$filename_字段名`:上传文件的原始文件名。 + - **CGI 模式(`-cgi`)**:模拟 CGI 环境,设置 HTTP 请求相关环境变量,处理请求体数据。 + +3. **安全与认证** + - **Basic 认证**:通过 `-basic-auth` 设置用户名密码,支持多用户。 + - **SSL/TLS**:使用 `-cert` 和 `-key` 选项启动 HTTPS 服务器。 + - **表单字段过滤**:通过 `-form-check` 限制参数名格式(如仅允许数字)。 + +4. **高级特性** + - **缓存**:`-cache=N` 缓存命令输出 N 秒。 + - **超时控制**:`-timeout` 设置命令执行超时时间。 + - **错误处理**:`-500` 在命令非零退出时返回 500 错误;`-show-errors` 显示错误输出。 + - **环境变量**:支持导出特定或全部环境变量(`-export-vars`/`-export-all-vars`)。 + +5. **日志与调试** + - 自定义日志文件(`-log`)、禁用时间戳(`-no-log-timestamp`)。 + +--- + +### **安装方式** +1. **MacOS** + ```shell + brew install msoap/tools/shell2http + ``` +2. **Docker** + ```shell + docker pull msoap/shell2http + docker run -p 8080:8080 msoap/shell2http /date "date" + ``` + - 使用 `--init` 防止僵尸进程。 + +3. **Snap(Linux)** + ```shell + sudo snap install shell2http + ``` + - 注意沙箱环境可能导致路径问题。 + +4. **源码编译** + ```shell + go install github.com/msoap/shell2http@latest + ``` + +5. **预编译二进制** + 从 [GitHub Releases](https://github.com/msoap/shell2http/releases) 下载(支持 Windows、Linux、MacOS、树莓派)。 + +--- + +### **使用示例** +1. **基础命令** + ```shell + shell2http /top "top -l 1 | head -10" /date "date" + ``` + - 访问 `http://localhost:8080/date` 返回当前时间。 + +2. **环境变量** + ```shell + shell2http -export-vars=GOPATH /gopath 'echo $GOPATH' + ``` + +3. **表单处理** + ```shell + shell2http -form /upload 'cp $filepath_file1 ./uploads/$filename_file1' + ``` + - 上传文件并保存到 `uploads` 目录。 + +4. **CGI 模式** + ```shell + shell2http -cgi /cgi-script './script.sh' + ``` + - 脚本可读取请求头、请求体,设置响应头。 + +5. **HTTPS 服务器** + ```shell + shell2http -cert=cert.pem -key=key.pem /date "date" + ``` + - 生成自签名证书: + ```shell + go run $(go env GOROOT)/src/crypto/tls/generate_cert.go -host localhost + ``` + +--- + +### **应用场景** +- **系统监控**:暴露 `top`、`ps`、`df` 等命令的 HTTP 接口。 +- **文件操作**:上传/下载文件、目录列表。 +- **远程控制**:调节音量、控制媒体播放器(如 MacOS 的 Vox.app)。 +- **API 模拟**:返回静态 JSON 或动态生成数据。 +- **调试工具**:模拟慢速响应、记录请求日志。 + +--- + +### **相关工具** +- **shell2telegram**:将 Shell 命令绑定到 Telegram 机器人。 +- **websocketd**:将 STDIN/STDOUT 程序转换为 WebSocket 服务。 +- **devd**:本地开发的轻量级 HTTP 守护进程。 + +--- + +### **注意事项** +- **安全性**:避免在生产环境暴露敏感命令,使用防火墙和认证机制。 +- **性能**:默认多线程处理请求,可通过 `-one-thread` 限制为单线程。 +- **路径问题**:Docker 或 Snap 环境需注意命令的可访问性。 + +通过灵活配置,`shell2http` 可快速搭建功能丰富的 HTTP 服务,适合开发者和运维人员简化工作流程。 \ No newline at end of file diff --git a/public/mengyanote/Linux/Termux/shell2http举例.md b/public/mengyanote/Linux/Termux/shell2http举例.md new file mode 100644 index 0000000..6120da2 --- /dev/null +++ b/public/mengyanote/Linux/Termux/shell2http举例.md @@ -0,0 +1,115 @@ +`shell2http` 的灵活性和轻量级特性让它能玩出许多有趣的花样!以下是一些创意使用案例,涵盖实用场景和趣味玩法: + +--- + +### **一、智能家居 & 自动化** +1. **远程控制智能插座** + ```bash + shell2http -basic-auth="admin:密码" POST:/灯控 'curl -X POST http://智能插座IP/开关 -d "state=on"' + ``` + - 用途:用手机浏览器一键开关灯,配合 Siri 快捷指令还能语音控制。 + +2. **树莓派摄像头拍照** + ```bash + shell2http /拍照 'raspistill -o /tmp/snapshot.jpg && base64 /tmp/snapshot.jpg' + ``` + - 用途:远程拍照并返回 Base64 图片,可嵌入网页实时查看。 + +3. **温湿度监控** + ```bash + shell2http /温湿度 'python3 读取传感器脚本.py' + ``` + - 用途:连接 DHT11/DHT22 传感器,通过 HTTP 返回 JSON 格式温湿度数据。 + +--- + +### **二、实用工具** +4. **临时文件共享** + ```bash + shell2http -form /upload 'mv $filepath_file1 ./共享文件夹/$filename_file1 && echo 上传成功' + ``` + - 用途:在局域网内快速共享文件,上传后生成直链供他人下载。 + +5. **二维码生成器** + ```bash + shell2http /qrcode "qrencode -t ANSIUTF8 '$v_text'" + ``` + - 用法:访问 `http://IP:8080/qrcode?text=HelloWorld`,终端直接显示二维码。 + +6. **DDNS 动态域名更新** + ```bash + shell2http /update_ddns 'curl "https://ddns服务商API?ip=$(curl ifconfig.me)"' + ``` + - 用途:外网触发更新 DDNS 记录,解决家庭宽带 IP 变化问题。 + +--- + +### **三、趣味玩法** +7. **语音播报远程控制** + ```bash + shell2http POST:/说话 'echo "$v_text" | espeak -v zh' # Linux 文本转语音 + ``` + - 用途:用手机输入文字,让电脑念出来(比如捉弄同事)。 + +8. **在线抽奖/随机选择** + ```bash + shell2http /抽奖 'shuf -n1 名单.txt' + ``` + - 用途:年会时打开网页点击按钮,大屏幕显示中奖者。 + +9. **生成梗图** + ```bash + shell2http -form /生成表情包 'convert 模板.jpg -pointsize 30 -fill white -annotate +100+200 "$v_text" -' + ``` + - 用途:上传文字生成表情包,可集成到微信群机器人。 + +--- + +### **四、开发调试** +10. **模拟慢速 API** + ```bash + shell2http /slow 'sleep ${v_time:-5} && echo 响应完成' + ``` + - 用途:测试前端 Loading 效果,访问 `/slow?time=10` 模拟 10 秒延迟。 + +11. **Mock 测试接口** + ```bash + shell2http /api/user 'echo "{\"name\":\"张三\",\"age\":$(shuf -i 20-60 -n1)}"' + ``` + - 用途:快速生成随机 JSON 数据,替代未完成的真实接口。 + +12. **代理请求记录器** + ```bash + shell2http -cgi /proxy 'echo "URL: $REQUEST_URI" >> log.txt; curl -s "$v_url"' + ``` + - 用途:记录所有经过的请求参数,调试第三方回调。 + +--- + +### **五、系统管理** +13. **服务器监控面板** + ```bash + shell2http /cpu "top -bn1 | grep 'Cpu(s)'" /内存 "free -h" /磁盘 "df -h" + ``` + - 用途:手机浏览器快速查看服务器状态。 + +14. **远程重启服务** + ```bash + shell2http -500 POST:/reboot_nginx 'systemctl restart nginx && echo 成功' + ``` + - 用途:内网安全重启服务(务必设置 Basic 认证!)。 + +15. **日志实时查看** + ```bash + shell2http /tail_log 'tail -n20 /var/log/syslog' + ``` + - 用途:快速检查日志,无需 SSH 登录。 + +--- + +### **注意事项** +- **安全第一**:暴露在公网时务必启用 `-basic-auth` 和 HTTPS。 +- **权限控制**:敏感操作(如重启服务)建议结合 IP 白名单。 +- **临时用途**:适合原型设计或内部工具,不建议替代专业 API 网关。 + +这些案例只需简单修改即可运行,试试用 `shell2http` 把你身边的硬件和脚本变成「物联网设备」吧! \ No newline at end of file diff --git a/public/mengyanote/Linux/Termux/termux的pkg命令总结.md b/public/mengyanote/Linux/Termux/termux的pkg命令总结.md new file mode 100644 index 0000000..f15c14d --- /dev/null +++ b/public/mengyanote/Linux/Termux/termux的pkg命令总结.md @@ -0,0 +1,25 @@ +pkg  是用于管理 apt 软件包的工具,用法为  pkg [--check-mirror] command [arguments] , --check-mirror  强制重新检查镜像可用性。其命令包括: + + autoclean :从 apt 缓存中删除所有过时软件包。 + + clean :从 apt 缓存中删除所有软件包。 + + files  :显示指定软件包安装的所有文件。 + + install  :安装指定软件包。 + + list-all :列出仓库中所有可用软件包。 + + list-installed :列出已安装的软件包。 + + reinstall  :以最新版本重新安装指定已安装软件包。 + + search  :按名称或描述等查询搜索软件包。 + + show  :显示软件包基本元数据,如依赖项。 + + uninstall  :卸载指定软件包,保留配置文件。 + + upgrade :将所有已安装软件包升级到最新版本。 + + update :从配置的仓库更新 apt 数据库。 \ No newline at end of file diff --git a/public/mengyanote/Linux相关/Windows文件一键上传到Linux.md b/public/mengyanote/Linux/Windows文件一键上传到Linux.md similarity index 100% rename from public/mengyanote/Linux相关/Windows文件一键上传到Linux.md rename to public/mengyanote/Linux/Windows文件一键上传到Linux.md diff --git a/public/mengyanote/Linux/busybox v1.36命令简介.md b/public/mengyanote/Linux/busybox v1.36命令简介.md new file mode 100644 index 0000000..a6d5736 --- /dev/null +++ b/public/mengyanote/Linux/busybox v1.36命令简介.md @@ -0,0 +1,512 @@ +以下是针对 **BusyBox** 中每条命令的简要说明: + +1. **[**:测试表达式的真假。 +2. **[[**:增强版的条件测试命令。 +3. **acpid**:管理系统的 ACPI 事件。 +4. **adjtimex**:调整系统时间。 +5. **ar**:创建、修改、提取归档文件。 +6. **arch**:显示机器架构类型。 +7. **arp**:显示或修改 ARP 缓存。 +8. **arping**:向网络发送 ARP 请求。 +9. **ascii**:显示 ASCII 表。 +10. **ash**:一个轻量级的 shell。 +11. **awk**:强大的文本处理工具。 +12. **base32**:以 Base32 编码格式进行数据转换。 +13. **base64**:以 Base64 编码格式进行数据转换。 +14. **basename**:从路径中提取文件名。 +15. **bbconfig**:配置 BusyBox。 +16. **beep**:产生蜂鸣声。 +17. **blkdiscard**:丢弃磁盘块。 +18. **blkid**:显示块设备的标识。 +19. **blockdev**:对块设备进行操作。 +20. **brctl**:管理网桥接口。 +21. **bunzip2**:解压 `.bz2` 格式文件。 +22. **bzcat**:查看 `.bz2` 格式文件内容。 +23. **bzip2**:压缩文件为 `.bz2` 格式。 +24. **cal**:显示日历。 +25. **cat**:连接文件并显示内容。 +26. **chat**:发送控制字符以进行调制解调器通信。 +27. **chattr**:改变文件的属性。 +28. **chcon**:改变文件的 SELinux 上下文。 +29. **chgrp**:改变文件的组。 +30. **chmod**:改变文件的权限。 +31. **chown**:改变文件的拥有者。 +32. **chroot**:改变根目录。 +33. **chrt**:操作进程的调度策略。 +34. **chvt**:切换虚拟终端。 +35. **cksum**:计算文件的校验和。 +36. **clear**:清除终端屏幕。 +37. **cmp**:比较两个文件。 +38. **comm**:比较两个已排序文件的内容。 +39. **conspy**:查看控制台的输出。 +40. **cp**:复制文件。 +41. **cpio**:创建、解压 cpio 格式归档。 +42. **crc32**:计算 CRC32 校验和。 +43. **crond**:周期性执行任务的守护进程。 +44. **crontab**:编辑 cron 表。 +45. **cttyhack**:改变控制终端。 +46. **cut**:按列剪切文本。 +47. **date**:显示或设置系统日期和时间。 +48. **dc**:计算器程序。 +49. **dd**:转换和复制文件。 +50. **deallocvt**:释放虚拟终端。 +51. **depmod**:生成内核模块依赖关系。 +52. **devmem**:访问物理内存。 +53. **df**:显示文件系统的磁盘空间使用情况。 +54. **dhcprelay**:转发 DHCP 请求。 +55. **diff**:比较文件的不同之处。 +56. **dirname**:获取路径的目录部分。 +57. **dmesg**:显示内核的消息缓冲区内容。 +58. **dnsd**:轻量级 DNS 服务器。 +59. **dnsdomainname**:显示域名。 +60. **dos2unix**:转换 DOS 格式文本为 Unix 格式。 +61. **du**:显示磁盘使用情况。 +62. **dumpkmap**:转储键盘映射。 +63. **dumpleases**:显示 DHCP 租约。 +64. **echo**:显示一行文本。 +65. **ed**:文本编辑器。 +66. **egrep**:扩展正则表达式的 grep 命令。 +67. **eject**:弹出光盘。 +68. **env**:显示或设置环境变量。 +69. **ether-wake**:发送 Wake-on-LAN 魔术包。 +70. **expand**:将制表符转换为空格。 +71. **expr**:计算表达式的值。 +72. **factor**:因数分解。 +73. **fakeidentd**:模拟 identd 服务。 +74. **false**:返回失败状态。 +75. **fatattr**:显示或修改 FAT 文件系统的属性。 +76. **fbset**:设置帧缓冲设备的参数。 +77. **fbsplash**:管理帧缓冲启动画面。 +78. **fdflush**:刷新文件描述符。 +79. **fdformat**:格式化软盘。 +80. **fdisk**:管理磁盘分区。 +81. **fgconsole**:切换到指定的虚拟终端。 +82. **fgrep**:固定字符串搜索工具。 +83. **find**:搜索文件。 +84. **findfs**:查找文件系统。 +85. **flash_eraseall**:擦除闪存设备。 +86. **flash_lock**:锁定闪存设备。 +87. **flash_unlock**:解锁闪存设备。 +88. **flock**:对文件进行锁定。 +89. **fold**:折叠文本行。 +90. **free**:显示内存使用情况。 +91. **freeramdisk**:释放 RAM 磁盘。 +92. **fsck**:检查文件系统的完整性。 +93. **fsck.minix**:检查 Minix 文件系统。 +94. **fsfreeze**:冻结文件系统以进行备份。 +95. **fstrim**:修剪未使用的磁盘空间。 +96. **fsync**:强制磁盘同步。 +97. **ftpd**:启动 FTP 服务器。 +98. **ftpget**:下载文件通过 FTP。 +99. **ftpput**:上传文件通过 FTP。 +100. **fuser**:显示正在使用某个文件的进程。 +101. **getenforce**:显示 SELinux 的状态。 +102. **getopt**:解析命令行选项。 +103. **grep**:搜索文本中的模式。 +104. **groups**:显示用户所属的组。 +105. **gunzip**:解压 `.gz` 文件。 +106. **gzip**:压缩文件为 `.gz` 格式。 +107. **hd**:显示硬盘的分区信息。 +108. **hdparm**:设置硬盘参数。 +109. **head**:显示文件的开头部分。 +110. **hexdump**:以十六进制格式显示文件内容。 +111. **hexedit**:编辑十六进制文件。 +112. **hostname**:显示或设置主机名。 +113. **httpd**:启动 HTTP 服务器。 +114. **hush**:一个小型 shell。 +115. **hwclock**:访问硬件时钟。 +116. **id**:显示用户和组信息。 +117. **ifconfig**:配置网络接口。 +118. **ifdown**:关闭网络接口。 +119. **ifenslave**:配置链路聚合。 +120. **ifplugd**:监控网络接口的连接状态。 +121. **ifup**:启用网络接口。 +122. **inetd**:启动网络服务守护进程。 +123. **inotifyd**:启动文件系统事件监控。 +124. **insmod**:加载内核模块。 +125. **install**:复制文件并设置权限。 +126. **ionice**:设置进程的 I/O 优先级。 +127. **iostat**:显示 CPU 和 I/O 统计信息。 +128. **ip**:配置网络接口和路由。 +129. **ipaddr**:显示或设置 IP 地址。 +130. **ipcalc**:计算和显示 IP 地址信息。 +131. **ipcrm**:删除共享内存、消息队列、信号量。 +132. **ipcs**:显示进程间通信的状态。 +133. **iplink**:管理网络接口的状态。 +134. **ipneigh**:显示邻居表。 +135. **iproute**:管理路由表。 +136. **iprule**:显示或管理路由规则。 +137. **iptunnel**:配置 IP 隧道。 +138. **kbd_mode**:设置键盘模式。 +139. **kill**:终止进程。 +140. **killall**:终止指定名称的所有进程。 +141. **killall5**:终止所有进程。 +142. **klogd**:内核日志守护进程。 +143. **less**:分页显示文件内容。 +144. **link**:创建硬链接。 +145. **ln**:创建硬链接或符号链接。 +146. **loadfont**:加载字体。 +147. **loadkmap**:加载键盘映射。 +148. **logread**:显示日志文件内容。 +149. **losetup**:管理环回设备。 +150. **ls**:列出目录内容。 + +继续接着之前的命令列表进行总结: + +151. **lsattr**:显示文件的属性。 + +152. **lsmod**:显示加载的内核模块。 + +153. **lsof**:列出打开的文件。 + +154. **lspci**:显示所有 PCI 设备。 + +155. **lsscsi**:显示 SCSI 设备信息。 + +156. **lsusb**:列出 USB 设备。 + +157. **lzcat**:解压 `.lz` 文件并显示内容。 + +158. **lzma**:压缩文件为 `.lzma` 格式。 + +159. **lzop**:快速的文件压缩工具。 + +160. **lzopcat**:查看 `.lzo` 格式文件内容。 + +161. **makedevs**:创建设备节点。 + +162. **makemime**:生成 MIME 类型文件。 + +163. **man**:查看手册页(如果有)。 + +164. **md5sum**:计算文件的 MD5 校验和。 + +165. **mesg**:控制终端消息的接收。 + +166. **microcom**:串行通信工具。 + +167. **mim**:提取文件的 MIME 类型。 + +168. **mkdir**:创建目录。 + +169. **mkdosfs**:创建 FAT 文件系统。 + +170. **mke2fs**:创建 ext2 文件系统。 + +171. **mkfifo**:创建命名管道。 + +172. **mkfs.ext2**:创建 ext2 文件系统。 + +173. **mkfs.minix**:创建 Minix 文件系统。 + +174. **mkfs.reiser**:创建 Reiser 文件系统。 + +175. **mkfs.vfat**:创建 VFAT 文件系统。 + +176. **mknod**:创建块设备或字符设备文件。 + +177. **mkswap**:创建交换分区。 + +178. **mktemp**:创建临时文件。 + +179. **modinfo**:显示内核模块的信息。 + +180. **modprobe**:加载或卸载内核模块。 + +181. **more**:分页显示文件内容。 + +182. **mount**:挂载文件系统。 + +183. **mountpoint**:检查是否为挂载点。 + +184. **mpstat**:显示 CPU 使用统计信息。 + +185. **mv**:移动或重命名文件。 + +186. **nameif**:根据 MAC 地址设置网络接口名称。 + +187. **nanddump**:转储 NAND 闪存的内容。 + +188. **nandwrite**:将数据写入 NAND 闪存。 + +189. **nbd-client**:连接到网络块设备。 + +190. **nc**:Netcat 工具,用于读写网络连接。 + +191. **netstat**:显示网络连接状态。 + +192. **nice**:调整进程的优先级。 + +193. **nl**:显示带有行号的文件内容。 + +194. **nmeter**:网络带宽监控工具。 + +195. **nohup**:在后台运行命令并忽略挂起信号。 + +196. **nologin**:禁止用户登录。 + +197. **nsenter**:进入其他命名空间。 + +198. **nslookup**:查询 DNS 信息。 + +199. **nuke**:终止所有与特定进程相关的网络连接。 + +200. **od**:以不同格式显示文件内容(如十六进制)。 + +201. **openvt**:在指定的虚拟终端上运行命令。 + +202. **partprobe**:通知操作系统重新读取分区表。 + +203. **paste**:合并多个文件按列显示。 + +204. **patch**:应用补丁文件。 + +205. **pgrep**:查找匹配指定模式的进程。 + +206. **pidof**:查找指定进程的 PID。 + +207. **ping**:向网络主机发送 ICMP 请求。 + +208. **ping6**:向网络主机发送 ICMPv6 请求。 + +209. **pipe_progress**:显示管道中的数据传输进度。 + +210. **pivot_root**:更改文件系统根目录。 + +211. **pkill**:根据进程名终止进程。 + +212. **pmap**:显示进程的内存映射。 + +213. **popmaildir**:从邮件目录中获取邮件。 + +214. **poweroff**:关闭计算机。 + +215. **powertop**:用于优化电源管理的工具。 + +216. **printenv**:显示所有环境变量。 + +217. **printf**:格式化并输出文本。 + +218. **ps**:显示当前进程信息。 + +219. **pscan**:扫描当前进程的状态。 + +220. **pstree**:以树形结构显示进程。 + +221. **pwd**:显示当前工作目录。 + +222. **pwdx**:显示指定进程的工作目录。 + +223. **raidautorun**:自动启动 RAID 配置。 + +224. **rdate**:同步时间。 + +225. **rdev**:显示或设置设备的特殊属性。 + +226. **readlink**:显示符号链接的目标。 + +227. **readprofile**:读取并显示应用的性能配置。 + +228. **realpath**:返回文件的绝对路径。 + +229. **reboot**:重启系统。 + +230. **reformime**:转换 MIME 格式。 + +231. **renice**:改变进程的优先级。 + +232. **reset**:重置终端。 + +233. **resize**:调整终端大小。 + +234. **resume**:恢复挂起的进程。 + +235. **rev**:反转每行文本。 + +236. **rfkill**:管理无线设备的开关。 + +237. **rm**:删除文件。 + +238. **rmdir**:删除空目录。 + +239. **rmmod**:卸载内核模块。 + +240. **route**:显示或修改路由表。 + +241. **rtcwake**:设置系统的 RTC 来定时唤醒。 + +242. **run-init**:运行初始化程序。 + +243. **run-parts**:按顺序运行目录中的脚本。 + +244. **runcon**:设置进程的 SELinux 上下文。 + +245. **rx**:接收串口数据。 + +246. **script**:记录终端会话。 + +247. **scriptreplay**:重放记录的终端会话。 + +248. **sed**:流编辑器,用于处理文本数据。 + +249. **seedrng**:种子随机数生成器。 + +250. **selinuxenabled**:检查 SELinux 是否启用。 + +251. **sendmail**:发送电子邮件。 + +252. **seq**:生成一个数字序列。 + +253. **sestatus**:显示 SELinux 状态。 + +254. **setconsole**:设置控制台的终端类型。 + +255. **setenforce**:启用或禁用 SELinux 强制模式。 + +256. **setfattr**:设置文件的扩展属性。 + +257. **setfont**:设置终端的字体。 + +258. **setkeycodes**:设置键盘扫描码到键值的映射。 + +259. **setlogcons**:设置日志控制台。 + +260. **setpriv**:设置进程的特权级别。 + +261. **setserial**:设置串口设备的参数。 + +262. **setsid**:创建新的会话并运行命令。 + +263. **setuidgid**:设置进程的用户和组标识。 + +264. **sh**:启动一个新的 shell。 + +265. **sha1sum**:计算文件的 SHA-1 校验和。 + +266. **sha256sum**:计算文件的 SHA-256 校验和。 + +267. **sha3sum**:计算文件的 SHA-3 校验和。 + +268. **sha512sum**:计算文件的 SHA-512 校验和。 + +269. **showkey**:显示键盘输入的键值。 + +270. **shred**:擦除文件,防止数据恢复。 + +271. **shuf**:随机排列输入行。 + +272. **slattach**:设置串行连接。 + +273. **sleep**:暂停一段时间。 + +274. **smemcap**:设置进程内存使用限制。 + +275. **sort**:按行排序文本文件。 + +276. **split**:将文件分割成多个小文件。 + +277. **ssl_client**:通过 SSL 连接远程主机。 + +278. **start-stop-daemon**:启动或停止后台守护进程。 + +279. **stat**:显示文件或文件系统的状态。 + +280. **strings**:显示文件中的可打印字符串。 + +281. **stty**:设置终端行属性。 + +282. **sum**:计算文件的校验和。 + +283. **svc**:启动、停止或重启服务。 + +284. **svok**:检查服务的状态。 + +285. **swapoff**:禁用交换空间。 + +286. **swapon**:启用交换空间。 + +287. **switch_root**:切换到新的根文件系统。 + +288. **sync**:同步文件系统。 + +289. **sysctl**:显示或设置内核参数。 + +290. **syslogd**:启动系统日志守护进程。 + +291. **tac**:反向显示文件内容。 + +292. **tail**:显示文件的最后部分。 + +293. **tar**:创建和解压 tar 归档。 + +294. **tc**:配置网络流量控制。 +295. **tcpsvd**:TCP 服务守护进程。 +296. **tee**:将输入内容输出到多个文件。 +297. **telnet**:远程登录到另一个计算机。 +298. **telnetd**:启动 Telnet 服务器。 +299. **test**:检查条件的真假。 +300. **tftp**:简易的文件传输协议客户端。 +301. **tftpd**:TFTP 服务器。 +302. **time**:测量命令执行时间。 +303. **timeout**:设置命令的超时时间。 +304. **top**:显示系统进程信息。 +305. **touch**:创建空文件或更新文件的时间戳。 +306. **tr**:替换或删除字符。 +307. **traceroute**:追踪数据包在网络中的路由。 +308. **traceroute6**:追踪 IPv6 数据包的路由。 +309. **tree**:以树形结构显示目录内容。 +310. **true**:始终返回成功状态。 +311. **truncate**:截断文件到指定长度。 +312. **ts**:为每行添加时间戳。 +313. **tsort**:排序文件中的时间戳。 +314. **tty**:显示终端设备名称。 +315. **ttysize**:显示终端的大小。 +316. **tunctl**:管理 TUN/TAP 网络设备。 +317. **tune2fs**:调整 ext2/ext3/ext4 文件系统的参数。 +318. **ubiattach**:附加 UBI 设备。 +319. **ubidetach**:分离 UBI 设备。 +320. **ubimkvol**:创建 UBI 卷。 +321. **ubirename**:重命名 UBI 卷。 +322. **ubirmvol**:删除 UBI 卷。 +323. **ubirsvol**:恢复 UBI 卷。 +324. **ubiupdatevol**:更新 UBI 卷的数据。 +325. **udhcpc**:DHCP 客户端,用于获取网络配置信息。 +326. **udhcpc6**:DHCPv6 客户端。 +327. **udhcpd**:DHCP 服务器。 +328. **udpsvd**:UDP 服务守护进程。 +329. **uevent**:显示系统的 udev 事件。 +330. **umount**:卸载文件系统。 +331. **uname**:显示系统信息。 +332. **uncompress**:解压 `.Z` 格式文件。 +333. **unexpand**:将空格转换为制表符。 +334. **uniq**:删除重复的行。 +335. **unix2dos**:转换 Unix 格式文本为 DOS 格式。 +336. **unlink**:删除文件。 +337. **unlzma**:解压 `.lzma` 格式文件。 +338. **unlzop**:解压 `.lzo` 格式文件。 +339. **unshare**:在新命名空间中运行命令。 +340. **unxz**:解压 `.xz` 格式文件。 +341. **unzip**:解压 `.zip` 文件。 +342. **uptime**:显示系统的运行时间和负载。 +343. **usleep**:暂停指定的微秒数。 +344. **uudecode**:解码 `.uu` 格式文件。 +345. **uuencode**:编码文件为 `.uu` 格式。 +346. **vconfig**:管理 VLAN 网络接口。 +347. **vi**:文本编辑器。 +348. **volname**:显示文件系统的卷标。 +349. **watch**:定期执行并显示命令输出。 +350. **watchdog**:监控系统状态并在需要时重启。 +351. **wc**:计算文件的行数、字数和字符数。 +352. **wget**:下载文件。 +353. **which**:显示可执行文件的路径。 +354. **whoami**:显示当前用户的用户名。 +355. **whois**:查询域名注册信息。 +356. **xargs**:将标准输入转换为命令行参数。 +357. **xxd**:创建十六进制转储。 +358. **xz**:压缩文件为 `.xz` 格式。 +359. **xzcat**:查看 `.xz` 格式文件内容。 +360. **yes**:输出指定字符串,通常用来测试管道。 +361. **zcat**:查看 `.gz` 格式文件内容。 +362. **zcip**:配置 ZCIP 地址。 + +这些命令覆盖了文件操作、系统管理、网络配置、进程管理等多个方面,是 BusyBox 在资源受限环境中为用户提供常用功能的集合。 diff --git a/public/mengyanote/Linux/busybox玩法总结.md b/public/mengyanote/Linux/busybox玩法总结.md new file mode 100644 index 0000000..fb1b360 --- /dev/null +++ b/public/mengyanote/Linux/busybox玩法总结.md @@ -0,0 +1,36 @@ +### 一句命令启动busybox的简单http服务器 + +```shell +busybox httpd -f -p 端口 -h 目录 +``` + +### 使用 `busybox netstat` 查看端口占用情况 + +- `-t`:显示 TCP 连接 +- `-u`:显示 UDP 连接 +- `-l`:只显示正在监听的端口 +- `-n`:显示数字形式的地址和端口号,而不进行域名解析 + +```shell +busybox netstat -tuln +``` + +### 启动busybox的ftp服务器 + +```shell +busybox ftp -d 目录 -p 端口 +busybox ftp -d 目录 #默认占用21端口 + +sudo mkdir -p 目录 +sudo chmod 755 目录 + +``` + +### 启动 `busybox` 的 Telnet 服务器(不安全的ssh) + +``` +busybox telnetd -l /bin/login +busybox telnetd -p 2323 -l /bin/login + +``` + diff --git a/public/mengyanote/Linux/crontab的使用.md b/public/mengyanote/Linux/crontab的使用.md new file mode 100644 index 0000000..3d0c02e --- /dev/null +++ b/public/mengyanote/Linux/crontab的使用.md @@ -0,0 +1,82 @@ +`crontab` 是一个用于在 Unix 和类 Unix 系统(如 Linux)中设置定时任务的工具。它允许用户根据指定的时间间隔安排脚本或命令的执行。以下是关于 `crontab` 使用方法的详细介绍和示例。 + +### 基本概念 +`crontab` 的配置文件由一系列行组成,每行代表一个定时任务,其基本格式如下: +```plaintext +* * * * * command +``` +这五个 `*` 分别代表分钟(0 - 59)、小时(0 - 23)、日期(1 - 31)、月份(1 - 12)和星期(0 - 7,其中 0 和 7 都代表星期日),`command` 是要执行的命令或脚本。 + +### 使用步骤 + +#### 1. 编辑 `crontab` 文件 +可以使用以下命令编辑当前用户的 `crontab` 文件: +```bash +crontab -e +``` +首次使用时,系统会提示选择一个文本编辑器,选择你熟悉的编辑器(如 `nano` 或 `vim`)即可。 + +#### 2. 添加定时任务 +在打开的 `crontab` 文件中添加定时任务,下面是一些具体的示例: + +##### 示例 1:每分钟执行一次命令 +```plaintext +* * * * * /usr/bin/echo "This is a test" >> /tmp/test.log +``` +这个任务会每分钟执行一次,将 `"This is a test"` 追加到 `/tmp/test.log` 文件中。 + +##### 示例 2:每小时的第 30 分钟执行一次命令 +```plaintext +30 * * * * /usr/bin/backup_script.sh +``` +这个任务会在每小时的第 30 分钟执行 `/usr/bin/backup_script.sh` 脚本。 + +##### 示例 3:每天凌晨 2 点执行一次命令 +```plaintext +0 2 * * * /usr/bin/daily_cleanup.sh +``` +这个任务会在每天凌晨 2 点执行 `/usr/bin/daily_cleanup.sh` 脚本。 + +##### 示例 4:每月 1 号的 3 点 15 分执行一次命令 +```plaintext +15 3 1 * * /usr/bin/monthly_report.sh +``` +这个任务会在每月 1 号的 3 点 15 分执行 `/usr/bin/monthly_report.sh` 脚本。 + +##### 示例 5:每周日的 18 点执行一次命令 +```plaintext +0 18 * * 0 /usr/bin/weekly_backup.sh +``` +这个任务会在每周日的 18 点执行 `/usr/bin/weekly_backup.sh` 脚本。 + +##### 示例 6:指定时间范围执行命令 +```plaintext +0 9-17 * * 1-5 /usr/bin/workday_check.sh +``` +这个任务会在周一至周五的 9 点到 17 点之间,每小时的整点执行 `/usr/bin/workday_check.sh` 脚本。 + +##### 示例 7:每隔一段时间执行命令 +```plaintext +*/15 * * * * /usr/bin/check_status.sh +``` +这个任务会每隔 15 分钟执行一次 `/usr/bin/check_status.sh` 脚本。 + +#### 3. 保存并退出 +编辑完成后,保存并退出文本编辑器。如果使用 `nano` 编辑器,按 `Ctrl + X`,然后按 `Y` 确认保存,最后按 `Enter` 键退出。如果使用 `vim` 编辑器,按 `Esc` 键,输入 `:wq` 并按 `Enter` 键保存并退出。 + +#### 4. 查看 `crontab` 文件内容 +可以使用以下命令查看当前用户的 `crontab` 文件内容: +```bash +crontab -l +``` + +#### 5. 删除 `crontab` 文件 +如果需要删除当前用户的所有定时任务,可以使用以下命令: +```bash +crontab -r +``` + +### 注意事项 +- **环境变量**:`crontab` 任务在执行时使用的环境变量可能与用户登录时不同。如果脚本依赖特定的环境变量,需要在脚本中明确设置。 +- **日志记录**:建议将定时任务的输出重定向到日志文件,以便后续排查问题。 +- **权限问题**:确保执行的命令或脚本具有足够的权限。 diff --git a/public/mengyanote/Linux/docker,LXC,qemu,k8s,chroot等的特点.md b/public/mengyanote/Linux/docker,LXC,qemu,k8s,chroot等的特点.md new file mode 100644 index 0000000..bfe4f2a --- /dev/null +++ b/public/mengyanote/Linux/docker,LXC,qemu,k8s,chroot等的特点.md @@ -0,0 +1,120 @@ + +以下从技术定义、核心原理、特点、区别及相互关系等方面,详细解析 **LXC、Docker、chroot、虚拟机、QEMU、K8s** 的概念及关联: + + +### **一、核心技术定义与原理** +#### 1. **chroot** +- **本质**:Linux 系统调用,用于修改进程的“根目录”(`/`),创建一个隔离的文件系统视图。 +- **原理**:通过 `chroot` 命令,指定一个新的根目录,进程只能访问该目录下的文件(类似“伪根”),但不隔离 CPU、内存、网络等资源。 +- **特点**: + - 最轻量的隔离,仅文件系统隔离,无资源限制。 + - 进程仍共享宿主机内核、进程空间、网络栈等。 + - 非完整容器,常用于调试、环境隔离(如构建跨平台程序)。 + +#### 2. **LXC(Linux Containers)** +- **本质**:基于 Linux 内核特性(`namespace` 命名空间 + `cgroups` 资源控制)的操作系统级容器。 +- **原理**: + - `namespace`:隔离进程、网络、文件系统、用户等资源(如 `PID namespace` 使容器内进程号独立)。 + - `cgroups`:限制容器的 CPU、内存、磁盘 I/O 资源使用。 +- **特点**: + - 共享宿主机内核,启动快(秒级),资源占用低。 + - 提供接近虚拟机的隔离性,但轻量高效。 + - 需要手动配置,侧重系统级隔离(如运行完整的 Linux 发行版)。 + +#### 3. **Docker** +- **本质**:基于容器技术的应用打包与部署平台,核心是容器运行时(`runc`,基于 Open Container Initiative 标准)。 +- **原理**: + - 继承 LXC 的 `namespace` 和 `cgroups`,但更上层,封装了镜像(`Image`)、容器(`Container`)、仓库(`Registry`)流程。 + - 通过镜像分层技术(UnionFS)实现快速打包,通过 `Docker Engine` 管理容器生命周期。 +- **特点**: + - 聚焦“应用容器化”,强调“一次构建,到处运行”。 + - 比 LXC 更易用(标准化 API、自动化部署),适合微服务、CI/CD。 + - 镜像生态丰富(Docker Hub),但隔离性略弱于 LXC(共享内核,依赖宿主机内核版本)。 + +#### 4. **虚拟机(Virtual Machine, VM)** +- **本质**:通过虚拟化技术模拟完整硬件环境,运行独立操作系统。 +- **分类与原理**: + - **全虚拟化**(如 VMware Workstation):Hypervisor 完全模拟硬件,Guest OS 无需修改。 + - **半虚拟化**(如 Xen):Guest OS 知道自己运行在虚拟机中,通过 Hypercall 与 Hypervisor 交互。 + - **硬件辅助虚拟化**(如 Intel VT-x):CPU 直接支持虚拟化,提升性能。 +- **特点**: + - 隔离性最强(独立内核、硬件资源),支持不同操作系统(如 Windows 跑在 Linux 宿主机上)。 + - 资源开销大(需模拟硬件,启动慢,内存/CPU 占用高)。 + - 适合需要完整 OS 环境的场景(如测试不同系统、遗留应用迁移)。 + +#### 5. **QEMU** +- **本质**:开源的通用模拟器和虚拟机监视器(Virtual Machine Monitor, VMM)。 +- **原理**: + - 单独使用时,通过软件模拟目标硬件(如在 x86 上运行 ARM 程序),性能较低。 + - 与 **KVM**(Kernel-based Virtual Machine,Linux 内核模块)结合时,利用硬件虚拟化技术(如 VT-x),成为高效的虚拟机引擎(QEMU-KVM)。 +- **特点**: + - 跨平台兼容性强,支持多种架构(x86、ARM、RISC-V 等)。 + - 是虚拟机技术的具体实现之一,常作为 KVM 的用户空间工具。 + +#### 6. **K8s(Kubernetes)** +- **本质**:容器编排平台,用于自动化部署、扩展和管理容器化应用。 +- **核心功能**: + - 调度容器到节点(Node),支持负载均衡、服务发现。 + - 处理容器的生命周期(重启、扩缩容、滚动更新)。 + - 提供资源配额、健康检查、故障恢复等机制。 +- **特点**: + - 不绑定特定容器运行时(支持 Docker、containerd、runc 等)。 + - 解决“大规模容器集群管理”问题,适合微服务架构、云原生应用。 + + +### **二、核心区别对比** +| **维度** | **chroot** | **LXC/Docker(容器)** | **虚拟机(含 QEMU-KVM)** | **K8s** | +|-------------------|------------------|------------------------|---------------------------|------------------------| +| **隔离级别** | 文件系统隔离 | 操作系统级隔离(内核共享) | 硬件级隔离(独立内核) | 编排管理层(不涉及底层隔离) | +| **资源共享** | 完全共享 | 共享宿主机内核 | 独立内核,硬件资源模拟 | 管理多个容器/节点的资源 | +| **启动时间** | 瞬间 | 秒级 | 分钟级(需启动 Guest OS) | 不涉及启动,管理已有容器 | +| **资源开销** | 极低 | 低(仅用户空间隔离) | 高(硬件模拟 + 完整 OS) | 额外控制平面开销 | +| **支持的 OS** | 同宿主机内核 | 同宿主机内核 | 任意 OS(如 Windows/Linux) | 不限制,管理容器化应用 | +| **核心目标** | 文件系统隔离 | 轻量应用隔离/部署 | 完整 OS 环境模拟 | 容器集群管理 | +| **典型用途** | 环境调试 | 应用打包、轻量部署 | 多系统测试、遗留应用兼容 | 大规模容器调度、微服务 | + + +### **三、相互关系** +#### 1. **技术栈分层** +``` +应用层(K8s) +├─ 容器运行时(Docker/LXC/containerd) +│ ├─ 内核特性(namespace/cgroups) +│ └─ chroot(基础文件系统隔离) +└─ 虚拟化层(虚拟机/QEMU-KVM) + └─ 硬件(CPU/内存/存储,支持 VT-x 等虚拟化技术) +``` + +#### 2. **具体关联** +- **chroot 与容器**: + chroot 是容器实现文件系统隔离的基础(如 Docker 镜像的根文件系统通过 chroot 挂载),但容器在此之上增加了 `namespace` 和 `cgroups` 实现完整隔离。 + +- **LXC 与 Docker**: + Docker 早期基于 LXC 开发,后转向自有运行时(`libcontainer`,现 `runc`),二者同属容器技术,但定位不同: + - LXC 偏向“系统级容器”(运行完整 Linux 发行版,如 Ubuntu 容器); + - Docker 偏向“应用级容器”(打包单个应用及其依赖,如 Node.js 服务)。 + +- **虚拟机与 QEMU**: + QEMU 是虚拟机的一种实现方式,单独使用时模拟硬件(慢),与 KVM 结合时利用硬件虚拟化(高效),属于虚拟机技术的底层引擎之一(类似 VirtualBox、VMware 的技术定位)。 + +- **K8s 与容器/虚拟机**: + - K8s 主要管理容器(如 Docker 容器),但也可通过虚拟机节点(Node)部署(每个 Node 可以是物理机或虚拟机)。 + - 容器运行在宿主机(物理机或虚拟机)上,K8s 不关心底层是物理机还是虚拟机,只调度容器到节点。 + + +### **四、应用场景总结** +- **chroot**:简单文件系统隔离(如构建跨版本软件、修复系统)。 +- **Docker/LXC**:轻量应用部署(微服务、Web 服务),追求资源效率和快速启动。 +- **虚拟机/QEMU-KVM**:需要完整 OS 隔离(如运行 Windows 应用、多租户隔离、硬件兼容性测试)。 +- **K8s**:大规模容器集群管理(微服务架构、弹性扩缩容、高可用部署)。 + + +### **五、核心总结** +- **隔离性**:虚拟机(强隔离,独立内核)> 容器(共享内核,OS 级隔离)> chroot(仅文件系统)。 +- **效率**:chroot/容器(高效)> 虚拟机(低效,因硬件模拟)。 +- **关系**: + - 容器技术(LXC/Docker)基于内核特性(namespace/cgroups),chroot 是其文件系统隔离的基础。 + - 虚拟机(如 QEMU-KVM)通过硬件虚拟化实现强隔离,与容器形成互补(容器适合同一 OS 下的应用隔离,虚拟机适合跨 OS 隔离)。 + - K8s 是容器的“上层管理工具”,不依赖特定容器运行时,聚焦集群调度与自动化。 + +理解这些技术的核心是明确其“隔离目标”和“资源模型”:容器追求轻量高效,虚拟机追求强隔离,K8s 解决规模化管理问题,而 chroot 是最基础的工具。根据需求选择合适的技术(如部署单个应用用 Docker,多 OS 环境用虚拟机,大规模集群用 K8s 编排容器)。 \ No newline at end of file diff --git a/public/mengyanote/Linux/docker配置.md b/public/mengyanote/Linux/docker配置.md new file mode 100644 index 0000000..ca7809a --- /dev/null +++ b/public/mengyanote/Linux/docker配置.md @@ -0,0 +1,16 @@ +QQ机器人(napcat) +docker run -d \ +-e NAPCAT_GID=$(id -g) \ +-e NAPCAT_UID=$(id -u) \ +-p 3000:3000 \ +-p 3001:3001 \ +-p 3002:6099 \ +--name napcat \ +--restart=always \ +mlikiowa/napcat-docker:latest + +微信机器人(gewe) +docker run -itd -v /shumengya/bin/wechatbot:/root/temp -p 2531:2531 -p 2532:2532 --privileged=true --name=gewe gewe /usr/sbin/init + + + diff --git a/public/mengyanote/Linux/frp配置.md b/public/mengyanote/Linux/frp配置.md new file mode 100644 index 0000000..7998ec1 --- /dev/null +++ b/public/mengyanote/Linux/frp配置.md @@ -0,0 +1,60 @@ +### 使用 yum 安装 systemd(CentOS/RHEL) +``` +yum install systemd +``` + + + +### 使用 apt 安装 systemd(Debian/Ubuntu) +``` +apt install systemd +sudo vim /etc/systemd/system/frps.service +``` + + + +### 服务名称,可自定义 +``` +Description = frp server +After = network.target syslog.target +Wants = network.target + +[Service] +Type = simple +``` + + +### 启动frps的命令,需修改为您的frps的安装路径 +``` +ExecStart = /path/to/frps -c /path/to/frps.toml + +[Install] +WantedBy = multi-user.target +``` + + + +### 启动frp +``` +sudo systemctl start frps +``` + + +### 停止frp +``` +sudo systemctl stop frps +``` + + +### 重启frp +``` +sudo systemctl restart frps +``` + + +### 查看frp状态 +``` +sudo systemctl status frps +sudo systemctl enable frps +``` + diff --git a/public/mengyanote/Linux相关/linux安装nodejs22.md b/public/mengyanote/Linux/linux安装nodejs22.md similarity index 100% rename from public/mengyanote/Linux相关/linux安装nodejs22.md rename to public/mengyanote/Linux/linux安装nodejs22.md diff --git a/public/mengyanote/Linux/nodejsmarkdown库.md b/public/mengyanote/Linux/nodejsmarkdown库.md new file mode 100644 index 0000000..4ff382a --- /dev/null +++ b/public/mengyanote/Linux/nodejsmarkdown库.md @@ -0,0 +1,39 @@ +1. **markdown-it**: + + - **简介**: 一个功能强大且可扩展的 Markdown 解析器,支持插件和自定义规则。 + - **安装**: 可以通过 npm 安装:`npm install markdown-it` + - **使用示例**: + ```javascript + const MarkdownIt = require('markdown-it'); + const md = new MarkdownIt(); + const result = md.render('# 你好,Markdown!'); + console.log(result); + ``` + +2. **marked**: + - **简介**: 一个快速、轻量级的 Markdown 解析器,支持自定义渲染器。 + - **安装**: 使用 npm 安装:`npm install marked` + - **使用示例**: + ```javascript + const marked = require('marked'); + const result = marked('# 你好,Markdown!'); + console.log(result); + ``` + +3. **remark**: + - **简介**: 一个强大的 Markdown 处理库,支持解析、检查和转换 Markdown 文档。 + - **安装**: 通过 npm 安装:`npm install remark remark-html` + - **使用示例**: + ```javascript + const remark = require('remark'); + const html = require('remark-html'); + + remark() + .use(html) + .process('# 你好,Markdown!', function (err, file) { + if (err) throw err; + console.log(String(file)); + }); + ``` + +这些库各有优点,选择哪个库取决于您的具体需求,比如性能、可扩展性、支持的特性等。如果你需要简单的解析和渲染,`marked` 和 `markdown-it` 都是不错的选择;如果需要更多的可扩展性和插件支持,`remark` 可能更适合。 \ No newline at end of file diff --git a/public/mengyanote/Linux/screen常用指令.md b/public/mengyanote/Linux/screen常用指令.md new file mode 100644 index 0000000..9d26e5a --- /dev/null +++ b/public/mengyanote/Linux/screen常用指令.md @@ -0,0 +1,69 @@ +## `screen`命令简介 + +`screen` 是一个窗口管理器,允许用户在一个单一的终端窗口中运行多个会话。它特别适用于需要长时间运行的进程,因为即使网络连接断开,进程也会继续运行。 + +## 常用命令 + +### 启动和使用 + +- **启动一个新的screen会话** + ```bash + screen + ``` + 或者为会话命名: + ```bash + screen -S session_name + ``` + +- **列出所有screen会话** + ```bash + screen -ls + ``` + +- **重新连接到一个已存在的screen会话** + ```bash + screen -r session_name + ``` + +- **分离当前会话(让会话在后台继续运行)** + 按下 `Ctrl + A` 然后按 `D`。 + +- **终止一个screen会话** + 在会话中按下 `Ctrl + D` 或者输入 `exit`。 + +### 会话管理 + +- **强制连接到一个会话** + 如果有多个会话在运行,使用: + ```bash + screen -r -d session_name + ``` + 这将断开该会话的其他连接并连接到它。 + +- **多窗口管理** + - 创建新窗口:`Ctrl + A` 然后 `C` + - 切换窗口:`Ctrl + A` 然后 `N`(下一个),`Ctrl + A` 然后 `P`(上一个) + - 列出所有窗口:`Ctrl + A` 然后 `"`(双引号) + +### 会话命名 + +- **重命名当前窗口** + 按下 `Ctrl + A` 然后 `A`,输入新的名称。 + +## 配置文件 + +- **自定义screen** + 可以通过编辑 `~/.screenrc` 文件进行配置。例如: + ```bash + # 开启多窗口状态栏 + hardstatus on + hardstatus alwayslastline + hardstatus string "%{= kG}%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<" + ``` + +## 提示 + +- 使用 `screen` 可以有效防止因网络不稳定导致的会话中断。 +- 熟练掌握快捷键可以大大提高效率。 +- 对于需要长期运行的任务,如编译或数据处理,`screen` 是一个非常有用的工具。 + diff --git a/public/mengyanote/Linux/systemctl命令详细总结-豆包.md b/public/mengyanote/Linux/systemctl命令详细总结-豆包.md new file mode 100644 index 0000000..61e96ec --- /dev/null +++ b/public/mengyanote/Linux/systemctl命令详细总结-豆包.md @@ -0,0 +1,283 @@ + +### Linux `systemctl` 命令常用用法总结 + + +#### **一、服务管理(核心功能)** +`systemctl` 主要用于管理系统服务(`.service` 文件),支持启动、停止、重启、查看状态、设置开机启动等操作。 + +##### 1. 服务状态操作 +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 启动服务 | `systemctl start <服务名>` | 启动指定服务(仅临时生效,重启后不保留) | +| 停止服务 | `systemctl stop <服务名>` | 停止指定服务 | +| 重启服务 | `systemctl restart <服务名>` | 重启服务(若服务未运行则启动) | +| 重新加载配置 | `systemctl reload <服务名>` | 重新加载服务配置文件(不重启服务,适用于支持此功能的服务,如 Nginx) | +| 平滑重启(优雅重启)| `systemctl try-restart <服务名>` | 仅在服务运行时重启,避免报错 | + +##### 2. 服务状态查询 +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 查看状态 | `systemctl status <服务名>` | 显示服务运行状态、日志及依赖关系(按 `Q` 退出) | +| 简洁状态 | `systemctl is-active <服务名>` | 仅显示服务是否激活(active/running) | +| 查看是否启用开机启动| `systemctl is-enabled <服务名>` | 显示服务是否设置为开机启动(enabled/disabled) | +| 列出所有服务 | `systemctl list-units --type=service` | 列出所有运行中的服务 | +| 列出所有服务(含未激活)| `systemctl list-units --type=service --all` | 显示所有服务,包括未激活的(状态为 inactive/failed 等) | +| 列出失败的服务 | `systemctl --failed --type=service` | 查看启动失败的服务 | + +##### 3. 开机启动管理 +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 启用开机启动 | `systemctl enable <服务名>` | 设置服务开机自动启动(永久生效,关联到默认运行目标) | +| 禁用开机启动 | `systemctl disable <服务名>` | 取消服务开机启动 | +| 临时启用(仅本次启动)| `systemctl enable --now <服务名>` | 立即启动服务并设置开机启动 | +| 临时禁用(停止并取消启动)| `systemctl disable --now <服务名>` | 立即停止服务并取消开机启动 | + +##### 4. 服务依赖与依赖关系 +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 查看依赖关系 | `systemctl list-dependencies <服务名>` | 显示服务的依赖项(依赖它的服务 + 它依赖的服务) | +| 查看直接依赖 | `systemctl list-dependencies --reverse <服务名>` | 仅显示依赖该服务的其他服务 | + + +#### **二、系统状态与控制** +##### 1. 系统基本状态 +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 查看系统运行时间 | `systemctl uptime` | 显示系统已运行时间(类似 `uptime` 命令) | +| 查看启动耗时 | `systemctl time` | 显示系统启动总耗时及各阶段(内核、用户空间、服务)耗时 | +| 查看登录会话 | `systemctl list-sessions` | 列出当前登录的用户会话 | + +##### 2. 电源管理(需管理员权限) +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 关机 | `systemctl poweroff` | 立即关机 | +| 重启 | `systemctl reboot` | 立即重启 | +| 休眠(挂起到硬盘) | `systemctl hibernate` | 系统进入休眠状态 | +| 睡眠(挂起到内存) | `systemctl suspend` | 系统进入睡眠状态(低功耗,断电数据丢失) | +| 混合休眠 | `systemctl hybrid-sleep` | 同时休眠到内存和硬盘,结合两者优势 | +| 取消挂起/休眠 | `systemctl wakeup` | 唤醒系统(需配合定时器使用) | + +##### 3. 运行目标(替代传统运行级别) +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 查看当前目标 | `systemctl get-default` | 显示默认运行目标(如 `graphical.target` 对应图形界面) | +| 切换目标 | `systemctl isolate <目标名>` | 切换到指定目标(如 `multi-user.target` 为无图形多用户模式) | +| 设置默认目标 | `systemctl set-default <目标名>` | 设置开机默认目标(需管理员权限) | + +**常用目标对应关系**: +- `graphical.target`:图形界面(对应传统运行级别 5) +- `multi-user.target`:无图形多用户模式(对应级别 3) +- `rescue.target`:单用户救援模式(对应级别 1) +- `emergency.target`:紧急模式(无文件系统挂载,仅基本命令) + + +#### **三、定时器管理(systemd.timer)** +`systemctl` 可管理定时任务(替代传统 `cron`),需配合 `.timer` 文件使用。 + +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 列出所有定时器 | `systemctl list-timers` | 显示激活的定时器及其下一次触发时间 | +| 查看定时器状态 | `systemctl status <定时器名>` | 显示定时器详细状态及日志 | +| 启用/禁用定时器 | `systemctl enable/disable <定时器名>` | 控制定时器是否开机启动 | +| 立即触发定时器任务 | `systemctl start <定时器名>` | 强制立即执行定时器关联的服务 | + + +#### **四、资源控制与限制(高级功能)** +可对服务设置 CPU、内存、IO 等资源限制(需在服务文件中配置,或临时生效)。 + +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 设置 CPU 核心限制 | `systemctl set-property <服务名> CPUAffinity=0,1` | 限制服务仅运行在 CPU 0 和 1 核心 | +| 设置内存上限 | `systemctl set-property <服务名> MemoryMax=1G` | 限制服务最大内存使用量为 1GB | +| 恢复默认资源配置 | `systemctl unset-property <服务名> CPUAffinity MemoryMax` | 清除已设置的资源限制 | + + +#### **五、日志相关(结合 journalctl)** +| 操作 | 命令 | 说明 | +|---------------------|---------------------------------------|----------------------------------------------------------------------| +| 查看服务日志 | `systemctl status <服务名> -l` | 显示服务状态并附带日志(`-l` 展开完整日志) | +| 实时监控日志 | `journalctl -u <服务名> -f` | 实时追踪服务日志(需结合 `journalctl` 命令) | +| 查看历史日志 | `journalctl -u <服务名> --since "2025-05-01"` | 查看指定时间后的服务日志 | + + +#### **六、常用选项与技巧** +- **通配符匹配**: + 可使用通配符管理同类服务,例如: + ```bash + systemctl start nginx*.service # 启动所有以 nginx 开头的服务 + systemctl stop *.timer # 停止所有定时器服务 + ``` + +- **强制操作**: + `--force` 用于强制停止/重启服务(可能终止进程): + ```bash + systemctl --force stop <服务名> + ``` + +- **临时生效(不修改配置)**: + 使用 `--now` 可立即执行操作并关联开机启动(或取消): + ```bash + systemctl enable --now <服务名> # 启动并启用开机启动 + systemctl disable --now <服务名> # 停止并禁用开机启动 + ``` + +- **查看帮助**: + ```bash + systemctl --help # 查看全局帮助 + systemctl help <子命令> # 查看子命令详细用法(如 systemctl help start) + ``` + + +#### **七、示例场景** +1. **管理 Nginx 服务**: + ```bash + systemctl start nginx # 启动 Nginx + systemctl enable nginx # 设置开机启动 + systemctl status nginx # 查看运行状态 + systemctl reload nginx # 重新加载配置 + ``` + +2. **系统关机与重启**: + ```bash + systemctl reboot # 立即重启 + systemctl poweroff # 立即关机 + systemctl suspend # 进入睡眠 + ``` + +3. **设置默认运行目标**: + ```bash + systemctl set-default multi-user.target # 设为无图形多用户模式 + systemctl isolate rescue.target # 进入单用户救援模式 + ``` + + +### 总结 +`systemctl` 是 systemd 生态的核心工具,覆盖服务管理、系统控制、定时任务、资源限制等功能。熟练掌握其常用命令可高效管理 Linux 系统服务与状态,替代传统 SysVinit 的 `service`、`chkconfig` 等工具。建议结合 `journalctl` 分析服务日志,通过服务文件(`/etc/systemd/system/`)自定义复杂配置。`systemctl` 是 Linux 系统中用于控制 `systemd` 系统和服务管理器的命令。以下是 `systemctl` 命令的一些常用用法总结: + +### 1. 服务管理 +#### 启动服务 +```bash +systemctl start <服务名> +``` +例如,启动 `httpd` 服务: +```bash +systemctl start httpd +``` + +#### 停止服务 +```bash +systemctl stop <服务名> +``` +例如,停止 `httpd` 服务: +```bash +systemctl stop httpd +``` + +#### 重启服务 +```bash +systemctl restart <服务名> +``` +例如,重启 `httpd` 服务: +```bash +systemctl restart httpd +``` + +#### 重新加载服务配置 +```bash +systemctl reload <服务名> +``` +例如,重新加载 `nginx` 服务配置: +```bash +systemctl reload nginx +``` + +#### 查看服务状态 +```bash +systemctl status <服务名> +``` +例如,查看 `httpd` 服务状态: +```bash +systemctl status httpd +``` + +### 2. 服务的开机自启管理 +#### 设置服务开机自启 +```bash +systemctl enable <服务名> +``` +例如,设置 `httpd` 服务开机自启: +```bash +systemctl enable httpd +``` + +#### 禁止服务开机自启 +```bash +systemctl disable <服务名> +``` +例如,禁止 `httpd` 服务开机自启: +```bash +systemctl disable httpd +``` + +#### 查看服务是否开机自启 +```bash +systemctl is-enabled <服务名> +``` +例如,查看 `httpd` 服务是否开机自启: +```bash +systemctl is-enabled httpd +``` + +### 3. 系统管理 +#### 重启系统 +```bash +systemctl reboot +``` + +#### 关机 +```bash +systemctl poweroff +``` + +#### 挂起系统 +```bash +systemctl suspend +``` + +#### 休眠系统 +```bash +systemctl hibernate +``` + +#### 混合休眠(挂起并休眠) +```bash +systemctl hybrid-sleep +``` + +### 4. 查看系统状态 +#### 查看系统当前运行级别 +```bash +systemctl get-default +``` + +#### 设置系统默认运行级别 +```bash +systemctl set-default <目标运行级别> +``` +例如,设置系统默认运行级别为多用户模式: +```bash +systemctl set-default multi-user.target +``` + +### 5. 查看服务列表 +#### 查看所有已激活的服务 +```bash +systemctl list-units --type=service --state=active +``` + +#### 查看所有服务(包括未激活的) +```bash +systemctl list-units --type=service --all +``` + +这些是 `systemctl` 命令的一些常用用法,掌握这些用法可以帮助你有效地管理 Linux 系统中的服务和系统状态。 \ No newline at end of file diff --git a/public/mengyanote/Linux相关/ubuntu设置root登陆.md b/public/mengyanote/Linux/ubuntu设置root登陆.md similarity index 100% rename from public/mengyanote/Linux相关/ubuntu设置root登陆.md rename to public/mengyanote/Linux/ubuntu设置root登陆.md diff --git a/public/mengyanote/Linux/wlan0简单介绍.md b/public/mengyanote/Linux/wlan0简单介绍.md new file mode 100644 index 0000000..3423111 --- /dev/null +++ b/public/mengyanote/Linux/wlan0简单介绍.md @@ -0,0 +1,45 @@ +### 1. 网络接口类型及其作用 +- **lo(回环接口)**: + - 用于系统内部通信,IP地址通常为 `127.0.0.1`,子网掩码为 `255.0.0.0`。 + - 主要用于本地测试,如运行本地服务器(如HTTPD)时,只能在本机访问。 + +- **eth0(以太网接口)**: + - 代表第一块物理网卡,`HWaddr` 表示网卡的MAC地址,`inet addr` 表示IP地址。 + - 支持IPv4和IPv6,通常用于有线网络连接。 + - 可以通过 `ifconfig` 查看网卡的接收和发送数据包的情况。 + +- **br0(网桥接口)**: + - 用于在链路层连接多个网络接口(如eth0),实现帧的转发。 + - 常用于虚拟化环境中,连接多个虚拟网络接口。 + +- **wlan0(无线接口)**: + - 代表无线网卡,类似于eth0,但用于无线网络连接。 + - 需要驱动程序支持,配置方式与以太网接口类似。 + +### 2. `ifconfig` 命令的常见操作 +Windows命令为:ipconfig + +- **启动/关闭网卡**: + - `ifconfig eth0 up`:启动网卡。 + - `ifconfig eth0 down`:关闭网卡。 + +- **配置/删除IPv6地址**: + - `ifconfig eth0 add `:为网卡添加IPv6地址。 + - `ifconfig eth0 del `:删除网卡的IPv6地址。 + +- **修改MAC地址**: + - `ifconfig eth0 hw ether `:修改网卡的MAC地址。 + +- **修改IP地址**: + - `ifconfig eth0 `:修改网卡的IP地址。 + - `ifconfig eth0 netmask <子网掩码>`:修改IP地址并设置子网掩码。 + - `ifconfig eth0 netmask <子网掩码> broadcast <广播地址>`:同时设置IP地址、子网掩码和广播地址。 + +- **设置最大传输单元(MTU)**: + - `ifconfig eth0 mtu <字节数>`:设置网卡的最大传输单元大小。 + +### 3. 注意事项 +- 使用 `ifconfig` 命令时,尤其是在远程服务器上操作时,需谨慎关闭网卡,否则可能导致无法远程连接。 +- 虚拟网卡和物理网卡的区别在于虚拟网卡由系统或应用程序创建,不依赖于物理硬件。 + +这篇文章详细介绍了 `ifconfig` 命令的使用方法以及常见网络接口的配置和功能,适合需要管理和调试网络接口的用户参考。 \ No newline at end of file diff --git a/public/mengyanote/Linux/我想全局执行某个sh脚本,该放在Linux哪个目录.md b/public/mengyanote/Linux/我想全局执行某个sh脚本,该放在Linux哪个目录.md new file mode 100644 index 0000000..f3412ca --- /dev/null +++ b/public/mengyanote/Linux/我想全局执行某个sh脚本,该放在Linux哪个目录.md @@ -0,0 +1,79 @@ +要使得某个 `.sh` 脚本能够在系统中全局执行,你可以将该脚本放在 **系统的 `PATH` 路径中**,使其在任何地方都能被执行。常见的目录有: + +### 1. **`/usr/local/bin/`** +这是推荐的目录,因为它是用来放置系统管理员手动安装或编译的软件及脚本的。脚本放在这个目录中,可以确保它对所有用户可用,并且不会与系统自带的命令冲突。 + +步骤: +1. 将你的 `.sh` 脚本复制到 `/usr/local/bin/` 目录下。 + + ```bash + sudo cp your_script.sh /usr/local/bin/ + ``` + +2. 赋予脚本执行权限: + + ```bash + sudo chmod +x /usr/local/bin/your_script.sh + ``` + +3. 确保脚本能被执行,可以通过命令行直接调用(例如 `your_script.sh`),无需指定路径。 + +### 2. **`/usr/bin/`** +这个目录通常用于系统范围内的二进制文件,和 `/usr/local/bin/` 类似。但是,建议将自定义脚本放在 `/usr/local/bin/` 目录下,因为 `/usr/bin/` 通常用于通过包管理器安装的系统级命令。 + +步骤: +1. 将脚本复制到 `/usr/bin/` 目录: + + ```bash + sudo cp your_script.sh /usr/bin/ + ``` + +2. 赋予执行权限: + + ```bash + sudo chmod +x /usr/bin/your_script.sh + ``` + +### 3. **`/bin/`**(不推荐) +`/bin/` 目录通常用于存放系统核心命令和工具,普通用户通常不建议将自定义脚本放在这个目录中,除非它们确实是系统必需的命令。通常会将脚本放置在 `/usr/local/bin/` 或 `/usr/bin/` 中。 + +### 4. **用户特定的目录(例如 `/home/username/bin/`)** +如果你只想为某个特定用户设置全局脚本,而不是所有用户可以访问的脚本,你可以将脚本放在该用户的 `~/bin/` 目录下(如果该目录不存在,可以自己创建)。确保将 `~/bin/` 添加到用户的 `PATH` 环境变量中。 + +步骤: +1. 创建 `~/bin/` 目录(如果没有的话): + + ```bash + mkdir -p ~/bin + ``` + +2. 将脚本复制到 `~/bin/` 目录: + + ```bash + cp your_script.sh ~/bin/ + ``` + +3. 赋予执行权限: + + ```bash + chmod +x ~/bin/your_script.sh + ``` + +4. 编辑 `~/.bashrc` 或 `~/.profile`,将 `~/bin/` 添加到 `PATH`: + + ```bash + export PATH=$PATH:~/bin + ``` + +5. 使 `~/.bashrc` 变更生效: + + ```bash + source ~/.bashrc + ``` + +### 总结 +- **最推荐的目录:** `/usr/local/bin/`,适用于系统范围内的自定义脚本。 +- **其他可选目录:** `/usr/bin/`(不推荐),如果需要放系统级命令可以选择该目录。 +- **特定用户的脚本:** 用户自己的 `~/bin/` 目录。 + +将脚本放入上述目录,并设置执行权限后,你就可以在系统中的任何地方执行该脚本了。如果有任何问题,请随时告知! \ No newline at end of file diff --git a/public/mengyanote/Linux/手动配置alist.md b/public/mengyanote/Linux/手动配置alist.md new file mode 100644 index 0000000..5650e80 --- /dev/null +++ b/public/mengyanote/Linux/手动配置alist.md @@ -0,0 +1,47 @@ +```shell +# 解压下载的文件,得到可执行文件: +tar -zxvf alist-xxxx.tar.gz +# 授予程序执行权限: +chmod +x alist +# 运行程序 +./alist server + +# 获得管理员信息 以下两个不同版本,新版本也有随机生成和手动设置 +# 低于v3.25.0版本 +./alist admin + +# 高于v3.25.0版本 +# 随机生成一个密码 +./alist admin random +# 手动设置一个密码 `NEW_PASSWORD`是指你需要设置的密码 +./alist admin set NEW_PASSWORD + +``` + + + +使用任意方式编辑 `/usr/lib/systemd/system/alist.service` 并添加如下内容,其中 path_alist 为 AList 所在的路径 + +```shell +[Unit] +Description=alist +After=network.target + +[Service] +Type=simple +WorkingDirectory=path_alist +ExecStart=path_alist/alist server +Restart=on-failure + +[Install] +WantedBy=multi-user.target + +``` + +然后,执行 systemctl daemon-reload 重载配置,现在你可以使用这些命令来管理程序: +**• 启动: systemctl start alist** +**• 关闭: systemctl stop alist** +**• 配置开机自启: systemctl enable alist** +**• 取消开机自启: systemctl disable alist** +**• 状态: systemctl status alist** +**• 重启: systemctl restart alist** \ No newline at end of file diff --git a/public/mengyanote/Linux相关/把Ubuntu镜像源切换到阿里云.md b/public/mengyanote/Linux/把Ubuntu镜像源切换到阿里云.md similarity index 100% rename from public/mengyanote/Linux相关/把Ubuntu镜像源切换到阿里云.md rename to public/mengyanote/Linux/把Ubuntu镜像源切换到阿里云.md diff --git a/public/mengyanote/Linux/构建最小Linux系统.md b/public/mengyanote/Linux/构建最小Linux系统.md new file mode 100644 index 0000000..abfae54 --- /dev/null +++ b/public/mengyanote/Linux/构建最小Linux系统.md @@ -0,0 +1,123 @@ +以下是手动构建一个极简Linux系统(约10MB)的完整步骤,包含内核和基础用户空间: + +### 1. 准备环境(Ubuntu/Debian示例) +```bash +sudo apt install -y build-essential libncurses-dev bison flex qemu-system-x86 +mkdir tiny_linux && cd tiny_linux +``` + +### 2. 编译定制化内核(5MB) +```bash +# 下载最新稳定版内核 +wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.8.tar.xz +tar xf linux-6.9.8.tar.xz && cd linux-6.9.8 + +# 最小化配置 +make defconfig +make menuconfig # 手动调整以下选项: +# General setup +# [ ] Configure standard kernel features (expert users) +# Device Drivers +# [*] Block devices > RAM block device support (16MB) +# [*] Network device support > Ethernet driver support > Intel(R) PRO/1000 +# File systems +# [*] Ext2 +# [ ] Btrfs +# [ ] XFS +# [*] Enable loadable module support # 禁用 + +# 编译内核 +make -j$(nproc) bzImage +``` + +### 3. 创建最小根文件系统(5MB) +```bash +cd .. +mkdir rootfs && cd rootfs + +# 使用BusyBox构建基础工具 +wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2 +tar xf busybox-1.36.1.tar.bz2 && cd busybox-1.36.1 +make defconfig +make menuconfig # 选择静态编译: +# Settings -> Build Options -> [*] Build static binary + +make -j$(nproc) && make install +cd _install + +# 创建必要目录 +mkdir -p proc sys dev etc/init.d + +# 创建启动脚本 +cat > etc/init.d/rcS <<EOF +#!/bin/sh +mount -t proc none /proc +mount -t sysfs none /sys +/sbin/mdev -s +EOF +chmod +x etc/init.d/rcS + +# 创建文件系统镜像 +dd if=/dev/zero of=rootfs.img bs=1M count=16 +mkfs.ext2 -F rootfs.img +sudo mount -o loop rootfs.img /mnt +sudo cp -r ./* /mnt +sudo umount /mnt +``` + +### 4. 使用QEMU启动测试 +```bash +qemu-system-x86_64 \ + -kernel ../linux-6.9.8/arch/x86/boot/bzImage \ + -hda rootfs.img \ + -append "root=/dev/ram0 console=ttyS0" \ + -nographic +``` + +### 5. 可选优化(缩减体积) +```bash +# 使用UPX压缩可执行文件 +sudo apt install upx +find . -type f -executable | xargs upx --best + +# 移除调试符号 +strip --strip-all busybox + +# 使用musl libc替代glibc +wget https://musl.libc.org/releases/musl-1.2.4.tar.gz +tar xzf musl-1.2.4.tar.gz && cd musl-1.2.4 +./configure --prefix=/usr/local/musl && make && sudo make install +``` + +### 6. 构建结果 +``` +├── linux-6.9.8 +│ └── arch/x86/boot/bzImage # 内核文件 +├── rootfs +│ ├── bin # 基础命令 +│ ├── rootfs.img # 根文件系统镜像 +│ └── etc # 配置文件 +``` + +### 替代方案:使用Buildroot快速构建 +```bash +git clone https://github.com/buildroot/buildroot +cd buildroot +make menuconfig # 选择: +# Target options -> Target Architecture = x86_64 +# System configuration -> Root filesystem overlay = ../rootfs +# Kernel -> Linux Kernel = 6.9.8 +make -j$(nrep) +``` + +### 系统特性对比 + +| 组件 | 手动构建 | Buildroot构建 | +| ------------ | -------- | ------------- | +| 启动时间 | <1s | <1.5s | +| 内存占用 | 8MB | 12MB | +| 可执行文件数 | 12个 | 25个 | +| 支持网络 | 否 | 是 | +| 支持动态库 | 否 | 可选 | + +建议从手动构建开始学习原理,实际项目使用Buildroot可节省90%时间。后续可添加OpenSSH(+1.2MB)或Web服务器(+0.8MB)等组件扩展功能。 \ No newline at end of file diff --git a/public/mengyanote/Linux/某安卓板子不知名初始化脚本.md b/public/mengyanote/Linux/某安卓板子不知名初始化脚本.md new file mode 100644 index 0000000..f2cfe48 --- /dev/null +++ b/public/mengyanote/Linux/某安卓板子不知名初始化脚本.md @@ -0,0 +1,5 @@ +adb push busybox /tmp +adb shell +cd /tmp +chmod 777 * +./busybox ifconfig wlan0 up \ No newline at end of file diff --git a/public/mengyanote/Linux相关/树萌芽常用Linux命令集合.md b/public/mengyanote/Linux/树萌芽常用Linux命令集合.md similarity index 100% rename from public/mengyanote/Linux相关/树萌芽常用Linux命令集合.md rename to public/mengyanote/Linux/树萌芽常用Linux命令集合.md diff --git a/public/mengyanote/Linux/树萌芽的局域网中网IP分配.md b/public/mengyanote/Linux/树萌芽的局域网中网IP分配.md new file mode 100644 index 0000000..6ff2a6e --- /dev/null +++ b/public/mengyanote/Linux/树萌芽的局域网中网IP分配.md @@ -0,0 +1,66 @@ +# IP分段:192.168.31.1-192.168.31.255 + +## ------------------------------------------------------------ + +## 10 20 30 40 50 60 70 + +## 66 99 88 11 22 33 44 55 + +## 110 120 119 + +## 111 222 + +## 233 + +## ------------------------------------------------------------ + +## x86电脑系列 + +#### Windows11 + +#### Linux Mint + +#### 树萌芽NAS(大萌芽):233 + + + +## 安卓手机系列 + +#### 红萌芽盘 :222 + +#### 黑萌芽盘 :111 + +#### 小萌芽盘: + + + +#### vivo平板 + +#### OPPO手机 + + + +## 随身WiFi系列 + +#### UFI1003 + +#### UZ801 + +#### UZ901 + +#### UFI100C 目前有9个 + +### IP:11 - 99 + + + +#### + +#### + +#### + +#### + + + diff --git a/public/mengyanote/Linux/编译alist.md b/public/mengyanote/Linux/编译alist.md new file mode 100644 index 0000000..a112463 --- /dev/null +++ b/public/mengyanote/Linux/编译alist.md @@ -0,0 +1,133 @@ +以下是编译 Alist 前后端的详细步骤: + +--- + +### **1. 准备工作** +#### 环境要求: +- **Go 1.16+** (后端依赖) +- **Node.js 14+** (前端依赖) +- **Git** (代码管理) +- **Yarn** 或 **npm** (前端包管理) + +#### 安装依赖: +```bash +# 安装 Go (以 Linux 为例) +wget https://golang.org/dl/go1.20.linux-amd64.tar.gz +sudo tar -C /usr/local -xzf go1.20.linux-amd64.tar.gz +export PATH=$PATH:/usr/local/go/bin + +# 安装 Node.js (推荐使用 nvm) +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash +nvm install 16 +nvm use 16 + +# 安装 Yarn +npm install -g yarn +``` + +--- + +### **2. 后端编译** +#### 获取源码: +```bash +git clone https://github.com/alist-org/alist.git +cd alist +``` + +#### 安装依赖并编译: +```bash +# 进入后端目录 +cd alist + +# 下载 Go 依赖 +go mod download + +# 编译(默认生成当前系统的可执行文件) +go build -o alist main.go + +# 交叉编译(示例:编译 Linux AMD64) +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o alist-linux-amd64 main.go +``` + +编译完成后,会在当前目录生成可执行文件 `alist`(或指定名称)。 + +--- + +### **3. 前端编译** +#### 进入前端目录: +```bash +cd ../web # 假设源码根目录为 alist/ +``` + +#### 安装依赖并构建: +```bash +yarn install # 或使用 npm install +yarn build # 或使用 npm run build +``` + +构建完成后,静态文件会生成在 `dist` 目录中。 + +--- + +### **4. 整合前后端** +将前端构建的静态文件复制到后端目录的 `public` 文件夹中: +```bash +# 创建 public 目录(如果不存在) +mkdir -p ../alist/public + +# 复制前端文件 +cp -r dist/* ../alist/public/ +``` + +--- + +### **5. 运行 Alist** +```bash +# 进入后端目录 +cd ../alist + +# 赋予执行权限(Linux/macOS) +chmod +x alist + +# 启动服务 +./alist server +``` + +默认访问地址:`http://localhost:5244` + +--- + +### **6. 高级配置** +1. **修改配置文件** + 首次运行后会在程序目录生成 `data/config.json`,可按需修改端口、存储驱动等。 + +2. **自定义前端变量** + 在 `web/.env` 文件中修改环境变量(如 API 地址): + ```env + VITE_API_URL=http://your-domain.com:5244 + ``` + +3. **Docker 编译(可选)** + Alist 官方提供 Docker 镜像,也可自行构建: + ```bash + docker build -t alist . + ``` + +--- + +### **常见问题** +1. **依赖安装失败** + - 检查网络是否通畅(尤其是 Go 依赖可能需要代理)。 + - 确保 Node.js 和 Go 版本符合要求。 + +2. **前端构建报错** + - 清理缓存:`yarn cache clean` 或 `rm -rf node_modules`。 + - 检查 `web/package.json` 中的依赖版本是否冲突。 + +3. **启动后无法访问** + - 检查防火墙是否开放端口(默认 `5244`)。 + - 确认 `config.json` 中 `address` 设置为 `0.0.0.0`(允许外部访问)。 + +--- + +通过以上步骤,你可以成功编译并运行 Alist 的完整服务。如需更多定制化配置,建议参考 [Alist 官方文档](https://alist.nn.ci/)。 \ No newline at end of file diff --git a/public/mengyanote/Linux/编译busybox步骤.md b/public/mengyanote/Linux/编译busybox步骤.md new file mode 100644 index 0000000..42d4266 --- /dev/null +++ b/public/mengyanote/Linux/编译busybox步骤.md @@ -0,0 +1,27 @@ +```shell +pkg update && pkg upgrade +pkg install git make clang +apt install gcc +export CC=clang +apt install build-essential +pkg install ncurses-dev +git clone https://git.busybox.net/busybox +cd busybox +make menuconfig +#make -j$(nproc) +make -j4 +make install + + +``` + +```shell +#可选创建符号链接 +PREFIX=$HOME/.local +mkdir -p $PREFIX/bin +for applet in $(./busybox --list); do + ln -s $PREFIX/bin/busybox $PREFIX/bin/$applet +done + +``` + diff --git a/public/mengyanote/Linux/飞牛os切换root.md b/public/mengyanote/Linux/飞牛os切换root.md new file mode 100644 index 0000000..ecbc2bd --- /dev/null +++ b/public/mengyanote/Linux/飞牛os切换root.md @@ -0,0 +1,10 @@ +1.打开飞牛ssh +2.ssh软件连接上飞牛(飞牛账号) +3.给root新建密码:sudo passwd root 回车 +再次输入飞牛密码 +再输入密码(root密码)两次(不回显,每次输完回车) +4.配置权限文件:sudo nano /etc/ssh/sshd_config 回车 +5.光标移动到:permitrootlogin no 把no 改为yes +6.ctrl+o(写入文本)回车 ctrl+x(退出) 重启服务器:sudo reboot +7.重启ssh服务:sudo service sshd restart +8.用命令切换root账号:su -(或者sudo su -)还要输入一次目前飞牛密码回车就切换root了。 \ No newline at end of file diff --git a/public/mengyanote/我的世界/我的世界常用命令.md b/public/mengyanote/Minecraft/Minecraft常用命令.md similarity index 100% rename from public/mengyanote/我的世界/我的世界常用命令.md rename to public/mengyanote/Minecraft/Minecraft常用命令.md diff --git a/public/mengyanote/Obsidion相关/Obsidion美化.md b/public/mengyanote/Obsidion/Obsidion美化.md similarity index 100% rename from public/mengyanote/Obsidion相关/Obsidion美化.md rename to public/mengyanote/Obsidion/Obsidion美化.md diff --git a/public/mengyanote/ignore.json b/public/mengyanote/ignore.json new file mode 100644 index 0000000..d6325da --- /dev/null +++ b/public/mengyanote/ignore.json @@ -0,0 +1,14 @@ +{ + "ignore": [ + ".obsidian", + ".trash", + "华为ICT", + "鉴政", + "临时解决方案", + "树萌芽的小本本", + "树萌芽制作的小东西", + "树萌芽の小想法", + "西南石油大学", + "临时" + ] +} diff --git a/public/mengyanote/临时解决方案/Code-Server配置.md b/public/mengyanote/临时/Code-Server配置.md similarity index 100% rename from public/mengyanote/临时解决方案/Code-Server配置.md rename to public/mengyanote/临时/Code-Server配置.md diff --git a/public/mengyanote/临时解决方案/HomePage美化配置.md b/public/mengyanote/临时/HomePage美化配置.md similarity index 100% rename from public/mengyanote/临时解决方案/HomePage美化配置.md rename to public/mengyanote/临时/HomePage美化配置.md diff --git a/public/mengyanote/临时解决方案/IDE快捷键.md b/public/mengyanote/临时/IDE快捷键.md similarity index 100% rename from public/mengyanote/临时解决方案/IDE快捷键.md rename to public/mengyanote/临时/IDE快捷键.md diff --git a/public/mengyanote/临时解决方案/Termux安装nodejs失败.md b/public/mengyanote/临时/Termux安装nodejs失败.md similarity index 100% rename from public/mengyanote/临时解决方案/Termux安装nodejs失败.md rename to public/mengyanote/临时/Termux安装nodejs失败.md diff --git a/public/mengyanote/临时解决方案/临时.md b/public/mengyanote/临时/临时.md similarity index 100% rename from public/mengyanote/临时解决方案/临时.md rename to public/mengyanote/临时/临时.md diff --git a/public/mengyanote/临时解决方案/修改hosts方式来直连Github.md b/public/mengyanote/临时/修改hosts方式来直连Github.md similarity index 100% rename from public/mengyanote/临时解决方案/修改hosts方式来直连Github.md rename to public/mengyanote/临时/修改hosts方式来直连Github.md diff --git a/public/mengyanote/临时/快速开启一个http服务器.md b/public/mengyanote/临时/快速开启一个http服务器.md new file mode 100644 index 0000000..cb7094d --- /dev/null +++ b/public/mengyanote/临时/快速开启一个http服务器.md @@ -0,0 +1,104 @@ +下面给你 **最快速、常用且实用** 的几种方法 —— 你可以按自己环境选一种直接复制运行(都有最短命令和一段可跑的代码示例)。注意:这些方法适合本地开发与临时文件共享;若要对公网长期暴露,需加强安全配置(见结尾安全提示)。 + +# 1) 最快:Python(适用于已装 Python 3) + +在当前目录启动一个静态文件 HTTP 服务器(默认端口 8000): + +```bash +python -m http.server 8000 +# 在所有网卡可访问(局域网可见): +python -m http.server 8000 --bind 0.0.0.0 +``` + +停止:Ctrl+C + +# 2) 最轻量 Node.js/一行(适合前端) + +如果没装全局包,用 npx 直接跑: + +```bash +npx http-server . -p 8000 +# 或者 +npx serve -s . -l 8000 +``` + +# 3) 快速用 PHP(机器有 PHP) + +```bash +# 在当前目录启动(0.0.0.0 让局域网可访问) +php -S 0.0.0.0:8000 +``` + +# 4) 用 Go(单文件可执行) + +一行临时服务器(需要 go 环境): + +```bash +go run <<'GO' +package main +import ("net/http"; "log") +func main(){ + http.Handle("/", http.FileServer(http.Dir("."))) + log.Println("listening :8000") + log.Fatal(http.ListenAndServe(":8000", nil)) +} +GO +``` + +# 5) 小型 Node.js 代码(可自定义响应) + +创建 `server.js`: + +```js +const http = require('http') +const fs = require('fs') +const path = require('path') +http.createServer((req,res)=>{ + const p = path.join(__dirname, req.url === '/' ? 'index.html' : req.url) + fs.readFile(p, (err,data)=>{ + if(err){ res.statusCode=404; res.end('Not found'); return } + res.end(data) + }) +}).listen(8000, ()=>console.log('http://localhost:8000')) +``` + +运行 `node server.js` + +# 6) 用 Docker + nginx(将当前目录当静态站点) + +```bash +docker run --rm -p 8080:80 -v "$PWD":/usr/share/nginx/html:ro nginx +# 访问 http://localhost:8080 +``` + +# 7) Windows PowerShell 快速(若无 python) + +PowerShell 一行启动(基于 .NET): + +```powershell +Start-Process -NoNewWindow -FilePath "python" -ArgumentList "-m http.server 8000" +# (推荐先安装 Python,然后用 python -m http.server) +``` + +--- + +# HTTPS / 暴露到公网(临时) + +- 暂时要把本地端口暴露到公网,可用 `ngrok`、`cloudflared` 等隧道工具(需安装并登录)。 + +- 若需要本地 HTTPS 简易方案,推荐使用 Caddy(自动 TLS)或为开发环境用 mkcert 生成证书并配置 nginx / Caddy。 + + +--- + +# 小结与安全提示(必读) + +- 以上方法都很快,**开发/调试/本地文件分享** 推荐 Python、http-server、PHP。 + +- **不要** 在不做认证/权限控制的情况下把敏感目录暴露到公网。 + +- 若要在局域网共享,使用 `--bind 0.0.0.0`(或相应选项)并确保防火墙策略允许。 + +- 生产环境请用经过配置的 nginx/Apache/Caddy,并启用 HTTPS、访问控制与日志。 + + diff --git a/public/mengyanote/临时/灵创第14周个人汇报.md b/public/mengyanote/临时/灵创第14周个人汇报.md new file mode 100644 index 0000000..617aeda --- /dev/null +++ b/public/mengyanote/临时/灵创第14周个人汇报.md @@ -0,0 +1,25 @@ +# 第14周个人汇报 + +## Godot游戏开发 + +- 这周终于把游戏后端给做出来了,虽然目前十分简单,只有登录注册和保存功能,等以后再学一学nodejs争取把客户端的操作转到服务端上,这样就可以实现一个比较好的游戏服务器(话说有点像我的世界基岩版早期服务端那种感觉呢) + +- 写游戏后端的同时顺便把[HTTP的访问方法](https://typecho.shumengya.top/index.php/archives/20/),[Godot支持的网络协议](https://typecho.shumengya.top/index.php/archives/27/),以及[Godot对于JSON文件的操作](https://typecho.shumengya.top/index.php/archives/25/)给学了一下 + +- 尝试了一下Godot的多线程。GDScript性能还是太差了,更新地块连续生成和删除40个节点就会阻塞主线程开始卡顿,周二看文档给地块更新单独弄了个线程加载,看着不卡顿以为问题解决了,周六再看发现UI加载出了问题,问了ChatGPT说是Godot的UI加载只能在主线程加载,没办法又回到了起点,以后再看吧 + +- 逛贴吧时发现Godot有一个*[OS.execute](https://typecho.shumengya.top/index.php/archives/19/)*方法,这个命令可以执行控制台命令,这给了我一个思路 + + ```swift + OS.execute("python", ["res://path/script.py", "arg1", "arg2"], true) + ``` + + 像是这样不就可以调用python脚本或是其他语言的东西,那Godot的扩展和一些耗性能的操作不是可以丢给其他语言,但这样好像只有Windows或者Linux可以这样,限制还是挺大的,感觉不如 GDExtension + +- 还有那个Godot导出安卓的访问外置储存也是一个问题 + +![](https://picabstract-preview-ftn.weiyun.com/ftn_pic_abs_v3/683dc2cd6013120f191ff37137ddc564aadc29310df55a9364a25093c6384093ded5a3327015594081b7ae72af6c2c5b?pictype=scale&from=30113&version=3.3.3.3&fname=%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202024-12-01%20164730.png&size=750) + +### 总结 + +截止到目前已经12月份了,估计以后要准备英语四级和进文学长的C++计算机二级考试以及gamejam的东西和期末考,这个游戏项目要搁置一段时间,但争取在这个学期内把他的一些基本功能做完吧,毕竟寒假还有寒假的安排 \ No newline at end of file diff --git a/public/mengyanote/临时/灵创第15周周报.md b/public/mengyanote/临时/灵创第15周周报.md new file mode 100644 index 0000000..43fe2d9 --- /dev/null +++ b/public/mengyanote/临时/灵创第15周周报.md @@ -0,0 +1,35 @@ +# 灵创第15周周报 + +### Godot开发 + +把以前的一个聊天软件的服务端用nodejs重新写了一遍,算是2.0吧 + +![](https://picabstract-preview-ftn.weiyun.com/ftn_pic_abs_v3/41efe513fcb2b7ab9d012751ce89dcb321c7a11ac966e78f067c4977dab87b470b1aa95b461d831c868e226bc456130b?pictype=scale&from=30113&version=3.3.3.3&fname=%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202024-12-07%20215620.png&size=750) + +![](https://picabstract-preview-ftn.weiyun.com/ftn_pic_abs_v3/ed8dcdb1a7aaab792e4416f89141c9b71fb6622cfb6beaad056e2625c21534d8c40deb8bee8edabc187e6e21baa6f641?pictype=scale&from=30113&version=3.3.3.3&fname=%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%2853%29.png&size=750) + +**待完成的任务**: + +- [ ] 将每个聊天室的聊天记录保存在一个*.chat文件中,当新用户加入聊天室时先加载该聊天室已有的聊天记录,*为每个聊天室的名字 保存在js同级目录下的rooms文件夹下 +- [ ] 统计服务器在线用户数和聊天室在线用户数 +- [ ] 记录用户的IP地址和设备类型(Android,Windows,macOS ) +- [ ] 称号系统 +- [ ] 控制台颜色和聊天颜色 +- [ ] 在线图片解析 +- [ ] 以后看看能不能解析markdown格式,godot自带的BBcode富文本节点太辣鸡了 +- [ ] 用户头像 + +### Unity开发 + +用github desketop 把 gamejam要做的项目给上传到了仓库 +目前就做了个会移动和发送子弹的正方形,素材都还没有弄上去 + +### 其他 + +学了一些Git指令,差不多会控制台里克隆和上传代码了 + +用github自带的域名弄了个[静态博客](https://shumengya6666666.github.io) + +继续准备四级... + +看了点C++基本语法 \ No newline at end of file diff --git a/public/mengyanote/临时/第11周学习内容.md b/public/mengyanote/临时/第11周学习内容.md new file mode 100644 index 0000000..6b58c31 --- /dev/null +++ b/public/mengyanote/临时/第11周学习内容.md @@ -0,0 +1,55 @@ +# 第11周学习内容 + + + +## 1. 算法 + + + +本周学习了以下算法: + +- **快速幂**:重点掌握了其实现及应用场景。 +- **二分查找**:复习了基本概念及在有序数组中的应用。 +- **埃拉托斯特尼筛法**:学习了其原理并实现了判断素数的功能。 + + + +## 2. 游戏开发 + + + +本周在Godot游戏开发方面取得了以下进展: + +- 完成了游戏《萌芽农场》的单机部分。 + +- 游戏开发进度: + + - [x] 游戏基本UI + - [x] 本地玩家数据储存 + - [x] 基本游戏玩法 + + - [ ] 多人联机 + - [ ] 作物贴图 + - [ ] 游戏频闪bug + + + +游戏截图 + +![截图](https://picabstract-preview-ftn.weiyun.com/ftn_pic_abs_v3/51b115b80170f5bd2d83257460a2b77e3141c3cc60f517f84d2d77845fd4d002d91fc7dbb5f2e624c3ad395d9d1c48bc?pictype=scale&from=30113&version=3.3.3.3&fname=%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202024-11-10%20084405.png&size=500) + +这周末或者下周准备完善游戏联机部分 + +## 3. 其他 + + + +- 帮助迷梦龙报名参加美国总统竞选,但遗憾落选。[迷梦龙竞选总统](https://迷梦龙.shumengya.top) + + + +### 总结 + + + +本周在算法方面有了新的突破,Godot游戏开发方面也向前推进了一步。希望下周能继续保持进展,完成更多任务。 \ No newline at end of file diff --git a/public/mengyanote/临时/第11周汇报.md b/public/mengyanote/临时/第11周汇报.md new file mode 100644 index 0000000..6b58c31 --- /dev/null +++ b/public/mengyanote/临时/第11周汇报.md @@ -0,0 +1,55 @@ +# 第11周学习内容 + + + +## 1. 算法 + + + +本周学习了以下算法: + +- **快速幂**:重点掌握了其实现及应用场景。 +- **二分查找**:复习了基本概念及在有序数组中的应用。 +- **埃拉托斯特尼筛法**:学习了其原理并实现了判断素数的功能。 + + + +## 2. 游戏开发 + + + +本周在Godot游戏开发方面取得了以下进展: + +- 完成了游戏《萌芽农场》的单机部分。 + +- 游戏开发进度: + + - [x] 游戏基本UI + - [x] 本地玩家数据储存 + - [x] 基本游戏玩法 + + - [ ] 多人联机 + - [ ] 作物贴图 + - [ ] 游戏频闪bug + + + +游戏截图 + +![截图](https://picabstract-preview-ftn.weiyun.com/ftn_pic_abs_v3/51b115b80170f5bd2d83257460a2b77e3141c3cc60f517f84d2d77845fd4d002d91fc7dbb5f2e624c3ad395d9d1c48bc?pictype=scale&from=30113&version=3.3.3.3&fname=%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202024-11-10%20084405.png&size=500) + +这周末或者下周准备完善游戏联机部分 + +## 3. 其他 + + + +- 帮助迷梦龙报名参加美国总统竞选,但遗憾落选。[迷梦龙竞选总统](https://迷梦龙.shumengya.top) + + + +### 总结 + + + +本周在算法方面有了新的突破,Godot游戏开发方面也向前推进了一步。希望下周能继续保持进展,完成更多任务。 \ No newline at end of file diff --git a/public/mengyanote/临时/第12周周报.md b/public/mengyanote/临时/第12周周报.md new file mode 100644 index 0000000..99a35e7 --- /dev/null +++ b/public/mengyanote/临时/第12周周报.md @@ -0,0 +1,40 @@ +# 第12周周报 + +## 算法 + +1. 学习了 **链表**、**栈** 和 **列表** 的相关知识。 +2. LeetCode 刷了 4 道题。 + +--- + +## Godot 游戏开发 + +#### 萌芽农场 + +- 更新了游戏 UI,使用 **GridContainer** 节点全面取代了 **ItemList** 节点,改善了界面的美观性(或许吧)。 +- 后端...还没想好怎么写 +- 还有那个AI画素材是真的抽象... + +![](https://picabstract-preview-ftn.weiyun.com/ftn_pic_abs_v3/e5b92d7100f6406f7b6fafb8b52e2934b3be175dbf3a44651f92bd7c4b728e4384c05934db5ca4d2f81470cfe6c748d8?pictype=scale&from=30113&version=3.3.3.3&fname=%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202024-11-17%20150619.png&size=750) + +#### 萌芽农场数据修改软件 + +- 为了更方便地修改游戏数据,开发了一个可视化的修改工具,封装了一个在 Godot 中创建和修改文件的方法。 + +- 重新尝试将游戏导出到安卓平台,了解了 **安卓的文件权限机制**。 + + ![](https://picabstract-preview-ftn.weiyun.com/ftn_pic_abs_v3/9e324548004aacccec03018e04347e7d03a9df41ab8c097e967ee27b08f89ae4e95f3fe6c9a7583b1fc6f97a70a8524f?pictype=scale&from=30113&version=3.3.3.3&fname=%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202024-11-17%20140029.png&size=750) + +--- + +## 指定任务 + +- 用 C 语言实现了一个控制台版的贪吃蛇游戏。详细见附件 + +--- + +## 其他 + +- 在宝塔面板上用docker部署了[alist](http://alist.shumengya.top)和[ChatGPT_next_web](http://chatgpt.shumengya.top),发现ChatGPT_next_web就是一托答辩 + +- alist没有深究,以后有机会看看能不能把我的蓝奏云,百度网盘这些给接入上去(想接微云,发现微云有48小时登录限制,垢璧腾讯) diff --git a/public/mengyanote/临时/第13周周报.md b/public/mengyanote/临时/第13周周报.md new file mode 100644 index 0000000..e69de29 diff --git a/public/mengyanote/临时/第16周灵创汇报.md b/public/mengyanote/临时/第16周灵创汇报.md new file mode 100644 index 0000000..12a2f0b --- /dev/null +++ b/public/mengyanote/临时/第16周灵创汇报.md @@ -0,0 +1,10 @@ +# 灵创第16周周报 + +## 其他 + +这周准备四级,然后周末和室友联机打泰拉瑞亚加上今天晚上突发恶疾(发烧),导致真没干什么,下周开始干点正事吧 +找了个我的世界基岩版远古版本的nukkit和pocketmine服务端,差不多配好了环境(,写了几个插件,看看能不能从中学到点东西(A*寻路,网络协议),好给我以后写游戏后端一点经验 +学了点c++语法 +找了个第三方QQ机器人框架napcat,接口还挺丰富的,看看能不能用nodejs写个简单的ChatGPTQQ机器人 +本来想开个泰拉瑞亚服务器的,还没来得及弄。 +周报mt管理器手打的,可以排版有点问题 \ No newline at end of file diff --git a/public/mengyanote/临时解决方案/萌芽云剪切板.md b/public/mengyanote/临时/萌芽云剪切板.md similarity index 95% rename from public/mengyanote/临时解决方案/萌芽云剪切板.md rename to public/mengyanote/临时/萌芽云剪切板.md index cf94b9e..bb459e4 100644 --- a/public/mengyanote/临时解决方案/萌芽云剪切板.md +++ b/public/mengyanote/临时/萌芽云剪切板.md @@ -1,4 +1,6 @@ +https://sealearn.yuque.com/org-wiki-sealearn-syaeae/oi5uvb/snonvxsmse9r9e4w + 用小米平板尝鲜下blender安卓版,目前只有高通SOC可用。感谢大佬的移植。大家可以自己安装试试,安卓手机和平板都可以。 大佬也在B站:@dshawshank github地址:https://github.com/dshawshank/APP-android_arm64 diff --git a/public/mengyanote/临时解决方案/跨平台软件开发总结.md b/public/mengyanote/临时/跨平台软件开发总结.md similarity index 100% rename from public/mengyanote/临时解决方案/跨平台软件开发总结.md rename to public/mengyanote/临时/跨平台软件开发总结.md diff --git a/public/mengyanote/无线-HCIA 02.md b/public/mengyanote/华为ICT/无线-HCIA 02.md similarity index 100% rename from public/mengyanote/无线-HCIA 02.md rename to public/mengyanote/华为ICT/无线-HCIA 02.md diff --git a/public/mengyanote/嵌入式/USB拓展坞接口数量决定因素.md b/public/mengyanote/嵌入式/USB拓展坞接口数量决定因素.md new file mode 100644 index 0000000..49a5490 --- /dev/null +++ b/public/mengyanote/嵌入式/USB拓展坞接口数量决定因素.md @@ -0,0 +1,39 @@ +一个USB拓展坞(或集线器)能拓展多少个USB接口,主要由以下几个因素决定: + +1. USB协议规范与层级限制 + +- USB主机控制器的能力:电脑本身的USB主机控制器(如主板上的控制器)决定了初始可连接的设备数量。根据USB规范,一个主机控制器理论上最多可连接 127个设备,但这是通过多级集线器级联实现的(例如主机→一级集线器→二级集线器→……)。 +- 单级集线器的端口数:单个集线器(如拓展坞)的直接端口数通常为 4、7、10个 等,这是由集线器芯片的设计决定的。例如,常见的4口集线器是单芯片直接支持的标准配置。 + +2. 集线器芯片的硬件设计 + +- 主控芯片的能力:不同型号的集线器芯片(如瑞萨、德州仪器等品牌)支持的端口数量不同。芯片内部集成的物理接口数量和信号处理能力直接限制了拓展坞的端口数。 +- 信号分配与带宽共享:USB接口共享总线带宽(如USB 3.0的5Gbps),过多端口可能导致带宽不足。因此,芯片设计时会平衡端口数与性能,避免过多端口导致速度下降。 + +3. 电源供应能力 + +- 主机供电 vs 外接电源: +- 无外接电源(总线供电):依赖电脑USB端口的功率(USB 2.0约500mA,USB 3.0约900mA)。若拓展坞无外接电源,总功率需低于主机端口上限,否则可能因供电不足导致设备无法工作(例如连接多个移动硬盘时易出现问题)。 +- 有外接电源(自供电):通过适配器供电,可支持更多高功耗设备,端口数主要受芯片和设计限制。 +- 单端口功率限制:每个USB端口需符合规范(如USB 2.0单端口最大500mA,USB 3.0最大900mA),总功率需在集线器设计的安全范围内。 + +4. 信号传输与物理限制 + +- 信号衰减与稳定性:USB信号在长距离或多端口分支中会衰减,尤其是高速率信号(如USB 3.0以上)。拓展坞的电路设计需保证信号完整性,过多端口可能增加干扰风险,因此实际端口数会受限于硬件可靠性。 +- 物理空间与布局:拓展坞的体积和接口排列也会影响端口数量,例如小型便携拓展坞通常设计为4口,而桌面级集线器可能有7-10个端口。 + +5. 厂商设计与市场需求 + +- 用户场景导向:厂商会根据目标用户(如普通办公、专业外设连接)设计端口数。例如,针对轻薄本的拓展坞可能集成4-6个端口(兼顾便携性和实用性),而工业级集线器可能支持更多端口。 +- 成本与性价比:更多端口意味着更高的芯片和制造成本,厂商需在功能与价格间平衡。 + +总结 + +核心决定因素: + +- USB协议的层级与单集线器端口限制 +- 集线器芯片的硬件设计(端口数、带宽分配) +- 电源供应能力(是否外接电源及总功率) +- 信号传输的稳定性与物理空间限制 + +实际中,常见的USB拓展坞多为 4-7个端口,高端或专用集线器可能支持更多(如10口以上),但需结合外接电源和高效的芯片方案来保证性能。 \ No newline at end of file diff --git a/public/mengyanote/数据库学习/MongoDB数据库优化方式一览.md b/public/mengyanote/数据库/MongoDB数据库优化方式一览.md similarity index 100% rename from public/mengyanote/数据库学习/MongoDB数据库优化方式一览.md rename to public/mengyanote/数据库/MongoDB数据库优化方式一览.md diff --git a/public/mengyanote/数据库学习/MongoDB的索引一览.md b/public/mengyanote/数据库/MongoDB的索引一览.md similarity index 97% rename from public/mengyanote/数据库学习/MongoDB的索引一览.md rename to public/mengyanote/数据库/MongoDB的索引一览.md index e31a349..7c0e185 100644 --- a/public/mengyanote/数据库学习/MongoDB的索引一览.md +++ b/public/mengyanote/数据库/MongoDB的索引一览.md @@ -1,4 +1,3 @@ -**MongoDB 提供了强大的索引功能,这是优化查询性能最主要和核心的方法**,其作用原理与其他关系型数据库(如 MySQL, PostgreSQL)中的索引类似。 **索引的核心作用:** diff --git a/public/mengyanote/数据库学习/MySQL数据库支持的数据类型.md b/public/mengyanote/数据库/MySQL数据库支持的数据类型.md similarity index 100% rename from public/mengyanote/数据库学习/MySQL数据库支持的数据类型.md rename to public/mengyanote/数据库/MySQL数据库支持的数据类型.md diff --git a/public/mengyanote/数据库学习/普通json储存和MongoDB储存优缺点.md b/public/mengyanote/数据库/json文件储存和MongoDB储存优缺点.md similarity index 100% rename from public/mengyanote/数据库学习/普通json储存和MongoDB储存优缺点.md rename to public/mengyanote/数据库/json文件储存和MongoDB储存优缺点.md diff --git a/public/mengyanote/数据结构与算法/二分查找右侧边界算法总结.md b/public/mengyanote/数据结构与算法/二分查找右侧边界算法总结.md new file mode 100644 index 0000000..cb5b329 --- /dev/null +++ b/public/mengyanote/数据结构与算法/二分查找右侧边界算法总结.md @@ -0,0 +1,118 @@ +# 二分查找右侧边界算法总结 + + + +## 题目描述 + + + +在一个有序不递减的数组中(可能包含重复元素),使用二分查找找到某个值 `x` 最后一次出现的位置。如果该值不存在,则返回 -1。 + + + +## 输入格式 + + + +1. 第一行:一个整数 `n`,表示数组元素个数(`n <= 10^5`)。 +2. 第二行:`n` 个整数,代表数组元素(`1 <= 数组元素的值 <= 10^8`)。 +3. 第三行:一个整数 `q`,表示查询的数个数(`q <= 10^5`)。 +4. 第四行:`q` 个整数,代表要查找的值(`1 <= 要查找的数 <= 10^8`)。 + + + +## 输出格式 + + + +输出每个查询对应的最后一次出现的位置,若不存在则输出 -1。 + + + +## 算法思路 + + + +1. **初始化**: + - 设置左右指针 `l` 和 `r`,分别指向数组的开始和结束。 + - 初始化结果 `res` 为 -1。 +2. **二分查找**: + - 当l小于等于r时,执行以下步骤: + - 计算中间索引 `m`。 + - 如果 `a[m]` 等于 `x`,更新 `res` 为 `m + 1`,并将 `l` 移动到 `m + 1` 继续向右查找。 + - 如果 `a[m]` 小于 `x`,将 `l` 移动到 `m + 1`。 + - 如果 `a[m]` 大于 `x`,将 `r` 移动到 `m - 1`。 +3. **输出结果**: + - 返回结果 `res`。 + + + +## 时间复杂度 + + + +- 每次查找的时间复杂度为 O(log n),因此总时间复杂度为 O(q log n)。 + + + +## 示例代码 + + + +```c +c#include + +int findRB(int a[], int n, int x) { + int l = 0, r = n - 1, res = -1; + + while (l <= r) { + int m = l + (r - l) / 2; + + if (a[m] == x) { + res = m + 1; + l = m + 1; + } else if (a[m] < x) { + l = m + 1; + } else { + r = m - 1; + } + } + + return res; +} + +int main() { + int n, q; + + scanf("%d", &n); + int a[n]; + + for (int i = 0; i < n; i++) { + scanf("%d", &a[i]); + } + + scanf("%d", &q); + int qry[q]; + + for (int i = 0; i < q; i++) { + scanf("%d", &qry[i]); + } + + for (int i = 0; i < q; i++) { + int pos = findRB(a, n, qry[i]); + printf("%d ", pos); + } + printf("\n"); + + return 0; +} +c +``` + + + +## 总结 + + + +该算法有效地使用二分查找来找到数组中元素的右侧边界,适合处理较大规模的输入数据。 \ No newline at end of file diff --git a/public/mengyanote/数据结构与算法/二分查找图书馆算法总结.md b/public/mengyanote/数据结构与算法/二分查找图书馆算法总结.md new file mode 100644 index 0000000..2f64e12 --- /dev/null +++ b/public/mengyanote/数据结构与算法/二分查找图书馆算法总结.md @@ -0,0 +1,108 @@ +谢谢你的反馈。我们来修正代码。编译错误主要有两个原因: + + + +1. **变量大小问题**:在 C 语言中,数组的大小必须是固定的声明。我们使用 `#define` 或 `const` 来定义常量。 +2. **缺少比较函数**:`cmp` 函数必须在调用之前声明,或者将比较逻辑嵌入到 `main` 函数之前。 + + + +我们可以做以下改变: + + + +- 使用 `#define` 来定义常量。 +- 在 `main` 函数之前声明比较函数。 + + + +以下是经过修正的 C 语言代码: + + + +```c +#include +#include + +#define MAXN 1000010 +int nums[MAXN]; +int key, n; + +int left_bound() { + if (n == 0) return -1; + int left = 0; + int right = n - 1; + + while (left <= right) { + int mid = left + ((right - left) >> 1); + if (nums[mid] == key) { + right = mid - 1; + } else if (nums[mid] < key) { + left = mid + 1; + } else { + right = mid - 1; + } + } + if (left == n || nums[left] != key) return -1; + return left; +} + +int right_bound() { + if (n == 0) return -1; + int left = 0; + int right = n - 1; + + while (left <= right) { + int mid = left + ((right - left) >> 1); + + if (nums[mid] == key) { + left = mid + 1; + } else if (nums[mid] < key) { + left = mid + 1; + } else { + right = mid - 1; + } + } + if (left == 0 || nums[left - 1] != key) return -1; + return left - 1; +} + +// Compare function for qsort +int cmp(const void *a, const void *b) { + return (*(int*)a - *(int*)b); +} + +int main() { + scanf("%d %d", &n, &key); + for (int i = 0; i < n; i++) { + scanf("%d", &nums[i]); + } + qsort(nums, n, sizeof(int), cmp); + + if (left_bound() == -1) { + printf("Not Found\n"); + return 0; + } + int ans = (left_bound() + right_bound()) / 2 + 1; + printf("%d\n", ans); + return 0; +} +``` + + + +### 关键点说明 + + + +1. **常量定义**:使用 `#define MAXN 1000010` 来定义数组的最大长度。 +2. **比较函数**:在 `main` 函数之前定义 `cmp` 函数,以便在使用 `qsort` 时可以调用。 +3. **错误处理**:添加了换行符 `\n` 在 "Not Found" 输出中,以确保输出格式正确。 + + + +### 总结 + + + +这个版本应该能够成功编译并正常工作。如果还有问题,请继续反馈! \ No newline at end of file diff --git a/public/mengyanote/数据结构与算法/二分查找左侧边界算法总结.md b/public/mengyanote/数据结构与算法/二分查找左侧边界算法总结.md new file mode 100644 index 0000000..166b6c1 --- /dev/null +++ b/public/mengyanote/数据结构与算法/二分查找左侧边界算法总结.md @@ -0,0 +1,145 @@ +# 二分查找左侧边界算法总结 + + + +## 题目描述 + + + +在一个有序不递减的数组中(可能包含重复元素),使用二分查找找到某个值 `x` 第一次出现的位置。如果该值不存在,则返回 -1。 + + + +## 输入格式 + + + +1. **第一行**:一个整数 `n`,表示数组元素个数(`n <= 10^5`)。 +2. **第二行**:`n` 个整数,代表数组元素(`1 <= 数组元素的值 <= 10^8`)。 +3. **第三行**:一个整数 `q`,表示查询的数个数(`q <= 10^5`)。 +4. **第四行**:`q` 个整数,代表要查找的值(`1 <= 要查找的数 <= 10^8`)。 + + + +## 输出格式 + + + +输出每个查询对应的第一次出现的位置,若不存在则输出 -1。 + + + +## 算法思路 + + + +1. **初始化**: + - 设置左右指针 `l` 和 `r`,分别指向数组的开始和结束。 + - 初始化结果 `res` 为 -1。 +2. **二分查找**: + - 当`l`小于等于`r`时,执行以下步骤: + - 计算中间索引 `m`。 + - 如果 `a[m]` 等于 `x`,更新 `res` 为 `m + 1`,并将 `r` 移动到 `m - 1` 继续向左查找。 + - 如果 `a[m]` 小于 `x`,将 `l` 移动到 `m + 1`。 + - 如果 `a[m]` 大于 `x`,将 `r` 移动到 `m - 1`。 +3. **输出结果**: + - 返回结果 `res`。 + + + +## 时间复杂度 + + + +- 每次查找的时间复杂度为 O(log n),因此总时间复杂度为 O(q log n)。 + + + +## 示例代码 + + + +```c +c#include + +int findLB(int a[], int n, int x) { + int l = 0, r = n - 1, res = -1; + + while (l <= r) { + int m = l + (r - l) / 2; + + if (a[m] == x) { + res = m + 1; + r = m - 1; + } else if (a[m] < x) { + l = m + 1; + } else { + r = m - 1; + } + } + + return res; +} + +int main() { + int n, q; + + scanf("%d", &n); + int a[n]; + + for (int i = 0; i < n; i++) { + scanf("%d", &a[i]); + } + + scanf("%d", &q); + int qry[q]; + + for (int i = 0; i < q; i++) { + scanf("%d", &qry[i]); + } + + for (int i = 0; i < q; i++) { + int pos = findLB(a, n, qry[i]); + printf("%d ", pos); + } + printf("\n"); + + return 0; +} +c +``` + + + +## 示例 + + + +### 输入 + + + +``` +6 +1 2 2 2 3 3 +3 +3 2 5 +``` + + + +### 输出 + + + +``` +5 2 -1 +``` + + + +## 总结 + + + +该算法有效地使用二分查找来找到数组中元素的左侧边界,适合处理较大规模的输入数据。 \ No newline at end of file diff --git a/public/mengyanote/数据结构与算法/判断素数.md b/public/mengyanote/数据结构与算法/判断素数.md new file mode 100644 index 0000000..f06e07f --- /dev/null +++ b/public/mengyanote/数据结构与算法/判断素数.md @@ -0,0 +1,118 @@ +```c +#include +#include +#include +#include + +#define N 100005 + +int prime[N]; +int c; +bool isVisit[N]; + +void tell(int n) { + for (int i = 2; i <= n; ++i) { + if (isVisit[i] == false) + prime[++c] = i; + for (int j = 1; j <= c && i * prime[j] <= n; ++j) { + isVisit[i * prime[j]] = true; + if (i % prime[j] == 0) + break; + } + } +} + +int main(void) { + isVisit[0] = true; + isVisit[1] = true; + tell(N); + int n; + while (scanf("%d", &n)!= EOF) { + if (!isVisit[n]) + printf("Yes\n"); + else + printf("No\n"); + } + return 0; +} +``` + +```c +#include +#include +#include + +#define N 1000007 + +int vis[N], prime[N]; + +void sieve(int n) { + int k = 0; + memset(vis, 0, sizeof(vis)); + vis[0] = vis[1] = 1; + for (int i = 2; i <= n; i++) { + if (vis[i] == 0) + prime[k++] = i; + for (int j = 0; j < k; j++) { + if (i * prime[j] > n) + break; + vis[i * prime[j]] = 1; + if (i % prime[j] == 0) + break; + } + } +} + +int main() { + sieve(N); + int n; + while (scanf("%d", &n)!= EOF) { + if (vis[n] == 0) + printf("Yes\n"); + else + printf("No\n"); + } + return 0; +} +``` + +```c +#include +#include + +#define MAXN 100001 + +bool is_prime[MAXN]; + +void sieve() { + for (int i = 2; i < MAXN; i++) { + is_prime[i] = true; // 初始化所有数为素数 + } + is_prime[0] = is_prime[1] = false; // 0和1不是素数 + + for (int i = 2; i * i < MAXN; i++) { + if (is_prime[i]) { + for (int j = i * i; j < MAXN; j += i) { + is_prime[j] = false; // 标记合数 + } + } + } +}//用空间换时间 + +int main() { + sieve(); // 进行素数筛选 + + int n; + while (scanf("%d", &n) != EOF) { + if (is_prime[n]) { + printf("Yes\n"); + } else { + printf("No\n"); + } + } + + return 0; +} + +``` + diff --git a/public/mengyanote/数据结构与算法/十大排序算法简介.md b/public/mengyanote/数据结构与算法/十大排序算法简介.md new file mode 100644 index 0000000..4dbfc12 --- /dev/null +++ b/public/mengyanote/数据结构与算法/十大排序算法简介.md @@ -0,0 +1,67 @@ +十大排序算法是计算机科学领域中常用的排序算法,根据其时间复杂度和实现方式大致可分为比较类排序和非比较类排序,以下为你详细介绍: + +### 比较类排序 +这类排序算法通过比较元素间的大小关系来确定元素的最终位置。 +1. **冒泡排序(Bubble Sort)** + - **原理**:重复遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来,直到整个数列都被排序好,就像气泡从水底逐渐升到水面一样。 + - **时间复杂度**:$O(n^2)$ + - **空间复杂度**:$O(1)$ + - **稳定性**:稳定 + - **适用场景**:数据量较小且基本有序的情况。 +2. **选择排序(Selection Sort)** + - **原理**:在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾,以此类推,直到所有元素均排序完毕。 + - **时间复杂度**:$O(n^2)$ + - **空间复杂度**:$O(1)$ + - **稳定性**:不稳定 + - **适用场景**:数据量较小且对稳定性要求不高的情况。 +3. **插入排序(Insertion Sort)** + - **原理**:将未排序数据插入到已排序序列的合适位置,就像玩扑克牌时整理手牌一样。 + - **时间复杂度**:$O(n^2)$ + - **空间复杂度**:$O(1)$ + - **稳定性**:稳定 + - **适用场景**:数据量较小且基本有序的情况。 +4. **希尔排序(Shell Sort)** + - **原理**:它是插入排序的一种改进版本,也称为缩小增量排序。通过将原始数据分成多个子序列来改善插入排序的性能,先比较距离较远的元素,而不是像插入排序那样比较相邻元素。 + - **时间复杂度**:与增量序列的选择有关,平均约为 $O(n^{1.3})$ + - **空间复杂度**:$O(1)$ + - **稳定性**:不稳定 + - **适用场景**:中等规模的数据排序。 +5. **归并排序(Merge Sort)** + - **原理**:采用分治法,将一个数组分成两个子数组,分别对这两个子数组进行排序,然后将排好序的子数组合并成一个最终的有序数组。 + - **时间复杂度**:$O(n log n)$ + - **空间复杂度**:$O(n)$ + - **稳定性**:稳定 + - **适用场景**:数据量大且对稳定性有要求的情况。 +6. **快速排序(Quick Sort)** + - **原理**:同样采用分治法,选择一个基准值,将数组分为两部分,使得左边部分的元素都小于等于基准值,右边部分的元素都大于等于基准值,然后递归地对左右两部分进行排序。 + - **时间复杂度**:平均 $O(n log n)$,最坏 $O(n^2)$ + - **空间复杂度**:平均 $O(log n)$,最坏 $O(n)$ + - **稳定性**:不稳定 + - **适用场景**:数据量大且分布较为随机的情况。 +7. **堆排序(Heap Sort)** + - **原理**:利用堆这种数据结构,通常是最大堆(每个节点的值都大于或等于其子节点的值)或最小堆,将待排序序列构造成一个堆,然后依次取出堆顶元素,调整堆结构,直到整个序列有序。 + - **时间复杂度**:$O(n log n)$ + - **空间复杂度**:$O(1)$ + - **稳定性**:不稳定 + - **适用场景**:数据量大且对空间复杂度有要求的情况。 + +### 非比较类排序 +这类排序算法不通过比较元素间的大小关系来确定元素的最终位置。 +8. **计数排序(Counting Sort)** + - **原理**:通过统计每个元素出现的次数,然后根据统计结果将元素依次输出。它要求输入的数据必须是有确定范围的整数。 + - **时间复杂度**:$O(n + k)$,其中 $k$ 是数据范围。 + - **空间复杂度**:$O(k)$ + - **稳定性**:稳定 + - **适用场景**:数据范围较小且数据值为整数的情况。 +9. **桶排序(Bucket Sort)** + - **原理**:将数据分到有限数量的桶里,每个桶再分别进行排序(可以使用其他排序算法),最后将各个桶中的数据合并成一个有序序列。 + - **时间复杂度**:平均 $O(n + k)$,其中 $k$ 是桶的数量。 + - **空间复杂度**:$O(n + k)$ + - **稳定性**:取决于桶内排序算法 + - **适用场景**:数据均匀分布在某个范围内的情况。 +10. **基数排序(Radix Sort)** + - **原理**:按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。 + - **时间复杂度**:$O(d(n + k))$,其中 $d$ 是最大数字的位数,$k$ 是基数(如十进制中 $k = 10$)。 + - **空间复杂度**:$O(n + k)$ + - **稳定性**:稳定 + - **适用场景**:数据位数固定且范围较大的整数排序。 \ No newline at end of file diff --git a/public/mengyanote/数据结构与算法/快速幂算法(一).md b/public/mengyanote/数据结构与算法/快速幂算法(一).md new file mode 100644 index 0000000..af156a9 --- /dev/null +++ b/public/mengyanote/数据结构与算法/快速幂算法(一).md @@ -0,0 +1,92 @@ +要在C语言中实现快速幂算法,可以利用递归的方法或者迭代的方法来计算 *a**b*mod*c*。这里提供一个较为简单的实现,使用迭代的方法来避免栈溢出问题。 + + + +以下是实现代码: + + + +```c +c#include + +// 快速幂函数 +long long quick_pow(int a, int b, int c) { + long long result = 1; + long long base = a % c; // 对c取模,避免基数过大 + + while (b > 0) { + if (b % 2 == 1) { // 如果b是奇数 + result = (result * base) % c; + } + base = (base * base) % c; // 基数平方 + b /= 2; // b除以2 + } + + return result; +} + +int main() { + int a, b, c; + + // 输入 a, b, c + while (scanf("%d %d %d", &a, &b, &c) != EOF) { + printf("%lld\n", quick_pow(a, b, c)); + } + + return 0; +} +c +``` + + + +### 代码解释 + + + +- **quick_pow 函数**: + - 使用迭代的方法计算 *a**b*mod*c*。 + - `base` 是 *a*mod*c* ,用于在计算时减少数值范围。 + - 当 `b` 为奇数时,乘以当前的 `base` 并对 `c` 取模。 + - 将 `base` 平方并更新为 `(base * base) % c`。 + - `b` 每循环将除以2。 +- **main 函数**: + - 使用 `scanf` 读取输入三元组(*a*,*b*,*c*)。 + - 使用 `printf` 输出结果。 + + + +### 使用示例 + + + +如果输入值为: + + + +``` +6 2 8 +``` + + + +程序的输出将是: + + + +``` +4 +``` + + + +### 注意事项 + + + +- 输入的值需在限制范围内(1 < a, b, c < 2^30)。 +- 快速幂算法的时间复杂度为 *O*(log*b*),适合大范围的指数计算。 + + + +这个程序应可在1秒内快速处理多组数据。 \ No newline at end of file diff --git a/public/mengyanote/数据结构与算法/跳石头二分算法总结.md b/public/mengyanote/数据结构与算法/跳石头二分算法总结.md new file mode 100644 index 0000000..bc142fa --- /dev/null +++ b/public/mengyanote/数据结构与算法/跳石头二分算法总结.md @@ -0,0 +1,106 @@ +# 跳石头二分算法总结 + + + +## 题目描述 + + + +在给定的长度 `L` 和 `N` 个书的位置 `a` 中,要求在这些书的位置之间放置 `M` 个分隔符,使得每两个相邻分隔符之间的最小距离最大化。需要找出这个最大最小距离。 + + + +## 输入格式 + + + +1. 第一行:三个整数 `L`(长度)、`N`(书的数量)、`M`(分隔符的数量)。 +2. 第二行:`N` 个整数,表示书的位置。 + + + +## 输出格式 + + + +- 输出一个整数,表示最大化的最小距离。 + + + +## 算法思路 + + + +1. **初始化**:定义数组 `a` 存储书的位置,使用二分查找来确定最大最小距离。 +2. **检查函数 `check`**:判断在给定的最小距离 `x` 的情况下,能否放置 `M` 个分隔符。 +3. **二分查找**:在区间 `[0, L + 1]` 中进行二分查找,逐步逼近最大最小距离。 + + + +## C语言实现 + + + +以下是转换后的 C 语言代码: + + + +```c +c#include + +const int N1 = 1e5 + 5; +int L, N, M; +int a[N1]; + +int check(int x) { + int cnt = 0, now = 0; + for (int i = 1; i <= N; ++i) { + if (a[i] - now < x) { + cnt++; + } else { + now = a[i]; + } + } + return cnt <= M; +} + +int main() { + scanf("%d %d %d", &L, &N, &M); + for (int i = 1; i <= N; ++i) { + scanf("%d", &a[i]); + } + int l = 0, r = L + 1, mid; + while (l < r) { + mid = (l + r) >> 1; + if (check(mid)) { + l = mid + 1; + } else { + r = mid; + } + } + printf("%d\n", r - 1); + return 0; +} +c +``` + + + +## 逻辑解析 + + + +- **数组声明**:`int a[N1];` 用于存储书籍位置。 +- **检查函数**:`check(int x)` 用于判断当前最小距离 `x` 是否可行,计算需要的分隔符数量。 +- **二分查找**: + - 初始化左右边界 `l` 和 `r`。 + - 通过 `mid` 值来逐步查找最大最小距离,更新边界 `l` 或 `r` 以收敛到解。 +- **结果输出**:最终输出最大最小距离 `r - 1`。 + + + +## 总结 + + + +该算法通过二分查找高效地确定在给定条件下的最大最小距离,适合大规模数据的处理,时间复杂度为 `O(N log L)`。 \ No newline at end of file diff --git a/public/mengyanote/数据结构与算法/递增序列查询算法总结.md b/public/mengyanote/数据结构与算法/递增序列查询算法总结.md new file mode 100644 index 0000000..a17a2ad --- /dev/null +++ b/public/mengyanote/数据结构与算法/递增序列查询算法总结.md @@ -0,0 +1,203 @@ +# 递增序列查询算法总结 + + + +## 题目描述 + + + +给定一个递增的正整数序列,针对不同的查询输出对应结果。查询类型包括查找最大下标、最小下标、数字范围计数、比某个数大的最小数字、比某个数小的最大数字等。 + + + +## 输入格式 + + + +1. 第一行:一个整数 `n`,代表序列的长度(下标从0开始到 `n-1`)。 +2. 第二行:`n` 个整数,代表序列对应位置上的数。 +3. 第三行:一个整数 `m`,代表查询次数。 +4. 接下来的`m`行,每行是以下五种类型之一: + - `0 x`:查询数字 `x` 出现的最大下标,若不存在则输出 -1。 + - `1 x`:查询数字 `x` 出现的最小下标,若不存在则输出 -1。 + - `2 x y`:查询大于等于 `x` 且小于等于 `y` 的数字的个数(保证 `x <= y`)。 + - `3 x`:查询比 `x` 大且下标最小的数字的大小,若不存在则输出 -1。 + - `4 x`:查询比 `x` 小且下标最大的数字的大小,若不存在则输出 -1。 + + + +## 输出格式 + + + +输出每个查询的结果,每个结果占一行。 + + + +## 算法思路 + + + +1. **初始化**:读取输入的序列和查询数。 +2. **二分查找**: + - **类型 0**:使用二分查找找到 `x` 的最大下标。 + - **类型 1**:使用二分查找找到 `x` 的最小下标。 + - **类型 2**:使用二分查找找到 `x` 和 `y` 的范围,计算范围内的元素个数。 + - **类型 3**:使用二分查找找到第一个比 `x` 大的元素。 + - **类型 4**:使用二分查找找到最后一个比 `x` 小的元素。 +3. **输出结果**:将所有查询结果依次输出。 + + + +## 示例代码 + + + +```c +c#include + +int findMaxIndex(int a[], int n, int x) { + int l = 0, r = n - 1, res = -1; + while (l <= r) { + int m = l + (r - l) / 2; + if (a[m] == x) { + res = m; + l = m + 1; + } else if (a[m] < x) { + l = m + 1; + } else { + r = m - 1; + } + } + return res; +} + +int findMinIndex(int a[], int n, int x) { + int l = 0, r = n - 1, res = -1; + while (l <= r) { + int m = l + (r - l) / 2; + if (a[m] == x) { + res = m; + r = m - 1; + } else if (a[m] < x) { + l = m + 1; + } else { + r = m - 1; + } + } + return res; +} + +int countInRange(int a[], int n, int x, int y) { + int leftIndex = findMinIndex(a, n, x); + int rightIndex = findMaxIndex(a, n, y); + if (leftIndex == -1 || rightIndex == -1) return 0; + return rightIndex - leftIndex + 1; +} + +int findFirstGreater(int a[], int n, int x) { + int l = 0, r = n - 1, res = -1; + while (l <= r) { + int m = l + (r - l) / 2; + if (a[m] > x) { + res = a[m]; + r = m - 1; + } else { + l = m + 1; + } + } + return res; +} + +int findLastSmaller(int a[], int n, int x) { + int l = 0, r = n - 1, res = -1; + while (l <= r) { + int m = l + (r - l) / 2; + if (a[m] < x) { + res = a[m]; + l = m + 1; + } else { + r = m - 1; + } + } + return res; +} + +int main() { + int n, m; + scanf("%d", &n); + int a[n]; + + for (int i = 0; i < n; i++) { + scanf("%d", &a[i]); + } + + scanf("%d", &m); + for (int i = 0; i < m; i++) { + int type, x, y; + scanf("%d", &type); + if (type == 0) { + scanf("%d", &x); + printf("%d\n", findMaxIndex(a, n, x)); + } else if (type == 1) { + scanf("%d", &x); + printf("%d\n", findMinIndex(a, n, x)); + } else if (type == 2) { + scanf("%d %d", &x, &y); + printf("%d\n", countInRange(a, n, x, y)); + } else if (type == 3) { + scanf("%d", &x); + printf("%d\n", findFirstGreater(a, n, x)); + } else if (type == 4) { + scanf("%d", &x); + printf("%d\n", findLastSmaller(a, n, x)); + } + } + + return 0; +} +c +``` + + + +## 示例 + + + +### 输入 + + + +``` +10 +1 1 1 3 4 5 5 5 5 8 +5 +0 5 +1 5 +2 1 5 +3 4 +4 8 +``` + + + +### 输出 + + + +``` +8 +5 +9 +5 +5 +``` + + + +## 总结 + + + +该算法使用二分查找处理多种查询类型,适合处理较大规模的输入数据,能够高效地返回查询结果。 \ No newline at end of file diff --git a/public/mengyanote/杂项/10月23日大学英语笔记.md b/public/mengyanote/杂项/10月23日大学英语笔记.md new file mode 100644 index 0000000..7b09796 --- /dev/null +++ b/public/mengyanote/杂项/10月23日大学英语笔记.md @@ -0,0 +1,126 @@ +以下是你提到的英语词汇及其翻译和音标。我已经为其添加了音标,并将其排版成HTML和CSS格式。 + + + +### 英语词汇及翻译 + + + +| 英文词汇 | 翻译 | 音标 | +| :------------------------------------------------ | :----------------------- | :------------------------------------------------- | +| hands | 手 | /hændz/ | +| butterflies in the stomach | 肚子里的蝴蝶 | /ˈbʌtərflaɪz ɪn ðə ˈstʌmək/ | +| muscle tension | 肌肉紧张 | /ˈmʌsl ˈtɛnʃən/ | +| credit | 学分 / 信用 | /ˈkrɛdɪt/ | +| major | 主修 / 专业 | /ˈmeɪdʒər/ | +| major in | 主修 | /ˈmeɪdʒər ɪn/ | +| dropout | 辍学 | /ˈdrɔpˌaʊt/ | +| trigger | 诱因 / 扳机 | /ˈtrɪɡər/ | +| resilience | 弹性 | /rɪˈzɪljəns/ | +| cyberlove | 网恋 | /ˈsaɪbərləv/ | +| long-distance relationship | 异地恋 | /lɔŋ ˈdɪstəns rɪˌleɪʃənˈʃɪp/ | +| date | 日期 / 约会 | /deɪt/ | +| lovesick | 恋爱中的病 | /ˈlʌvˌsɪk/ | +| zodiac | 星座 | /ˈzoʊ.dɪ.æk/ | +| aquaman | 水行侠 | /ˈækwəˌmæn/ | +| aquarium | 水族馆 | /əˈkwɛərɪəm/ | +| pilgrim | 朝圣者 | /ˈpɪlɡrɪm/ | +| soul | 灵魂 | /soʊl/ | +| bar | 酒吧 | /bɑr/ | +| soap bar | 香皂 | /soʊp bɑr/ | +| behind the bars | 在监狱里 | /bɪˈhaɪnd ðə bɑrz/ | +| enjoy each other's company | 享受彼此的陪伴 | /ɪnˈdʒɔɪ iʧ ˈʌðərz ˈkʌmpəni/ | +| crush | 暗恋 | /krʌʃ/ | +| have a crush on | 对某人有好感 | /hæv ə krʌʃ ɑn/ | +| idol | 偶像 | /ˈaɪdəl/ | +| icon | 图标 / 偶像 | /ˈaɪˌkɒn/ | +| ideal | 理想 | /aɪˈdɪəl/ | +| idea | 主意 | /aɪˈdɪə/ | +| idiot | 傻瓜 | /ˈɪdiət/ | +| marketing campaign | 营销活动 | /ˈmɑrkɪtɪŋ kæmˈpeɪn/ | +| being in love implies that you can fall out of it | 恋爱意味着你可能会失去爱 | /ˈbiːɪŋ ɪn lʌv ɪmˈplaɪz ðæt juː kæn fɔl aʊt ʌv ɪt/ | +| -wise | 方面的 | /waɪz/ | +| family-wise | 从家庭的角度 | /ˈfæmɪli waɪz/ | +| better off | 过得更好 | /ˈbɛtər ɔf/ | +| big old kiss | 大大的吻 | /bɪɡ oʊld kɪs/ | +| vulnerable | 脆弱的 | /ˈvʌlnərəbəl/ | + + + +### HTML/CSS 排版美化 + + + +```html +html + + + + + 英语词汇及翻译 + + + +

英语词汇及翻译

+ + + + + + + + + + + + + + + + + + + + + + +
英文词汇翻译音标
hands/hændz/
butterflies in the stomach肚子里的蝴蝶/ˈbʌtərflaɪz ɪn ðə ˈstʌmək/
muscle tension肌肉紧张/ˈmʌsl ˈtɛnʃən/
+ + +html +``` + + + +你可以将上述HTML代码复制到文本编辑器中,然后另存为`.html`文件,以在浏览器中打开并查看效果。如果有其他需求或需要进一步的帮助,请告知我! \ No newline at end of file diff --git a/public/mengyanote/杂项/Markdown格式大全.md b/public/mengyanote/杂项/Markdown格式大全.md new file mode 100644 index 0000000..f4f9e21 --- /dev/null +++ b/public/mengyanote/杂项/Markdown格式大全.md @@ -0,0 +1,126 @@ +# MarkDown书写规范 + +写文档好帮手,轻量级标记语言 Markdown + +# 概述 + +## 起源 + +Markdown是[Daring Fireball](http://daringfireball.net/projects/markdown/syntax)的作者John Gruber发明,身为Blogger,可能他也觉得传统的HTML有些复杂吧,退一步来讲,若是一个毫无计算机基础的Blogger,根本也没必要去掌握那些复杂的标签语言知识。 + +## 宗旨 + +Markdown 的目标是实现「易读易写」,成为一种适用于网络的书写语言。 + +可读性,无论如何,都是最重要的。一份使用 Markdown 格式撰写的文件应该可以直接以纯文本发布,并且看起来不会像是由许多标签或是格式指令所构成。Markdown 语法受到一些既有 text-to-HTML 格式的影响,包括 Setext、atx、Textile、reStructuredText、Grutatext 和 EtText,而最大灵感来源其实是纯文本电子邮件的格式。 + +总之, Markdown 的语法全由一些符号所组成,这些符号经过精挑细选,其作用一目了然。比如:在文字两旁加上星号,看起来就像*强调*。Markdown 的列表看起来,嗯,就是列表。Markdown 的区块引用看起来就真的像是引用一段文字,就像你曾在电子邮件中见过的那样。 + + +# 全局规范 + +MarkDown 文件均使用```.md```作为后缀 *(小写字母)* + +普通文本换行,使用行末尾```2空格```触发 + + +## 发展 + +越来越多的软件和服务支持Markdown语法,应该说,Mac上大多数的写作软件都支持它。在线工具同样有很多,如果你的博客基于Wordpress或是blogger,它同样支持发布。 + +不仅仅是写博客,一切文章都可以用Markdown语法来写,比如说你想将一个标题加大字体,只需要在相应文字前面加上一个#或是在它的下一行加上一些等号即可,还有比这更简单的调整格式方式吗? + + +# 语法参见 + +[官方语法说明](http://daringfireball.net/projects/markdown/syntax) + +# 示例 + +--- + +## 标题 + +# 一级标题 + +## 二级标题 + +### 三级标题 + +#### 四级标题 + +##### 五级标题 + +###### 六级标题 + +## 强调 + +- **粗体** + +- _斜体_ + +## 引用 + +上面的横线用三个-表示 + +> 区块引用 + +## 列表 + +* red +* green +* blue + ++ red ++ green ++ blue + +- red +- green +- blue + + +1. red +2. green +3. blue + + +* 一个列表包含一个区块 +> 区块内容 +> 更多内容 + +## 代码 + +代码的插入方式 `printf('\n');` + +``` +function method() +{ + alert("javascript"); +} +``` + +``` +class Test{ + public static void main(String argc[]){ + System.out.println("java"); + } +} +``` + +``` +class Test{ + public static void main() + { + Console.WriteLine("C#"); + } +} +``` + +## 链接 + +行内连接 [GitHub](https://github.com/) 的链接 + +## 图片 + +![shiyanlou logo](https://static.shiyanlou.com/img/logo_03.png) diff --git a/public/mengyanote/杂项/PTA万能代码.md b/public/mengyanote/杂项/PTA万能代码.md new file mode 100644 index 0000000..e83d791 --- /dev/null +++ b/public/mengyanote/杂项/PTA万能代码.md @@ -0,0 +1,30 @@ +```c++ +#include +#include +#include +#include + +using namespace std; + +int main() { + // 使用当前时间的时间戳作为种子 + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + + // 创建一个基于该种子的随机数生成器 + std::default_random_engine generator(seed); + + // 创建一个均匀分布的随机数生成器(在 1 到 100 之间) + std::uniform_int_distribution distribution(0, 10); + + //这里填写你需要输入的 + string str1,str2; + cin>>str1>>str2; + + // 生成并打印随机数 + std::cout < +#include + +typedef struct { + char word[10 + 1]; + int index; +} Word; + +int main() { + Word words[20]; + int count = 0; //单词数量 + + + while (1) { + char word[10 + 1]; + fgets(word, sizeof(word), stdin); + + + if (word[0] == '#') { + break; + } + + + word[strcspn(word, "\n")] = '\0'; + + + strcpy(words[count].word, word); + words[count].index = count; + count++; + } + + //标准冒泡排序 + for (int i = 0; i < count - 1; i++) { + for (int j = 0; j < count-1-i; j++) { + if (strlen(words[j].word) > strlen(words[j+1].word)) { + // 交换单词 + Word temp = words[j]; + words[j] = words[j+1]; + words[j+1] = temp; + } + } + } + + for (int i = 0; i < count; i++) { + printf("%s ", words[i].word); + } + printf("\n"); + + return 0; +} + +``` + diff --git a/public/mengyanote/杂项/PTA好题-计算众数.md b/public/mengyanote/杂项/PTA好题-计算众数.md new file mode 100644 index 0000000..2341320 --- /dev/null +++ b/public/mengyanote/杂项/PTA好题-计算众数.md @@ -0,0 +1,78 @@ +**7-6 求整数序列中出现次数最多的数** + +分数 20 + +作者 张彤彧 + +单位 浙江大学 + +本题要求统计一个整型序列中出现次数最多的整数及其出现次数。 + +### 输入格式: + +输入在一行中给出序列中整数个数N(0 + +int main() { + int N; + scanf("%d", &N); + int arr[N]; + for(int i = 0; i < N; i++) { + scanf("%d", &arr[i]); + } + + int max_count = 0; + int most_freq_num = arr[0]; + for(int i = 0; i < N; i++) { + int count = 1; + for(int j = i+1; j < N; j++) { + if(arr[j] == arr[i]) { + count++; + } + } + if(count > max_count) { + max_count = count; + most_freq_num = arr[i]; + } + } + + printf("%d %d", most_freq_num, max_count); + return 0; +} + +``` + diff --git a/public/mengyanote/杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md b/public/mengyanote/杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md new file mode 100644 index 0000000..0438560 --- /dev/null +++ b/public/mengyanote/杂项/c++如何快速的检测一个字串符在另一个字串符的出现次数.md @@ -0,0 +1,31 @@ +```c++ +#include +#include +using namespace std; + +int countSubstrings(const string& str, const string& sub) { + int count = 0; + size_t pos = 0; + + // 循环直到找不到子字符串 + while ((pos = str.find(sub, pos)) != string::npos) { + count++; // 找到一个子字符串,计数器加1 + pos += sub.length(); // 更新位置,跳过已找到的子字符串 + } + + return count; +} + +int main() { + string str = "ababcabcabcab"; + string sub = "abc"; + + int result = countSubstrings(str, sub); + cout << "子字符串 \"" << sub << "\" 在字符串 \"" << str << "\" 中出现的次数是: " << result << endl; + + return 0; +} + +``` + +### TMD一生之耻!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! \ No newline at end of file diff --git a/public/mengyanote/杂项/markdown格式(没什么用).md b/public/mengyanote/杂项/markdown格式(没什么用).md new file mode 100644 index 0000000..51e9c14 --- /dev/null +++ b/public/mengyanote/杂项/markdown格式(没什么用).md @@ -0,0 +1,66 @@ +https://storage.googleapis.com/docscloudstorage/2022.3/UnityDocumentation.zip + +ChatGPT响应: Markdown中的一些常用标识符包括: + +1. **标题**:使用`#`表示不同级别的标题 + ```markdown + # 一级标题 + ## 二级标题 + ### 三级标题 + ``` + +2. **粗体**:使用`**`或`__`包围文本 + ```markdown + **粗体文本** 或 __粗体文本__ + ``` + +3. **斜体**:使用`*`或`_`包围文本 + ```markdown + *斜体文本* 或 _斜体文本_ + ``` + +4. **无序列表**:使用`-`、`*`或`+` + ```markdown + - 项目1 + * 项目2 + + 项目3 + ``` + +5. **有序列表**:使用数字加点 + ```markdown + 1. 第一项 + 2. 第二项 + ``` + +6. **链接**:使用`[链接文本](URL)` + ```markdown + [这是一个链接](https://example.com) + ``` + +7. **图片**:使用`![图片描述](图片URL)` + ```markdown + ![示例图片](https://example.com/image.png) + ``` + +8. **代码块**:使用反引号`` ` `` + ```markdown + `行内代码` + ``` + + 或使用三个反引号表示多行代码 + ```markdown + ``` + 多行代码 + ``` + ``` + +9. **引用**:使用`>` + ```markdown + > 这是一个引用 + ``` + +10. **水平线**:使用三个或以上的`-`、`*`或`_` + ```markdown + --- + ``` + diff --git a/public/mengyanote/杂项/古诗.md b/public/mengyanote/杂项/古诗.md new file mode 100644 index 0000000..eb1b1ed --- /dev/null +++ b/public/mengyanote/杂项/古诗.md @@ -0,0 +1,60 @@ +知我者,谓我心忧;不知我者,谓我何求 +路漫漫其修远兮,吾将上下而求索 +夕阳西下,断肠人在天涯 +兴,百姓苦;亡,百姓苦 +封侯非我意,但愿海波平 +我自横刀向天笑,去留肝胆两昆仑 +海上生明月,天涯共此时 +红豆生南国,春来发几枝。愿君多采撷,此物最相思 +气蒸云梦泽,波撼岳阳城 +黄沙百战穿金甲,不破楼兰终不还 +天生我材必有用,千金散尽还复来 +长风破浪会有时,直挂云帆济沧海 +安能摧眉折腰事权贵,使我不得开心颜 +会当凌绝顶,一览众山小 +国破山河在,城春草木深。感时花溅泪,恨别鸟惊心 +烽火连三月,家书抵万金 +日出江花红胜火,春来江水绿如蓝。能不忆江南 +同是天涯沦落人,相逢何必曾相识 +春蚕到死丝方尽,蜡炬成灰泪始干 +身无彩凤双飞翼,心有灵犀一点通 +山有木兮木有枝,心悦君兮君不知 +生年不满百,常怀千岁忧 +人生如逆旅,我亦是行人 +桃李春风一杯酒,江湖夜雨十年灯 +劝君莫惜金缕衣,劝君惜取少年时 + + +但愿人长久,千里共婵娟 +抽刀断水水更流,举杯消愁愁更愁 +孤帆远影碧空尽,唯见长江天际流 +两岸猿声啼不住,轻舟已过万重山 +疏影横斜水清浅,暗香浮动月黄昏 +晚来天欲雪,能饮一杯无 +山重水复疑无路,柳暗花明又一村 +旧时王谢堂前燕,飞入寻常百姓家 +葡萄美酒夜光杯,欲饮琵琶马上催 +两岸青山相对出,孤帆一片日边来 +落霞与孤鹜齐飞,秋水共长天一色 +杨柳青青江水平,闻郎江上踏歌声 +近乡情更怯,不敢问来人 +洛阳亲友如相问,一片冰心在玉壶 +莫愁前路无知己,天下谁人不识君 +七八个星天外,两三点雨山前 +一年好景君须记,最是橙黄橘绿时 +今夜月明人尽望,不知秋思落谁家 +劝君更尽一杯酒,西出阳关无故人 +云想衣裳花想容,春风拂槛露华浓 +此情可待成追忆,只是当时已惘然 +问君能有几多愁,恰似一江春水向东流 +小荷才露尖尖角,早有蜻蜓立上头 +两个黄鹂鸣翠柳,一行白鹭上青天 +两岸荔枝红,万家烟雨中 +独在异乡为异客,每逢佳节倍思亲 +无边落木萧萧下,不尽长江滚滚来 +千山鸟飞绝,万径人踪灭 +相见时难别亦难,东风无力百花残 +人间四月芳菲尽,山寺桃花始盛开 +春风得意马蹄疾,一日看尽长安花 +竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生 +我花开后百花杀,秋草萋萋鹦鹉洲 \ No newline at end of file diff --git a/public/mengyanote/杂项/文本颜色测试.md b/public/mengyanote/杂项/文本颜色测试.md new file mode 100644 index 0000000..428442b --- /dev/null +++ b/public/mengyanote/杂项/文本颜色测试.md @@ -0,0 +1,42 @@ +我是逐浪圆体 +我是逐浪花体 +我是逐浪像素字 +我是逐浪立楷 +我是红色 +我是绿色 +我是黄色 +我是蓝色 +我是紫色 +我是浅灰色 +我是尺寸 +我是尺寸 +我是逐浪立楷,绿色,尺寸为5 + +
背景色yellow
+ + +水果名称| 价格 | 数量 +-|-|- +香蕉 | $1 | 5 | +苹果 | $1 | 6 | +草莓 | $1 | 7 | + +name | 111 | 222 | 333 | 444 +- | :-: | :-: | :-: | -: +aaa | bbb | ccc | ddd | eee| +fff | ggg| hhh | iii | 000| + +name | 111 | 222 | 333 | 444 +:-- | :-- | :-- | :-- | :-- +aaa | bbb | ccc | ddd | eee +fff | ggg| hhh | iii | 000 + +颜色名 | 十六进制颜色值 | rgb颜色 +-|-|- +黑色(black) | 000000 | rgb(0, 0, 0) | +蓝色(blue) | 0000FF | rgb(0, 0, 255) | +灰色(grey) | 808080 | rgb(128, 128, 128) | +绿色(green) | 008000 | rgb(0, 128, 0) | +橙色(orange) | FFA500 | rgb(255, 165, 0) | +红色(red) | FF0000 | rgb(255, 0, 0) | +黄色(yellow) | FFFF00 | rgb(255, 255, 0) | \ No newline at end of file diff --git a/public/mengyanote/杂项/计算机刷题网站.md b/public/mengyanote/杂项/计算机刷题网站.md new file mode 100644 index 0000000..640ffb9 --- /dev/null +++ b/public/mengyanote/杂项/计算机刷题网站.md @@ -0,0 +1,7 @@ +#### 计算机刷题网站 + +1. 洛谷 https://www.luogu.com.cn/ +2. 牛客网 https://www.nowcoder.com/ +3. leetcode https://leetcode.cn/ +4. acm实验室 http://acm.mangata.ltd/ +5. PTA https://pintia.cn/home \ No newline at end of file diff --git a/public/mengyanote/2025年9月紧急规划.md b/public/mengyanote/树萌芽的小本本/2025年9月紧急规划.md similarity index 100% rename from public/mengyanote/2025年9月紧急规划.md rename to public/mengyanote/树萌芽的小本本/2025年9月紧急规划.md diff --git a/public/mengyanote/临时解决方案/2025年大一下暑假规划(大方向).md b/public/mengyanote/树萌芽的小本本/2025年大一下暑假规划(大方向).md similarity index 100% rename from public/mengyanote/临时解决方案/2025年大一下暑假规划(大方向).md rename to public/mengyanote/树萌芽的小本本/2025年大一下暑假规划(大方向).md diff --git a/public/mengyanote/大萌芽-Debian13服务器.md b/public/mengyanote/树萌芽的小本本/大萌芽-Debian13服务器.md similarity index 100% rename from public/mengyanote/大萌芽-Debian13服务器.md rename to public/mengyanote/树萌芽的小本本/大萌芽-Debian13服务器.md diff --git a/public/mengyanote/树萌芽的小本本/树萌芽の编程想法.md b/public/mengyanote/树萌芽的小本本/树萌芽の编程想法.md index 636b335..95076f1 100644 --- a/public/mengyanote/树萌芽的小本本/树萌芽の编程想法.md +++ b/public/mengyanote/树萌芽的小本本/树萌芽の编程想法.md @@ -29,7 +29,7 @@ - [x] ai 大模型测试名字的稀有度 - [x] ai大模型说一个词汇返回一个Emoji和颜文字 - [x] 写一个AI一键普通文章转文言文的功能 -- [ ] 用python写一个自动把Obsidian的markdown笔记上传到GitHub仓库自动部署成静态网页展示,或者python +- [x] 写一个自动把Obsidian的markdown笔记上传到GitHub仓库自动部署成静态网页展示 - [ ] 做一个获取网站域名来进行网站截图的API - [ ] 做一个树萌芽的宝库,收集从各路来的好用的软件 - [x] 用户发送一个Linux下的需求 AI返回相关的Linux命令 @@ -37,5 +37,7 @@ - [ ] 用AI制作一个亲戚称呼关系计算器 - [ ] 以30列30行的形式随机展示各种Emoji,点击对应Emoji可以直接一键复制,有刷新按钮可以刷新相应Emoji - [ ] 用python写个随机系列:随机一言,随机音乐,随机视频,随机诗歌,随机编程题,随机占卜/算命的后端API==, +- [ ] 做一个TCP,udp,websocket连接器,服务端和客户端,用来学习和测试 +- [ ] 写一个插件,模组,玩家可以用钻石驯服幻翼,腐肉,幻翼膜修复幻翼,驯服后可以跟随玩家打怪,可以被栓绳拴住,白天免疫燃烧伤害 diff --git a/public/mengyanote/游戏引擎学习/Godot/BBCode 标签学习.md b/public/mengyanote/游戏引擎/Godot/BBCode 标签学习.md similarity index 100% rename from public/mengyanote/游戏引擎学习/Godot/BBCode 标签学习.md rename to public/mengyanote/游戏引擎/Godot/BBCode 标签学习.md diff --git a/public/mengyanote/游戏引擎学习/Godot/DisplayServer简单总结.md b/public/mengyanote/游戏引擎/Godot/DisplayServer简单总结.md similarity index 100% rename from public/mengyanote/游戏引擎学习/Godot/DisplayServer简单总结.md rename to public/mengyanote/游戏引擎/Godot/DisplayServer简单总结.md diff --git a/public/mengyanote/游戏引擎学习/Godot/Godot字典的详细用法.md b/public/mengyanote/游戏引擎/Godot/Godot字典的详细用法.md similarity index 100% rename from public/mengyanote/游戏引擎学习/Godot/Godot字典的详细用法.md rename to public/mengyanote/游戏引擎/Godot/Godot字典的详细用法.md diff --git a/public/mengyanote/游戏引擎学习/Godot/OS类简单总结.md b/public/mengyanote/游戏引擎/Godot/OS类简单总结.md similarity index 100% rename from public/mengyanote/游戏引擎学习/Godot/OS类简单总结.md rename to public/mengyanote/游戏引擎/Godot/OS类简单总结.md diff --git a/public/mengyanote/游戏引擎学习/Godot/godot小代码.md b/public/mengyanote/游戏引擎/Godot/godot小代码.md similarity index 100% rename from public/mengyanote/游戏引擎学习/Godot/godot小代码.md rename to public/mengyanote/游戏引擎/Godot/godot小代码.md diff --git a/public/mengyanote/游戏引擎/Unity/Unity代码片段/Unity中的单例模式(全局变量).md b/public/mengyanote/游戏引擎/Unity/Unity代码片段/Unity中的单例模式(全局变量).md new file mode 100644 index 0000000..0e5bfdc --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity代码片段/Unity中的单例模式(全局变量).md @@ -0,0 +1,242 @@ +是的,Unity确实可以通过全局管理的脚本来实现你所说的功能。可以通过 **单例模式** 来创建一个全局的管理脚本,存储并更新玩家的位置,然后让其他脚本通过访问这个全局管理类来实时获取玩家的位置。 + +### 解决方案:使用单例模式来管理全局数据 + +**步骤:** + +1. 创建一个全局的管理脚本,使用单例模式保存玩家的位置。 +2. 在玩家生成脚本中,不断更新这个全局位置。 +3. 在 `GUI` 或其他脚本中,通过访问这个全局脚本来获取玩家位置。 + +### 示例: + +#### 1. 创建一个全局管理类 `GameManager` + +这个类将使用单例模式,并且持有玩家的位置。 + +```csharp +using UnityEngine; + +public class GameManager : MonoBehaviour +{ + public static GameManager Instance { get; private set; } // 单例模式 + public Vector3 PlayerPosition { get; private set; } // 存储玩家位置 + + void Awake() + { + // 确保只有一个 GameManager 实例 + if (Instance == null) + { + Instance = this; + } + else + { + Destroy(gameObject); // 如果已经有一个实例,销毁当前实例 + } + + // 不销毁该物体,以便在场景切换时仍然存在 + DontDestroyOnLoad(gameObject); + } + + public void UpdatePlayerPosition(Vector3 newPosition) + { + PlayerPosition = newPosition; // 更新玩家位置 + } +} +``` + +#### 2. 修改玩家生成脚本 `Player_Generated_Pos` + +在玩家生成脚本中,实例化玩家时更新全局的玩家位置。 + +```csharp +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Player_Generated_Pos : MonoBehaviour +{ + public GameObject playerPrefab; // 玩家飞机的预制体 + public Transform[] spawnPoints; // 存储生成点的数组 + + private GameObject playerInstance; // 玩家实例 + + void Start() + { + // 调用函数在随机位置生成玩家飞机 + SpawnPlayerAtRandomPosition(); + } + + void SpawnPlayerAtRandomPosition() + { + // 随机选择一个生成点 + int randomIndex = Random.Range(0, spawnPoints.Length); + Transform spawnPoint = spawnPoints[randomIndex]; + + // 在选定的位置生成玩家飞机,并获取实例对象 + playerInstance = Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation); + + // 更新全局玩家位置 + GameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position); + + // 输出生成的玩家飞机实例的位置 + Debug.Log("玩家生成位置:" + playerInstance.transform.position); + } + + void Update() + { + // 实时更新全局玩家位置 + if (playerInstance != null) + { + GameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position); + } + } +} +``` + +#### 3. 修改 `GUI` 脚本 + +在 `GUI` 脚本中,通过访问 `GameManager.Instance` 获取玩家的实时位置并更新 UI。 + +```csharp +using System.Collections; +using System.Collections.Generic; +using TMPro; // 引入 TextMeshPro 命名空间 +using UnityEngine; + +public class GUI : MonoBehaviour +{ + private TextMeshProUGUI Player_Pos; // 存储 TextMeshProUGUI 组件 + + void Start() + { + // 使用 GetComponent 获取 TextMeshProUGUI 组件 + Player_Pos = GameObject.Find("Player_Pos")?.GetComponent(); + } + + void Update() + { + // 获取全局的玩家位置 + if (GameManager.Instance != null) + { + Vector3 playerPosition = GameManager.Instance.PlayerPosition; + + // 更新UI显示玩家位置 + if (Player_Pos != null) + { + Player_Pos.text = "玩家坐标: (" + playerPosition.x + "," + playerPosition.y + ")"; + } + } + } +} +``` + +### 解释: + +1. **`GameManager` 类**: + - `GameManager` 类作为一个 **单例**,负责存储并提供玩家的位置数据。它使用 `Awake()` 方法确保只会有一个实例,并使用 `DontDestroyOnLoad()` 方法确保场景切换时 `GameManager` 不会被销毁。 + - `UpdatePlayerPosition()` 方法用于更新玩家的位置。 + +2. **`Player_Generated_Pos` 类**: + - 在 `SpawnPlayerAtRandomPosition()` 中,生成玩家飞机后,通过 `GameManager.Instance.UpdatePlayerPosition()` 将生成的位置传递到全局管理器。 + - 在 `Update()` 方法中,实时更新全局的玩家位置。 + +3. **`GUI` 类**: + - 在 `Update()` 方法中,通过 `GameManager.Instance.PlayerPosition` 获取玩家的实时位置,并更新 `TextMeshProUGUI` 组件中的文本。 + +### 优点: +- **全局管理**:通过 `GameManager` 单例类,你可以轻松地在任何脚本中获取和更新玩家的位置。 +- **实时更新**:`GUI` 脚本每帧都会自动获取并显示玩家的实时位置。 +- **模块化**:通过分离管理和显示逻辑,你的代码结构会更加清晰和易于维护。 + +### 总结: +使用 **单例模式** 作为全局脚本来管理和共享玩家位置是一个非常有效的方法。它不仅能减少跨脚本传递数据的复杂度,而且能确保玩家位置在不同的脚本之间实时同步。 + + + +根据你的描述,问题出在这一行代码: + +```csharp +GameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position); +``` + +如果报错是由于 `GameManager.Instance` 返回 `null`,说明 `GameManager` 这个单例没有正确初始化,或者它没有被加载到场景中。通常,这种情况是因为: + +1. **`GameManager` 没有正确加载或实例化**,即它没有在场景中创建,或者它在访问时被销毁。 +2. **`Awake()` 方法没有正确执行**,从而导致 `Instance` 为 `null`。 + +### 检查和修复步骤: + +1. **确保 `GameManager` 存在于场景中**: + 确保 `GameManager` 脚本已挂载到一个对象上,并且该对象已存在于场景中。你可以检查 `GameManager` 是否被添加到了一个合适的 GameObject 上(例如一个 "GameManager" 或 "Manager" 的空物体)。 + +2. **确保 `GameManager` 使用单例模式**: + 检查 `GameManager` 脚本的 `Awake()` 方法,确保它正确初始化并设置 `Instance`,例如: + + ```csharp + using UnityEngine; + + public class GameManager : MonoBehaviour + { + public static GameManager Instance { get; private set; } + + public Vector3 PlayerPosition { get; private set; } // 存储玩家位置 + + void Awake() + { + // 检查是否已经有 GameManager 实例存在 + if (Instance == null) + { + Instance = this; + DontDestroyOnLoad(gameObject); // 确保场景切换时不销毁该对象 + } + else + { + Destroy(gameObject); // 如果已经有一个实例,销毁当前实例 + } + } + + public void UpdatePlayerPosition(Vector3 newPosition) + { + PlayerPosition = newPosition; // 更新玩家位置 + } + } + ``` + + - 确保 `Instance` 在 `Awake()` 中被赋值。 + - 如果场景中已经存在一个 `GameManager` 实例,后加载的 `GameManager` 会被销毁。 + +3. **检查是否有其他 `GameManager` 实例**: + - 如果在场景中有多个 `GameManager` 实例,`Instance` 可能会被覆盖。确保只有一个 `GameManager` 实例,避免出现多个对象争夺单例实例。 + +4. **调试**: + 在 `Player_Generated_Pos` 脚本中,添加调试信息来检查 `GameManager.Instance` 是否为 `null`。 + + ```csharp + void Update() + { + // 检查 GameManager 是否为 null + if (GameManager.Instance == null) + { + Debug.LogError("GameManager 实例为 null,确保 GameManager 已经正确加载!"); + } + else if (playerInstance != null) + { + // 更新全局玩家位置 + GameManager.Instance.UpdatePlayerPosition(playerInstance.transform.position); + } + } + ``` + + 如果控制台显示 "GameManager 实例为 null",说明 `GameManager` 没有正确实例化,可能是由于 `Awake()` 方法没有执行,或者场景中没有正确的 `GameManager` 对象。 + +### 总结: + +- 确保 `GameManager` 正确地使用单例模式,并且它的实例在场景中是唯一的。 +- 使用 `DontDestroyOnLoad` 确保 `GameManager` 在场景切换时不被销毁。 +- 在其他脚本中访问 `GameManager.Instance` 前,确保它已经正确初始化。 + +通过这些步骤,你应该能够解决 `GameManager.Instance` 为 `null` 的问题。 + + + diff --git a/public/mengyanote/游戏引擎/Unity/Unity代码片段/Unity获取同一场景中其他对象的属性&组件.md b/public/mengyanote/游戏引擎/Unity/Unity代码片段/Unity获取同一场景中其他对象的属性&组件.md new file mode 100644 index 0000000..41d8d7c --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity代码片段/Unity获取同一场景中其他对象的属性&组件.md @@ -0,0 +1,111 @@ +在 Unity 中,获取同一场景中其他对象的属性(如位置)非常简单。你可以通过查找目标对象,并访问其组件来获取需要的信息。常用的方法有以下几种: + +### 1. 使用 `GameObject.Find()` 查找对象并获取其属性 +`GameObject.Find()` 可以用来查找场景中具有指定名称的对象。 + +示例代码: + +```csharp +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Player_Generated_Pos : MonoBehaviour +{ + void Start() + { + // 查找名称为 "TargetObject" 的对象 + GameObject targetObject = GameObject.Find("TargetObject"); + + if (targetObject != null) + { + // 获取目标对象的位置 + Vector3 targetPosition = targetObject.transform.position; + Debug.Log("Target position: " + targetPosition); + } + else + { + Debug.LogWarning("TargetObject not found!"); + } + } + + void Update() + { + // 可以根据需要在 Update 中执行相关操作 + } +} +``` + +### 2. 使用标签(`Tag`)查找对象 +如果对象的名称可能发生变化,使用标签(`Tag`)来查找更为可靠。你可以先在 Unity 编辑器中为对象设置标签。 + +示例代码: + +```csharp +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Player_Generated_Pos : MonoBehaviour +{ + void Start() + { + // 查找所有带有 "Target" 标签的对象 + GameObject[] targetObjects = GameObject.FindGameObjectsWithTag("Target"); + + foreach (GameObject targetObject in targetObjects) + { + // 获取目标对象的位置 + Vector3 targetPosition = targetObject.transform.position; + Debug.Log("Target position: " + targetPosition); + } + } + + void Update() + { + // 可以根据需要在 Update 中执行相关操作 + } +} +``` + +### 3. 使用 `GetComponent` 访问其他组件的属性 +如果你已经有了目标对象的引用,可以通过 `GetComponent` 获取该对象的组件并访问其属性。 + +例如,假设你已经有一个 `Player` 对象,并且想访问该对象的 `Transform` 组件的位置: + +```csharp +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Player_Generated_Pos : MonoBehaviour +{ + public GameObject player; // 你可以将 Player 对象通过 Inspector 拖入 + + void Start() + { + if (player != null) + { + // 获取 Player 对象的位置 + Vector3 playerPosition = player.transform.position; + Debug.Log("Player position: " + playerPosition); + } + else + { + Debug.LogWarning("Player object not assigned!"); + } + } + + void Update() + { + // 可以根据需要在 Update 中执行相关操作 + } +} +``` + +### 总结: +- **`GameObject.Find()`**:通过名称查找对象。 +- **`GameObject.FindGameObjectsWithTag()`**:通过标签查找对象。 +- **`GetComponent()`**:如果你有对象引用,使用该方法来访问对象的组件和属性。 + +根据你的需求,选择适合的方式来获取对象的位置或其他属性。 \ No newline at end of file diff --git a/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity修改物理碰撞层.md b/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity修改物理碰撞层.md new file mode 100644 index 0000000..3a1783b --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity修改物理碰撞层.md @@ -0,0 +1,49 @@ +要实现玩家射出的子弹不与玩家碰撞,而与敌人碰撞,敌人射出的子弹不与敌人碰撞而与玩家碰撞,你可以通过调整Unity中的**物理层(Layer)**和**碰撞矩阵(Collision Matrix)**来解决这个问题。 + +### 步骤: + +1. **创建新的物理层**: + - 在Unity中,首先你需要为玩家、敌人和子弹分别创建不同的物理层。 + - 转到 `Edit` -> `Project Settings` -> `Tags and Layers`。 + - 在 `Layers` 部分,点击 `User Layer` 下面的空白区域,创建以下新的层: + - `Player` + - `Enemy` + - `PlayerBullet` + - `EnemyBullet` + +2. **将对象分配到不同的层**: + - 将玩家对象的 `Layer` 设置为 `Player`。 + - 将敌人对象的 `Layer` 设置为 `Enemy`。 + - 将玩家射出的子弹的 `Layer` 设置为 `PlayerBullet`。 + - 将敌人射出的子弹的 `Layer` 设置为 `EnemyBullet`。 + +3. **设置碰撞矩阵**: + - 转到 `Edit` -> `Project Settings` -> `Physics`。 + - 在 `Physics` 设置中,找到 `Layer Collision Matrix`。 + - 你可以在这里设置哪些层之间可以发生碰撞。 + - **Player 和 PlayerBullet** 之间不发生碰撞。 + - **Enemy 和 EnemyBullet** 之间不发生碰撞。 + - **PlayerBullet 和 Enemy** 之间发生碰撞。 + - **EnemyBullet 和 Player** 之间发生碰撞。 + + 具体的设置应该如下: + - 确保 `Player` 和 `PlayerBullet` 行与列之间的勾选框是**取消勾选的**,这样它们不会发生碰撞。 + - 确保 `Enemy` 和 `EnemyBullet` 行与列之间的勾选框是**取消勾选的**,这样它们不会发生碰撞。 + - 确保 `PlayerBullet` 和 `Enemy` 之间,以及 `EnemyBullet` 和 `Player` 之间的碰撞是**勾选的**。 + +4. **确保Rigidbody的碰撞检测模式正确**: + - 对于玩家和子弹的 `Rigidbody` 组件,确保它们的 `Collision Detection` 设置为 `Continuous` 或 `Continuous Dynamic`,这有助于避免物理计算错误,尤其是在高速度的情况下。 + +### 代码示例(如果需要动态设置层): +如果你希望在代码中动态设置某个对象的层,可以使用以下代码: + +```csharp +// 设置玩家子弹的层 +gameObject.layer = LayerMask.NameToLayer("PlayerBullet"); + +// 设置敌人子弹的层 +gameObject.layer = LayerMask.NameToLayer("EnemyBullet"); +``` + +### 结论: +通过使用Unity的**Layer**和**Layer Collision Matrix**,你可以精确控制不同物体之间的碰撞行为。将玩家、敌人和子弹分别分配到不同的物理层,并在碰撞矩阵中配置它们之间的碰撞规则,就能实现你所需要的功能:玩家射出的子弹不与玩家碰撞,而与敌人碰撞,敌人射出的子弹不与敌人碰撞,而与玩家碰撞。 \ No newline at end of file diff --git a/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity导出到Windows改变窗口.md b/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity导出到Windows改变窗口.md new file mode 100644 index 0000000..7a5ffb1 --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity导出到Windows改变窗口.md @@ -0,0 +1,35 @@ +在Unity中,如果你希望应用程序以特定的窗口大小而不是全屏运行,可以通过以下步骤进行设置: + +### 1. **通过Player Settings设置窗口模式**: + - 打开 `Edit` 菜单,选择 `Project Settings`。 + - 在 `Project Settings` 中,选择 `Player`。 + - 在 `Player` 设置中,找到 `Resolution and Presentation` 部分。 + +### 2. **调整默认显示模式**: + - 在 `Resolution and Presentation` 下,找到 `Default Screen Mode`。 + - 将其设置为 `Windowed`,而不是 `Full Screen`,这样Unity会默认以窗口模式运行。 + +### 3. **设置窗口的分辨率**: + - 在 `Resolution and Presentation` 中,你还可以设置窗口的默认分辨率: + - `Default Screen Width` 和 `Default Screen Height` 可以指定启动时窗口的大小。 + - 例如,设置为 `1024x768`,这将使窗口在启动时以 1024x768 的分辨率打开。 + +### 4. **通过代码动态调整窗口大小**: + 如果你希望根据需要在游戏运行时改变窗口大小,可以使用以下代码: + + ```csharp + void Start() + { + // 设置窗口大小为 1024x768 + Screen.SetResolution(1024, 768, false); + } + ``` + + 这里,`Screen.SetResolution` 的第三个参数是布尔值,`false` 表示窗口模式(如果是 `true` 则会进入全屏模式)。 + +### 总结: +1. 在 `Player Settings` 中设置默认为窗口模式(`Windowed`)。 +2. 可选择设置默认窗口的分辨率。 +3. 如果需要动态调整窗口大小,可以通过 `Screen.SetResolution` 来实现。 + +通过这些设置,你就能让你的Unity项目在启动时以指定窗口大小而不是全屏运行。 \ No newline at end of file diff --git a/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity碰撞体撞到指定标签的碰撞体后操作.md b/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity碰撞体撞到指定标签的碰撞体后操作.md new file mode 100644 index 0000000..3421d92 --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity代码片段/unity碰撞体撞到指定标签的碰撞体后操作.md @@ -0,0 +1,40 @@ +要实现子弹在撞到标签为“air_wall”的碰撞体后被销毁,你需要在 `Bullet` 脚本中添加碰撞检测代码。使用 `OnCollisionEnter2D` 方法来处理与碰撞体的接触,并检查碰撞体的标签是否是“air_wall”。 + +以下是修改后的代码: + +```csharp +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Bullet : MonoBehaviour +{ + void Start() + { + // 在 5 秒后销毁子弹对象 + Destroy(gameObject, 5f); // 5f 表示 5 秒后销毁该对象 + } + + void Update() + { + // 你可以在这里添加子弹的移动逻辑 + } + + void OnCollisionEnter2D(Collision2D collision) + { + // 检查碰撞体是否有标签 "air_wall" + if (collision.gameObject.CompareTag("AirWall")) + { + // 如果是,销毁子弹 + Destroy(gameObject); + } + } +} +``` + +### 解释: +- `OnCollisionEnter2D(Collision2D collision)`:当子弹与其他物体发生碰撞时,这个方法会被调用。 +- `collision.gameObject.CompareTag("AirWall")`:检查碰撞体的标签是否是 "AirWall"。 +- 如果是,使用 `Destroy(gameObject)` 销毁子弹对象。 + +这样,子弹在撞到标签为 "AirWall" 的物体时就会被销毁。如果需要,也可以将销毁逻辑添加到其他碰撞处理上。 \ No newline at end of file diff --git a/public/mengyanote/游戏引擎/Unity/Unity代码片段/保留整数.md b/public/mengyanote/游戏引擎/Unity/Unity代码片段/保留整数.md new file mode 100644 index 0000000..d68b8ca --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity代码片段/保留整数.md @@ -0,0 +1,26 @@ +要保留整数并显示玩家坐标,你可以使用 `Mathf.RoundToInt()` 来将浮动的坐标值四舍五入为整数,或者直接使用 `ToString()` 来控制格式。这里是两种常见的方法: + +### 方法 1:使用 `Mathf.RoundToInt()` 将坐标四舍五入为整数 + +```csharp +Player_Pos.text = "玩家坐标: (" + Mathf.RoundToInt(playerPosition.x) + "," + Mathf.RoundToInt(playerPosition.y) + ")"; +``` + +`Mathf.RoundToInt()` 会将浮动的坐标值四舍五入为最接近的整数。 + +### 方法 2:使用 `ToString()` 来格式化数字 + +你也可以使用 `ToString("F0")` 来将数字转换为带有指定小数位数的字符串,在这种情况下是零小数位,表示整数。 + +```csharp +Player_Pos.text = "玩家坐标: (" + playerPosition.x.ToString("F0") + "," + playerPosition.y.ToString("F0") + ")"; +``` + +这种方式也会将坐标保留为整数,并且格式化为 `string` 类型。 + +### 总结: + +- **`Mathf.RoundToInt()`**: 将浮动坐标值四舍五入为最接近的整数。 +- **`ToString("F0")`**: 格式化为没有小数位的字符串。 + +这两种方法都能达到你的目的,具体选择哪一种取决于你是否需要精确的四舍五入,或者仅仅是格式化显示。 \ No newline at end of file diff --git a/public/mengyanote/游戏引擎/Unity/Unity代码片段/设置在几个特定点钟随机生成.md b/public/mengyanote/游戏引擎/Unity/Unity代码片段/设置在几个特定点钟随机生成.md new file mode 100644 index 0000000..2150ac8 --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity代码片段/设置在几个特定点钟随机生成.md @@ -0,0 +1,53 @@ +要实现玩家飞机在地图上的 5 个点之间随机生成,你可以定义一个包含这 5 个点的数组或列表,然后通过随机选择一个点来生成飞机。 + +以下是一个示例脚本: + +### 步骤: +1. **定义 5 个生成点的位置**:你可以将这些点的位置存储在一个 `Vector3[]` 数组中。 +2. **随机选择一个点**:使用 `Random.Range` 方法从这个数组中随机选择一个点。 +3. **将玩家飞机生成到选定的位置**:通过 `Instantiate` 方法实例化玩家飞机对象并设置它的位置。 + +### 示例代码: + +```csharp +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Player_Generated_Pos : MonoBehaviour +{ + public GameObject playerPrefab; // 玩家飞机的预制体 + public Transform[] spawnPoints; // 存储生成点的数组 + + void Start() + { + // 调用函数在随机位置生成玩家飞机 + SpawnPlayerAtRandomPosition(); + } + + void SpawnPlayerAtRandomPosition() + { + // 随机选择一个生成点 + int randomIndex = Random.Range(0, spawnPoints.Length); + Transform spawnPoint = spawnPoints[randomIndex]; + + // 在选定的位置生成玩家飞机 + Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation); + } +} +``` + +### 解释: +1. **`spawnPoints`**:这是一个 `Transform[]` 数组,用来存储 5 个可能的生成点。你可以在 Unity 编辑器中通过拖拽场景中的物体(生成点)到这个数组中来设置这些位置。 +2. **`Random.Range(0, spawnPoints.Length)`**:随机选择一个索引,范围从 `0` 到 `spawnPoints.Length - 1`。 +3. **`Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation)`**:在选择的生成点位置生成玩家飞机(`playerPrefab`)。 + +### 在 Unity 编辑器中: +1. 将 `Player_Generated_Pos` 脚本附加到一个物体(比如一个空的 GameObject)。 +2. 在 Inspector 面板中,设置 `playerPrefab` 为你的玩家飞机预制体。 +3. 设置 `spawnPoints` 数组,确保它包含你要随机生成玩家飞机的 5 个位置点。你可以将场景中的空物体拖到该数组中,作为生成点。 + +### 生成点设置: +你可以在 Unity 场景中创建 5 个空物体,并将它们放置在你希望飞机生成的位置。然后,将这些空物体拖到 `spawnPoints` 数组中。 + +这样,当游戏开始时,玩家飞机将会在这 5 个点之间的一个位置随机生成。 \ No newline at end of file diff --git a/public/mengyanote/游戏引擎/Unity/Unity简单解决字体放大模糊问题.md b/public/mengyanote/游戏引擎/Unity/Unity简单解决字体放大模糊问题.md new file mode 100644 index 0000000..e68d45d --- /dev/null +++ b/public/mengyanote/游戏引擎/Unity/Unity简单解决字体放大模糊问题.md @@ -0,0 +1,5 @@ +把文本组件缩小十倍(以1为基准) + +然后把字体大小放大10倍 + +然后拖动适应原来的位置大小 \ No newline at end of file diff --git a/public/mengyanote/生物学科普/OTC药和处方药的区别.md b/public/mengyanote/生活科普/OTC药和处方药的区别.md similarity index 100% rename from public/mengyanote/生物学科普/OTC药和处方药的区别.md rename to public/mengyanote/生活科普/OTC药和处方药的区别.md diff --git a/public/mengyanote/生物学科普/打针和注射原理.md b/public/mengyanote/生活科普/打针和注射原理.md similarity index 100% rename from public/mengyanote/生物学科普/打针和注射原理.md rename to public/mengyanote/生活科普/打针和注射原理.md diff --git a/public/mengyanote/生物学科普/死亡后的尸体现象与死亡时间推断.md b/public/mengyanote/生物学科普/死亡后的尸体现象与死亡时间推断.md new file mode 100644 index 0000000..0754ef4 --- /dev/null +++ b/public/mengyanote/生物学科普/死亡后的尸体现象与死亡时间推断.md @@ -0,0 +1,178 @@ + +## 一、早期尸体现象 + +早期变化通常发生在**死亡后数小时至两天内**,主要包括: + +### 1. 尸冷(Algor mortis) + +- **机制**:死亡后产热停止,体温逐渐下降,直至与环境温度一致。 + +- **一般规律**: + + - 室内常温:每小时约下降 **0.83℃**。 + + - 水中:每小时下降 **3-4℃**。 + + - 高温环境(如沙漠):尸温可能不降反升。 + + - 冬季:下降速度更快,可超过 **1℃/h**。 + +- **经验公式**: + + ``` + 死后时间(小时)= (37℃ - 直肠温度) ÷ 0.83 × 系数 + 系数:春秋=1;夏季=1.4;冬季=0.7 + ``` + + +### 2. 尸僵(Rigor mortis) + +- **机制**:肌肉内ATP耗竭,肌纤维固定。 + +- **时间规律**: + + - 30分钟~2小时:开始出现。 + + - 6~8小时:全身僵硬。 + + - 12~15小时:达到高峰。 + + - 24~36小时:逐渐缓解并消失。 + +- **影响因素**:环境温度(高温→加快)、死前剧烈活动。 + + +### 3. 尸斑(Livor mortis) + +- **机制**:血液因重力下沉,淤积于低垂部位。 + +- **时间规律**: + + - 30分钟内:可见淡红色。 + + - 5~6小时:明显,按压可消退。 + + - 8小时后:血红蛋白渗入组织,颜色固定,不再随体位改变。 + +- **特殊表现**: + + - 中毒:一氧化碳中毒呈鲜红色。 + + - 冻死:尸斑呈红色。 + + +### 4. 其他早期指标 + +- **角膜混浊**:8~12小时出现。 + +- **胃内容物消化情况**:饭后2–4小时消化明显,可作为辅助判断。 + +- **尸绿**:腹部皮肤变绿,多在死亡2~3天后出现。 + + +--- + +## 二、晚期尸体现象 + +当死亡超过**数天至数周**,进入晚期变化。 + +### 1. 腐败(Putrefaction) + +- **起始**:2–3天内出现腹部尸绿,随后扩散全身。 + +- **典型表现**: + + - 5–7天:气体产生,颜面肿胀,口鼻流出液体。 + + - 数周:软组织液化,最后仅剩骨骼。 + +- **白骨化**:土中一般需7–10年。 + + +### 2. 动物破坏 + +- 苍蝇产卵→蛆→蛹→成蝇。 + +- 夏季1个月内可能食尽软组织。 + +- 蚂蚁、鼠类、犬猫等亦可造成破坏。 + + +### 3. 保存现象 + +- **尸蜡(adipocere)**:潮湿缺氧环境,1–2月起始,数月至1年可广泛形成。 + +- **木乃伊化**:干燥环境下数月后形成。 + + +--- + +## 三、死亡时间推断方法 + +### 1. 基于尸体现象 + +- **尸温下降**:常用于**12小时内**。 + +- **尸斑与尸僵**:用于**48小时内**的判断。 + +- **腐败与昆虫学**:适用于**数日以上**。 + + +### 2. 胃肠道内容物 + +- 餐后 0–2h:胃内充满食物。 + +- 餐后 2–4h:食物进入十二指肠。 + +- 餐后 6h 以上:胃已排空。 + + +### 3. 法医昆虫学 + +- 苍蝇卵:死亡后几小时即产卵。 + +- 蛆成熟:4–15天。 + +- 蛹壳存在:提示**死后约2周以上**。 + + +### 4. 超生反应 + +- **死后肌肉反应**:2小时内仍可有收缩。 + +- **瞳孔反应**:4小时内可见药物作用反应。 + +- **汗腺反应**:18–24小时可见,30小时后消失。 + + +--- + +## 四、腐败进程(时间线) + +- **2–3天**:腹部尸绿、轻度膨胀。 + +- **5–6天**:腹部膨胀显著、皮肤水泡。 + +- **2周**:腹部极度膨胀。 + +- **3–4周**:组织液化,五官难辨。 + +- **数月**:尸蜡或木乃伊。 + +- **数年**:白骨化。 + + +--- + +# 总结 + +- **短期(<48小时)**:尸冷、尸斑、尸僵为主要依据。 + +- **中期(数日至数周)**:依赖腐败程度与昆虫学。 + +- **长期(数月–数十年)**:尸蜡、木乃伊与白骨化作为参考。 + + +死亡时间的推断需**综合多种因素**:尸体现象、环境温度、衣物覆盖、胃内容物及现场条件,不能依赖单一指标。 + +--- diff --git a/public/mengyanote/生物学科普/死亡时间判断.md b/public/mengyanote/生物学科普/死亡时间判断.md deleted file mode 100644 index a1222f6..0000000 --- a/public/mengyanote/生物学科普/死亡时间判断.md +++ /dev/null @@ -1,263 +0,0 @@ -links:  -https://www.thepaper.cn/newsDetail_forward_17159257 -https://www.sohu.com/a/406707817_771937 -https://zh.wikipedia.org/zh-cn/尸体现象 - -无法提供确切的时间,仅可提供一个范围 - -从死亡现场开始,全面地记录下温度和物理环境,以及死者身上的衣物或其它覆盖物。 - -同时,尸体的血液因重力原因而聚积于身体低下部位,产生一种有色斑痕,称为尸斑;而人死后身体各个肌群也会发生变化,形成一种僵硬状态,称为尸僵。 - -如果死亡时间估计不超过48小时,在尸检之前观察到的以上这些现象都能够帮助推断死亡时间。 - -如果死者已死亡数日或数周,甚至更久,那么这些现象则无法帮助法医进行推断。这时,就要用到其他方法了,如根据尸体的腐败程度以及尸体周围昆虫的活动来推断死亡时间。 -# 一.早期变化 -## 1.尸冷 -人在死亡之后,产热停止。尸体会随即开始冷却,向外部环境散发热量,直至与环境温度相同。在春秋季节成年人尸体,室内每小时大约下降0.83度。水中尸体每小时下降3---4度;在高温季节室外尸体,死后几小时内尸温还能上升。 - -但尸体所处的环境温度会对其产生很大影响。如果尸体是在盛夏季节的沙漠地带被发现的,那么它的温度会不降反升,因为那里的温度极有可能超过40℃。而如果处于天气寒冷的季节,则尸体有可能会以超过每小时1℃的速度降温。 - -另外,很多疾病会导致高烧,因此死者在死亡时的体温可能超过37℃的正常体温,这会影响对死亡时间的推断。一般而言,如果死亡发生于尸体被发现的12小时内,法医病理学家就只需要通过尸冷情况来推断死亡时间。 - -据国内的尸温研究报告,死后4---5小时内,体内产生热尚未完全停止,尸温平均每小时下降0.58度;死后5---16小时,产热完全停止,尸温平均每小时下降0.97度;死后16---24小时,因是尸文与环境的的温差缩小,尸温下降变慢,平均每小时下降0.54度。该项研究建立了死亡时间计算公式,经过实际应用和完善得出一下简便公式: - -死后经过时间(小时)=37度-尸体直肠温度/0.83*系数 - -(所乘系数:春秋季为1,夏季为1.4,冬季为0.7。) -## 2.尸僵 -一个人死亡后,关节和肌肉均呈松弛状态。2~5个小时后,肌肉开始收缩,导致关节僵硬。尸僵最快出现是在死后30分钟左右,通常是在死后2---3小时,一部分肌肉开始僵直,6---8小时遍及全身各关节,12---15小时达到高峰。这种状态持续到24---36小时又开始缓解。在夏天2---3天,在春秋季节3---4天,冬天3---7天尸僵逐渐消失。 - -此外还有尸体痉挛、皮革样斑、角膜混浊、自溶等均为早期尸体变化。 - -也就是说,尸僵也受温度影响,温度高时,尸僵发生得早。另外,如果死者在死亡前不久进行过剧烈的体力活动,也会加速尸僵的形成。 -## 3.尸斑 -人死亡后,血液便停止循环,并在重力的影响下聚集于身体的最低处。 - -例如,如果死者死亡时躺在地上,血液就会向下沉积于死者背部,此时这个区域就会呈粉红色,并逐渐变成紫色,而上半部分则会变得苍白。 - -在尸斑的形成过程中,如果有人或物体接触尸体,它的表面就会产生相应的印迹。这也就意味着,如果发现这样的印迹,就说明有人曾移动过尸体。 - -尸斑痕迹还有可能因物体的局部压迫而没有形成血液积聚,如尸体仰卧于地面或其他硬物表面时,背部和臀部由于受到压迫,常呈现苍白色而不见尸斑。 - -尸斑的产生非常快,通常在死后30分钟内即可见,而在几个小时后,尸斑就逐渐固定下来了。接着,形成尸斑的区域的组织液便渗入血管内,促使红细胞膜破裂,并逐渐向外渗入周围的组织中,从而导致尸斑颜色加深、范围扩大。 - -尸斑的形成、发展可分为几个阶段。 - -尸斑形成的最初阶段,称为**坠积期**。此期在死后5---6小时内达到明显可见。可持续6---12小时。坠积期尸斑被按压尸斑退色或消失,出去按压则尸斑又重现。在此前阶段如果变动尸体位置。尸斑也随之改变,在新的低下部位重新出现。 - -尸斑发展的第二阶段为**扩散期**。从死亡后发展到扩散期约需8小时,延续至26---32小时。此期被血红蛋白染红的血浆浸透到周围组织,此时按压尸斑已经不能完全消失,只是稍许退色,停止按压后尸斑恢复原色也慢。变动尸体位置,部分尸斑可能移位,部分尸斑则保留在原来形成的部位。 - -尸斑发展的第三阶段为浸润到组织中的时间较久,此期用手指压迫尸斑不再改变颜色,也不再消失,变动尸体位置则尸斑不再转移。 某些中毒尸斑颜色特异,一氧化碳中毒时呈鲜红色,氧化物中毒呈樱桃红色,亚硝酸盐、氯酸钾中毒呈灰褐色,冻死时呈红色。 -## 4.其他 -此外,眼球玻璃体液的浑浊程度、心肌pH值(酸度或碱度)、肌肉超声波检查、骨骼肌的电活动、创伤形态等也都能为推断死亡时间提供较大帮助。多年来,对尸体胃内容物的检查一直是尸体解剖标准程序的重要一环。 - -因为化学物质和未完全消化的药物可以作为确定死亡原因和死亡方式的重要证据。对胃内容物的分析也可以用来帮助推断死亡时间。 - -通常胃的消化过程大约需要2~4个小时,如果死者在死亡时胃内有食物,则可大致推定该人约在不超过2~4小时前死亡。 - -然而,死者死亡时的身体状况各不相同,决定消化时间的变量也较多,故胃内容物只能作为参考的补强证据。此外,还有一些消化过程甚至发生在死亡和腐烂过程中,也需要特别注意。 - -在死亡发生后的一两天中,尸体内仍会发生一些变化,这些变化都有助于我们推断死亡时间。例如,尸体会开始腐烂,发生颜色变化,并且在腹部和臀部附近产生尸绿。尸绿的出现足以证明死者已经死亡至少2~3天。 - -# 二.晚期变化 - -继早期尸体变化后出现腐败、毁坏、白骨化,以及保存型的木乃伊、尸蜡、鞣尸等皆为晚期尸体变化。 - -## **1、腐败** - -从死后第2---3昼夜开始产生大量气体(硫化氢、甲烷、氨等),散发出难闻的腐败臭味。 - -腐败一般开始于大肠,主要是肠内细菌引起,在右下腹的皮肤上出现绿色斑块,然后扩延至全身,在12---14天腐败气体进入皮下组织,颜面肿胀呈黑色,眼球突出,口唇变厚、舌尖挺出,腹部膨隆,呈所谓巨人观。由于腹腔内的腐败气体的压力作用,使口鼻腔流出血性泡沫液体,排出大小便,阴囊与阴茎膨大成球状,子宫内胎儿娩出,即死后分娩。 - -在腐败过程中,尸体所有软组织分解消失露出白骨。在空气中白骨化所需的时间随季节不同,成人尸体在夏季需半个月至1个月以上。在土中白骨化经过时间长,季节变化少,在成人需7---10年,小儿尸体4---5年,幼儿尸体2---3年,新生儿尸体大约1年。 - -根据尸体腐败发展的程度,可大致推测死后经过时间,急剧的尸体腐败不影响骨损伤鉴定,但对生前伤或死后伤鉴别以及疾病死亡原因的确定会造成很大困难,甚至无法鉴定。 - -## **2、动物毁坏尸体** - -各类昆虫、啮齿类和食肉类动物也能严重损伤尸体,甚至毁殆尽。 - -蝇类对尸体的毁坏最为严重,人死后苍蝇就即可在尸体眼角、口、鼻孔、肛门、伤口等周围产卵,暖和天气经过1---3天卵孵成蛆,软组织被食成蜂窝状。蛆又可以长成蛹,过两周又成蝇,然后再开始新繁殖周期。在条件适宜时,成人尸体在1个月左右就能被蝇类吃尽软组织。 - -蚂蚁也能破坏尸体,一般认为,在两个月内,蚂蚁能将一巨成人尸体咬食得只剩骨骼。 - -其他动物破坏尸体(如犬、猫、狼、狐、鼠、鸟类等),均能留下有特征的咬痕。水中尸体可被鱼、虾、蟹等咬食。 - -# **三、死后经过时间推断** - -推断死亡时间是法医鉴定的重要的内容,是在命案现场或对无名尸体检验时要解决的主要问题之一。知道了死亡时间,可以查清某人有无作案时间,可以核对证人或嫌疑人的供述。 - -## **1、根据尸体现象推断死亡时间** - -10小时之内尸温每小时下降1度 - -10小时以上 尸温每小时下降0.5度 - -角膜轻度混浊8---12小时 - -瞳孔不能透见48小时左右 - -尸体新鲜尚未出现尸斑及尸僵1小时以内 - -尸斑开始出现1---2小时 - -尸斑轻度,指压退色,尸僵限于颌、颈关节2-3小时内 - -尸斑明显,但变动尸体可消退,并于新的低下部又形成新尸斑;尸僵延及上肢,如人为使其缓解可再出现4-5小时内 - -尸斑、尸僵均明显;指压与变更体位尸斑不消失7-8小时 - -尸斑尸僵存在,伴角膜中度混浊10-12小时 - -尸斑可以转移15小时之内 - -尸斑发展高峰15小时左右 - -尸僵开始出现2---3小时 - -尸僵发展高峰12---15小时 - -尸僵下颌关节开始缓解30小时 - -上肢尸僵开始缓解,死后经过时间为36小时 - -下肢尸僵缓解,角膜高度混浊(不透明),死后经过时间为48小时 - -尸僵消失3---4日(在夏天2---3天,在春秋季节3---4天,冬天3---7天) - -下腹部腐败变色24---48小时 - -腐败发展,出现水泡,死后经过时间为2-3日 - -腹部皮肤出现尸绿;口、眼角、鼻孔有蝇蛆,死后经过时间为24小时 - -蛆侵蚀皮肤4日以上 - -蝇蛆发育成蝇,死后经过时间为8日 - -蛹脱壳成蝇,脱壳存在,死后经过时间为2-3周 - -皮下脂肪脂化,死后经过时间为1-2个月 - -蛆食尽内脏1个月左右 - -尸蜡形成,死后经过时间为2-4个月 - -肌肉尸蜡化,死后经过时间为3个月后至1年后 - -全身尸蜡化(水中)1年左右 - -白骨化(土葬),死后经过时间为3-4年 - -韧带和软骨消失(土葬),死后经过时间为5年 - -骨中脂肪消失,死后经过时间为5-10年 - -骨开始风化,死后经过时间为10-15年 - -骨组织脆弱化,死后经过时间为50年 - -成人白骨化(土中)7---10年 - -成人木乃伊3个月以上 - -### **尸体腐败现象在不同季节开始出现的时间** - -尸体腐败现象夏季秋季冬季 - -腹部膨胀4---5小时8---10小时2—3天 - -腐败绿斑约12小时约24小时3---5天 - -腐败血管网1---2天2---3天5---7天 - -腐败水泡1---2天3---5天一般不出现 - -腐败巨人观2---3天3---7天15---30天 - -## **2、根据尸体胃肠道内容物推断死亡时间** - -胃内充满食物,死亡发生在餐中或餐后不久 - -胃内容物移向十二指肠,死亡发生在餐后2-3小时 - -十二指肠有消化食物及其残渣,死亡发生在餐后4-5小时 - -胃、十二指肠均已空虚,死亡发生在餐后6小时以上 - -根据死者胃肠道内容物可以推断其死前最后一次进餐至死亡所经过的时间,从而推断死亡时间,胃内容并可以确定事物成分或进食地点等。虽然每个人饮食习惯、消化能力各不相同,死后胃肠活动功能还能持续一段时间,但是绝大多数人食物进入、停留于各段消化道时间呈规律性变化。 - -在法医学的实践中,胃肠道食物消化和推进程度的利用价值不逊于尸表现象。若胃内米饭、蔬菜外形完整,只有少量食物进入十二指肠,应为饭后1—2小时内。若胃内食物部分呈乳糜状,尚有极少量饭粒、菜渣,则食物已进入大肠,应为饭后4小时内。若胃内容全部排空,有时残留青菜根纤维或海带等,应为饭后6小时以上。根据凶杀案件尸体的胃肠道内容物检查多数会得到重要线索和证据。因此,应作为一项常规检查。 - -## 3、根据蝇蛆生长规律推断死亡时间 - -蝇蛆是造成尸体毁坏最常见的一类昆虫。 - -苍蝇从成虫产卵,由卵孵化成蛆,蛆变成蛹,蛹发育成蝇,破壳起飞,在现场上留下蛹壳,完成一代苍蝇的生活史,因此可以借助苍蝇卵、蛆、蛹出现的不同阶段推断尸体的死亡时间。 - -在夏季,死后十余分钟苍蝇即可在尸体眼角、鼻孔、口角、阴部和暴露的创口等处产卵,每次产卵约150粒。在30℃条件下,经10-14小时蝇卵孵化成蛆。 - -蛆每天可生长0.24-0.3cm,4-15天生长成熟,体长可达1.2cm。 - -成熟姐继而潜入附近的泥土内变成蛹,再经1周左右,破壳成为幼蝇。 - -因此,若在夏季,尸体周围发现有蛹壳和幼蝇或卵即可推断死后经过的时间约为2周以上,春秋季完成同一过程约需4周。 - -根据蝇姐生长发育的情况,考察现场环境气温等条件,就可大致推断死后经过时间。 - -此外,蝇蛆可分泌富含蛋白质溶解酶的消化液,能将皮肤和黏膜溶解,继而侵入皮下、肌组织甚至内脏。 - -婴儿尸体在1-8天,成人尸体3-4周可被其蚀蛀得仅剩骨骼。 - -## 4、根据超生反应推断死亡时间 - -生命活动终止以后,生前的代谢过程尚能维持一定的时间,因此可以利用超生反应来推断死亡时间。 - -超生反应包括肉肌的超生反应,死后皮下出血反应,瞳孔的超生反应,汗腺的超生反应等。 - -①肌肉的超生反应:死后2小时,肌肉受机械刺激后可发生收缩反应。电刺激法能更细致地显示死后肌肉收缩。 - -②瞳孔的超生反应:死后4小时结膜囊内滴入毒扁豆碱或阿托品等作用于自主神经系统的药物可发生相应的缩瞳或散瞳反应。 - -③汗腺的超生反应:皮下注射1%肾上腺素的部位,死后18小时内,可见汗液分泌,死后24小时内汗液分泌少量,死后30小时后消失。 - -## 5、根据尸温推断死亡时间 - -根据死后尸体温度下降的变化规律来推断死亡时间,是法医学中意义最大的一种推断死亡时间的方法。 - -许多法医学家做过许多广泛的研究,认为这种方法是最为可靠的。 - -人死后的尸体温度会受多方面因素的影响,比如环境温度会直接影响到尸体表面的温度,因此,在法医学上一般以肝和直肠的温度作为尸体的核心温度,因为尸体内部的温度由于有皮肤、皮下脂肪及肌肉保护,受到环境温度影响的可能性较小。 - -在法医学鉴定中一般以测量直肠温度为准。正确测量直肠温度的方式是将直肠测温仪探头从肛门处深插入直肠内15 cm左右,一般刚死亡的死者,直肠温度在34.2℃至37.6℃之间浮动,平均为36.9℃。 - -测算时,仅需间隔1小时测量两次尸体直肠温度,然后通过参考曲线图和公式就可以计算出死亡时间。 - -尸体直肠冷却的规律(尸冷),一般在常温下死后10小时以内,每小时平均下降0.5~1℃; 肥胖尸体在死亡后最初10小时,尸温每小时平均下降0.75℃,消瘦尸体每小时平均下降1℃。 夏季尸体温度下降率较春秋时节慢1.4倍,冬季快0.7倍。 - -**根据尸冷推断死亡时间的公式是:** -**T=37摄氏度-直肠温度/0.83摄氏度xK** - -其中,T为死后经过时间;K为系数,春秋为1.0,夏季为1.4,冬季为0.7。 - -春秋时节的一具消瘦尸体,通过直肠测量测得尸温为24℃,这意味着尸温下降了13℃,(一般临终直肠温度在34.2℃至37.6℃之间浮动,平均为36.9℃) - -按上述方法公式计算,(37-24) ÷0.83×1=15.6,所以这具尸体死了15.6个小时,接近16个小时。 - -虽然通过尸体温度推断死亡时间具有一定的准确性,但是依然会受到许多因素的影响:比如环境温度,昼夜温差、通风情况,雨、雪、潮湿、衣着状况等。此外,死者的年龄,身体胖瘦、裸尸与着装尸体、有无覆盖物等等,都会影响到尸体温度。所以在判断死亡时间的时候,要重点排除这些因素的影响,取出一个最合理的死亡时间。 - -## 6、根据现场勘察所见推断死亡时间 - -包括尸体下植物的情况,钟表停止的时刻,降雨后衣服淋湿的情况,报纸、书信、日记、牛乳等的日期。 - -如:①动物吃尽尸体软组织,需3-6周 - -②尸体下的草和绿叶退色(夏季花草生长期),需3-8日 -# 四.人死亡后腐烂过程 -2天至3天:腐烂从人体的腹部开始,尸体内组织因分解后产生气体,因此尸体开始胀大。 -3天至4天:腐烂开始从腹部扩散,静脉变得较褪色。 -5天至6天:因细菌分解尸体生成的气体的缘故,腹部胀得更大和皮肤开始出现水泡。 -2个星期:腹部变得非常紧和圆鼓。 -3个星期:组织开始变得柔和。 -4个星期:软的组织开始液化,而且面孔变得无法认出。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/C++中的语法糖.md b/public/mengyanote/编程语言/C++/C++中的语法糖.md new file mode 100644 index 0000000..6f141bb --- /dev/null +++ b/public/mengyanote/编程语言/C++/C++中的语法糖.md @@ -0,0 +1,73 @@ +C++中有不少语法糖,以下是一些常见的例子: + +范围-based for循环 + +传统的 for 循环遍历容器需要使用迭代器,较为繁琐。范围 - based for循环则更简洁,例如: + +#include +#include + +int main() { + std::vector v = {1, 2, 3, 4, 5}; + for (int num : v) { + std::cout << num << " "; + } + return 0; +} +  + +初始化列表 + +可以使用花括号初始化列表来初始化对象或容器,例如: + +#include +#include + +int main() { + // 用初始化列表初始化vector + std::vector v = {1, 2, 3, 4, 5}; + // 用初始化列表初始化自定义类对象 + class MyClass { + public: + int num; + MyClass(int n) : num(n) {} + }; + MyClass obj{10}; + std::cout << obj.num << std::endl; + return 0; +} +  + +auto关键字 + + auto 关键字让编译器根据初始化表达式自动推导变量的类型,减少了类型声明的冗长,例如: + +#include +#include + +int main() { + std::vector v = {1, 2, 3, 4, 5}; + // 使用auto自动推导迭代器类型 + for (auto it = v.begin(); it!= v.end(); ++it) { + std::cout << *it << " "; + } + return 0; +} +  + +模板别名 + +通过 using 关键字定义模板别名,简化复杂的模板类型定义,例如: + +#include +#include +#include + +int main() { + // 定义模板别名 + using MyMap = std::map; + MyMap myMap; + myMap["key"] = 10; + std::cout << myMap["key"] << std::endl; + return 0; +} \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/C++关联文件.md b/public/mengyanote/编程语言/C++/C++关联文件.md new file mode 100644 index 0000000..da3a1c0 --- /dev/null +++ b/public/mengyanote/编程语言/C++/C++关联文件.md @@ -0,0 +1,23 @@ +### 源文件 + +- **.cpp 或 .cxx 或 .cc :**C++源文件的扩展名,用于编写C++代码,包含函数、类、变量等定义和实现。 +- **.h 或 .hpp 或 .hxx :**头文件扩展名,用于声明函数原型、类定义、常量和变量等,以便在多个源文件中共享声明。 + +### 项目和配置文件 + +- **.vcxproj :**Visual C++项目文件,用于Visual Studio开发环境,包含项目的配置信息、源文件列表、引用等。 +- **.sln :**解决方案文件,用于组织多个相关的项目,包含项目之间的依赖关系等信息。 +- **CMakeLists.txt :**使用CMake构建系统时的项目配置文件,用于描述项目的源文件、目标、依赖等信息,可生成不同平台和编译器的项目文件。 +- **Makefile :**在Unix和类Unix系统中,用于定义编译规则和目标,指定源文件如何编译链接成可执行文件或库。 + +### 库文件 + +- **.lib :**Windows下的静态库文件,包含已编译的代码和数据,在链接时被直接复制到可执行文件中。 +- **.a :**Unix和类Unix系统下的静态库文件,作用与Windows下的 .lib 类似。 +- **.dll :**Windows下的动态链接库文件,包含可在运行时被加载和调用的代码和数据。 +- **.so :**Unix和类Unix系统下的共享库文件,类似于Windows的 .dll ,在运行时动态链接。 + +### 可执行文件 + +- **.exe :**Windows下的可执行文件,是编译链接后的最终产物,可在操作系统中直接运行。 +- 在Unix和类Unix系统中,可执行文件没有特定的扩展名,但通常具有可执行权限,通过命令行或图形界面启动。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/C++模拟考试.md b/public/mengyanote/编程语言/C++/C++模拟考试.md new file mode 100644 index 0000000..390e75c --- /dev/null +++ b/public/mengyanote/编程语言/C++/C++模拟考试.md @@ -0,0 +1,345 @@ + +# 计算机二级 C++ 试题 + +**考试时间:120 分钟** +**满分:100 分** + +> **说明:** +> 本试卷不涉及模板和智能指针,重点考查面向对象编程和简单算法的编程能力。 + +--- + +## 一、选择题 (共10题,每题2分,共20分) + +1. 关于 C++ 的面向对象特性,下列描述正确的是: D + A. 封装使得数据与对数据的操作组合在一起 + B. 继承支持代码复用 + C. 多态允许同一操作在不同对象上表现出不同的行为 + D. 以上全部 + +2. 在 C++ 中,class的默认访问权限是: C + A. public + B. protected + C. private + D. 无默认权限 + +3. 当类中存在虚函数时,运行时调用哪个函数版本取决于: A + A. 指针或引用所指对象的实际类型 + B. 指针或引用的类型 + C. 编译时绑定 + D. 函数的参数列表 + +4. 如果希望禁止类对象的拷贝,通常的做法是: C + A. 不提供拷贝构造函数和赋值运算符 + B. 将拷贝构造函数和赋值运算符声明为私有 + C. 使用 const 修饰所有成员变量 + D. 以上都不正确 + +5. 在 C++ 中,struct的默认访问权限是: A + A. public + B. protected + C. private + D. 无默认权限 + +6. 以下哪条语句正确包含了 iostream 头文件? C + A. `#import ` + B. `#include iostream` + C. `#include ` + D. `using namespace std;` + +7. 在 C++ 中,下列哪个运算符用于获取变量的地址? A + A. & + B. * + C. -> + D. % + +8. 以下哪一项是正确的函数声明? B + A. `int func(int a, b);` + B. `int func(int a, int b);` + C. `func(int a, int b);` + D. `int func(a, b);` + +9. 下列选项中,哪一个不是 C++ 的访问控制符? D + A. public + B. private + C. protected + D. external + +10. 关于 C++ 中的引用,以下说法正确的是: A + A. 引用必须在定义时初始化 + B. 引用可以改变绑定的对象 + C. 引用可以为 NULL + D. 引用占用额外的内存空间 + +--- + +## 二、填空题 (共4题,每题2.5分,共10分) + +1. C++ 的面向对象三大特性是封装、______继承__ 和多态。 + +2. 成员函数在类外定义时需要使用 ______::__ 运算符指定其所属的类。 + +3. 如果一个函数在基类中声明为虚函数,那么在派生类中重写该函数时可以选择在函数声明后加上 ______override__ 关键字以提高代码可读性。 + +4. 递归算法必须包含一个或多个 ______终止__ 条件,以确保递归能够终止。 + +--- + + + +--- + +## 三、代码分析题 (共2题,每题10分,共20分) + + +### 题目1 + +阅读下面的代码,并回答问题: + +```cpp +#include +using namespace std; + +void modifyPointer(int *p) { + *p = 20; +} + +int main() { + int a = 10; + int *ptr = &a; + + modifyPointer(ptr); + + cout << a << endl; + + return 0; +} +``` +1.程序的输出结果是什么?20 +2.解释指针 ptr 在 modifyPointer 函数调用过程中的作用,以及它对变量 a 的影响。指向a的地址 修改a的值 + + +### 题目2 + +阅读下面的代码,并回答问题: + +```cpp +#include +using namespace std; + +class A { +public: + A() { + cout << "A Constructor" << endl; + } + ~A() { + cout << "A Destructor" << endl; + } +}; + +class B : public A { +public: + B() { + cout << "B Constructor" << endl; + } + ~B() { + cout << "B Destructor" << endl; + } +}; + +int main() { + B obj; + return 0; +} +``` +1.程序的输出结果是什么? + +A Constructor + +B Constructor + +B Destructor + +A Destructor + +2.解释下子类与父类的构造、析构函数的调用顺序。子类构造过了父类,子类析构过了父类 + +## 四、编程题 (共3题,共40分) + +### 题目:基于继承与多态的学生管理系统设计 — 10分 + +**要求:** +- 定义一个基类 `Person`,包含下列内容: + - **保护成员**:姓名(`string`) + - 构造函数:用于初始化姓名 + - **虚函数** `display()`:用于输出人员的基本信息 +- 定义一个派生类 `Student`,继承自 `Person`,并添加下列私有成员: + - 学号(`int`) + - 成绩(`float`) +- 在 `Student` 类中,重写基类中的 `display()` 函数,输出学生的姓名、学号和成绩。 +- 在 `main()` 函数中,创建至少两个 `Student` 对象,并使用基类 `Person` 类型的指针调用 `display()` 函数,体现虚函数的多态特性。 +- 注意:请确保在基类中定义虚析构函数,以便正确释放派生类对象,请填充下面的代码实现。 + +**示例代码:** +```cpp +#include +#include +using namespace std; + +// 基类 Person,包含姓名和虚函数 display() +class Person { + protected: + string name; + public: + + Person(string n, int i, float g){ + name = n; + } + + virtual void display(){ + + } +}; + +// 派生类 Student,继承自 Person,并添加学号和成绩 +class Student :public Person { + private: + int id; + float grade; + + public: + Student(string n,int i,float g) override{ + name =n; + id = i; + grade = g; + } + + virtual void display() override{ + cout<<"学生的姓名:"<display(); + p2->display(); + + // 释放内存 + delete p1; + delete p2; + + return 0; +} +``` + + +--- + +### 题目2:递归实现二分查找 — 20分 + +**要求:** +- 编写一个 C++ 程序,使用递归实现二分查找算法,在一个有序的整数数组中查找目标值。 +- 程序应要求用户输入一个目标值,若目标值存在,则输出其在数组中的下标;否则输出 -1。 +- 代码中应包含对输入数据的提示以及对边界条件的合理判断。 + +**示例代码:** +```cpp +#include +using namespace std; + +// 递归实现二分查找函数 请你填充此函数实现 +int binarySearch(int arr[], int left, int right, int target) { + while (left<=right){ + int mid = left + (right-left)/2; + if(arr[mid]==target){ + return mid; + }else if(arr[mid]> target; + + int index = binarySearch(arr, 0, n - 1, target); + if(index != -1) { + cout << "目标值 " << target << " 在数组中的下标为:" << index << endl; + } else { + cout << "目标值 " << target << " 不在数组中。" << endl; + } + return 0; +} +``` + +--- + +### 题目3:冒泡排序实现 — 10分 + +**要求:** +- 编写一个 C++ 程序,定义一个整数数组,对数组进行冒泡排序。 +- 程序应先输出排序前的数组,再输出排序后的数组。 +- 代码要求体现出对冒泡排序核心思想的理解,结构清晰、注释明确,并注意边界情况的处理。 + +**示例代码:** +```cpp +#include +using namespace std; + +// 冒泡排序函数 请你填充这个函数 +void bubbleSort(int arr[], int n) { + for(int i=0;iarr[j+1]){ + swap(arr[j],arr[j+1]); + } + } +} + +// 打印数组函数 +void printArray(const int arr[], int n) { + for (int i = 0; i < n; i++) { + cout << arr[i] << " "; + } + cout << endl; +} + +int main() { + int arr[] = { 5, 3, 8, 6, 2, 7, 4, 1 }; + int n = sizeof(arr) / sizeof(arr[0]); + + cout << "排序前的数组:" << endl; + printArray(arr, n); + + bubbleSort(arr, n); + + cout << "排序后的数组:" << endl; + printArray(arr, n); + + return 0; +} +``` + + +**注意事项:** +- 请仔细阅读每道题目的要求,确保在答题时详细阐述思路及关键实现步骤。 +- 编程题请在本地编译测试确保代码正确无误。 + +祝各位考生考试顺利! \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/C语言学习笔记.md b/public/mengyanote/编程语言/C++/C语言学习笔记.md new file mode 100644 index 0000000..68bfe8e --- /dev/null +++ b/public/mengyanote/编程语言/C++/C语言学习笔记.md @@ -0,0 +1,15 @@ +## C语言学习笔记 + +1.scanf()不能输入空格,用fgets可以解决这个问题,但fgets需要对回车进行处理 + +```c + // 读取输入字符串 + fgets(str, 81, stdin); + + // 去除输入字符串中的换行符 + int len = strlen(str); + if (str[len - 1] == '\n') { + str[len - 1] = '\0'; + } +``` + diff --git a/public/mengyanote/编程语言/C++/值传递和地址传递的区别.md b/public/mengyanote/编程语言/C++/值传递和地址传递的区别.md new file mode 100644 index 0000000..b7ae2c1 --- /dev/null +++ b/public/mengyanote/编程语言/C++/值传递和地址传递的区别.md @@ -0,0 +1,60 @@ +在编程中,函数调用时的数据传递方式主要分为值传递和地址传递(也称为引用传递,在 C++ 中还有引用类型专门用于引用传递),下面详细介绍它们的区别: + +### 基本概念 +- **值传递**:在函数调用时,将实际参数的值复制一份传递给形式参数。函数内部对形式参数的修改不会影响到实际参数。 +- **地址传递**:在函数调用时,将实际参数的内存地址传递给形式参数。函数内部通过该地址可以直接访问和修改实际参数所指向的内存空间中的值。 + +### 语法示例 +以下是 C++ 语言中值传递和地址传递的示例代码: +```cpp +#include + +// 值传递函数 +void valuePass(int num) { + num = num + 1; + std::cout << "Inside valuePass, num: " << num << std::endl; +} + +// 地址传递函数(使用指针) +void addressPass(int* numPtr) { + *numPtr = *numPtr + 1; + std::cout << "Inside addressPass, *numPtr: " << *numPtr << std::endl; +} + +int main() { + int value = 10; + + // 值传递调用 + std::cout << "Before valuePass, value: " << value << std::endl; + valuePass(value); + std::cout << "After valuePass, value: " << value << std::endl; + + // 地址传递调用 + std::cout << "Before addressPass, value: " << value << std::endl; + addressPass(&value); + std::cout << "After addressPass, value: " << value << std::endl; + + return 0; +} +``` +### 区别分析 + +#### 1. 数据复制情况 +- **值传递**:会创建实际参数的副本,将副本传递给函数。这意味着在函数内部操作的是这个副本,而不是原始数据。例如上述代码中,`valuePass` 函数接收到的 `num` 是 `value` 的一个副本,对 `num` 的修改不会影响到 `main` 函数中的 `value`。 +- **地址传递**:不会复制实际参数的值,而是传递实际参数的地址。函数内部通过该地址直接访问和操作原始数据。如 `addressPass` 函数接收到的是 `value` 的地址,通过解引用操作可以直接修改 `value` 的值。 + +#### 2. 内存开销 +- **值传递**:由于需要复制实际参数的值,对于大型数据结构(如大数组、大对象),会占用额外的内存空间,增加内存开销。 +- **地址传递**:只传递地址,无论实际参数的数据量多大,传递的地址通常只占用固定大小的内存空间(如在 32 位系统上指针通常占 4 字节,64 位系统上占 8 字节),内存开销较小。 + +#### 3. 对实际参数的影响 +- **值传递**:函数内部对形式参数的修改不会影响到实际参数。在上述代码中,`valuePass` 函数执行完后,`main` 函数中的 `value` 值保持不变。 +- **地址传递**:函数内部对形式参数所指向的内存空间的修改会直接影响到实际参数。在 `addressPass` 函数中修改 `*numPtr` 的值,实际上就是修改了 `main` 函数中 `value` 的值。 + +#### 4. 函数调用的安全性 +- **值传递**:由于函数内部操作的是副本,不会意外修改原始数据,因此在某些情况下可以保证数据的安全性。例如,当你不希望函数修改原始数据时,使用值传递是一个好选择。 +- **地址传递**:如果函数内部不小心对指针进行了错误的操作,可能会导致原始数据被意外修改,甚至可能引发内存错误(如空指针解引用、越界访问等)。 + +#### 5. 代码可读性和可维护性 +- **值传递**:函数的行为相对简单,容易理解,因为它不会影响外部的实际参数。调用者可以清楚地知道函数内部不会修改传入的数据。 +- **地址传递**:使用地址传递可以在函数内部修改外部数据,这在某些情况下可以使代码更加简洁,但也可能会增加代码的复杂度,需要调用者更加小心地处理。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/变量使用set,get方法原因.md b/public/mengyanote/编程语言/C++/变量使用set,get方法原因.md new file mode 100644 index 0000000..72607eb --- /dev/null +++ b/public/mengyanote/编程语言/C++/变量使用set,get方法原因.md @@ -0,0 +1,21 @@ +在面向对象编程中,不直接修改变量而使用get和set函数(通常称为访问器和修改器方法)有以下几个重要原因: + +数据封装 + +- 将变量(通常称为成员变量或属性)通过get和set函数封装起来,可以隐藏类的内部实现细节。外部代码只能通过这些函数来访问和修改属性,而无法直接操作,这样可以避免外部代码对内部数据的随意访问和修改,增强了类的独立性和安全性。 + +数据验证 + +- 在set函数中,可以对要设置的值进行合法性验证。例如,一个表示人的年龄的属性,在set函数中可以添加逻辑来确保设置的年龄是一个合理的数值,防止出现负数或过大的不合理值,从而保证数据的完整性和正确性。 + +控制访问权限 + +- 通过get和set函数,可以更精确地控制对属性的访问权限。可以将某些属性设置为只读(只有get函数,没有set函数),或者只允许在特定条件下进行修改,这样可以更好地满足不同的业务需求。 + +实现代码复用 + +- 当需要对属性的访问或修改进行一些额外的操作时,比如记录属性的访问日志、在属性值变化时触发其他相关的操作等,只需要在get和set函数中添加相应的代码,而不需要在所有访问该属性的地方都进行修改,提高了代码的可维护性和复用性。 + +便于代码扩展和维护 + +- 如果未来需要对属性的存储方式或访问逻辑进行修改,只需要在get和set函数内部进行修改,而不会影响到外部调用代码,使得代码的扩展性和维护性更好。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/多个set方法.md b/public/mengyanote/编程语言/C++/多个set方法.md new file mode 100644 index 0000000..05a1a15 --- /dev/null +++ b/public/mengyanote/编程语言/C++/多个set方法.md @@ -0,0 +1,51 @@ +当变量有多种 set 方法时,可以通过以下几种方式来处理: + +方法重载 + +在支持方法重载的编程语言中,如Java、C#等,可以定义多个同名的 set 方法,但参数列表不同。例如,一个 set 方法可以接受一个整数参数来设置变量,另一个 set 方法可以接受一个字符串参数并根据字符串的内容来设置变量。 + +java + +public class MyClass { + private int myVariable; + + public void setMyVariable(int value) { + myVariable = value; + } + + public void setMyVariable(String value) { + myVariable = Integer.parseInt(value); + } +} +  + +不同的方法名 + +如果方法的功能差异较大,也可以使用不同的方法名来表示不同的设置方式。比如,一个方法用于从文件中读取值来设置变量,另一个方法用于从网络获取值来设置变量,可以分别命名为 setVariableFromFile 和 setVariableFromNetwork 。 + +使用参数标志或枚举 + +可以在 set 方法中使用参数标志或枚举类型来区分不同的设置方式。例如,定义一个枚举类型来表示设置变量的不同来源,然后在 set 方法中根据传入的枚举值来执行不同的设置逻辑。 + +java + +public class MyClass { + private int myVariable; + + public enum SetSource { + FROM_FILE, FROM_NETWORK + } + + public void setMyVariable(int value, SetSource source) { + if (source == SetSource.FROM_FILE) { + // 从文件设置变量的逻辑 + myVariable = value; + } else if (source == SetSource.FROM_NETWORK) { + // 从网络设置变量的逻辑 + myVariable = value; + } + } +} +  + +这样可以根据不同的需求灵活选择合适的方式来设置变量,同时保持代码的清晰和可维护性。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/指针变量的区别.md b/public/mengyanote/编程语言/C++/指针变量的区别.md new file mode 100644 index 0000000..e6f2720 --- /dev/null +++ b/public/mengyanote/编程语言/C++/指针变量的区别.md @@ -0,0 +1,8 @@ +在C和C++语言中,`int* a` 和 `int *a` 本质上没有区别,它们都表示定义了一个指向 `int` 类型数据的指针变量 `a`。以下是关于它们的详细说明: + +- **从语法角度看**:这两种写法都是合法的C和C++ 语法,用于声明一个指针变量。`*` 是指针声明符,用来表示后面的变量是一个指针。在这两种写法中,`*` 都与变量名 `a` 结合,表示 `a` 是一个指针,它可以存储一个 `int` 类型数据的内存地址。 +- **从阅读习惯和风格角度看** + - `int* a`:这种写法将 `*` 紧跟在类型名 `int` 后面,强调 `*` 是类型的一部分,即 `int*` 被视为一个整体,表示“指向 `int` 的指针”类型。这种写法在一些代码风格中更受欢迎,因为它使代码看起来更紧凑,类型定义更清晰,特别是在同时声明多个指针变量时,如 `int* a, *b, *c;`,可以很直观地看出 `a`、`b`、`c` 都是 `int` 型指针。 + - `int *a`:这种写法将 `*` 靠近变量名 `a`,更加强调 `a` 是一个指针变量,`*` 是用来修饰 `a` 的。有些程序员更喜欢这种写法,因为它更突出了变量的性质是指针,在阅读代码时,更容易将注意力集中在变量 `a` 本身是一个指针这一事实上。 + +虽然在功能上没有区别,但在实际使用中,可能会根据个人或团队的编程习惯和代码风格来选择使用哪种形式。需要注意的是,在同时声明多个变量时,如果采用 `int* a, b;` 的形式,会让人误以为 `b` 也是 `int` 型指针,但实际上 `b` 是一个普通的 `int` 型变量。为了避免这种混淆,更清晰的做法是每个指针变量都单独声明,如 `int* a; int* b;` 或者都采用 `int *a; int *b;` 的形式。 diff --git a/public/mengyanote/编程语言/C++/指针简单讲解.md b/public/mengyanote/编程语言/C++/指针简单讲解.md new file mode 100644 index 0000000..2fe96c9 --- /dev/null +++ b/public/mengyanote/编程语言/C++/指针简单讲解.md @@ -0,0 +1,111 @@ +下面将详细介绍指针的核心内容,包括指针声明、指针运算、指针与数组的关系以及二级指针,并结合代码示例和内存图进行说明。 + +### 1. 指针声明:`int *p` 的正确写法 + +在 C 和 C++ 中,指针声明的语法是 `数据类型 *指针变量名`。`int *p` 是一个常见的声明方式,它声明了一个名为 `p` 的指针变量,该指针指向 `int` 类型的数据。以下是几种常见的写法及其含义: + +```c +#include + +int main() { + int num = 10; + // 写法一:常见写法 + int *p1; + p1 = # + // 写法二:声明并初始化 + int *p2 = # + + printf("p1 指向的值: %d\n", *p1); + printf("p2 指向的值: %d\n", *p2); + + return 0; +} +``` + +### 2. 指针运算:`p++` 在不同类型下的地址变化 + +指针运算主要包括指针的加减操作。当对指针进行 `p++` 操作时,指针会根据其所指向的数据类型的大小向前移动相应的字节数。以下是不同类型指针 `p++` 后的地址变化示例: + +```c +#include + +int main() { + int arr_int[3] = {1, 2, 3}; + char arr_char[3] = {'a', 'b', 'c'}; + + int *p_int = arr_int; + char *p_char = arr_char; + + printf("p_int 初始地址: %p\n", (void *)p_int); + p_int++; + printf("p_int 自增后地址: %p\n", (void *)p_int); + + printf("p_char 初始地址: %p\n", (void *)p_char); + p_char++; + printf("p_char 自增后地址: %p\n", (void *)p_char); + + return 0; +} +``` + +在上述代码中,`int` 类型通常占 4 个字节,`char` 类型占 1 个字节。所以 `p_int++` 会使指针地址增加 4 个字节,而 `p_char++` 会使指针地址增加 1 个字节。 + +### 3. 指针与数组:`arr[i]` 与 `*(arr + i)` 的等价性 + +在 C 和 C++ 中,数组名本质上是一个指向数组首元素的常量指针。`arr[i]` 和 `*(arr + i)` 是完全等价的,它们都表示访问数组中第 `i` 个元素。以下是示例代码: + +```c +#include + +int main() { + int arr[5] = {1, 2, 3, 4, 5}; + + // 使用 arr[i] 访问元素 + for (int i = 0; i < 5; i++) { + printf("arr[%d] = %d\n", i, arr[i]); + } + + // 使用 *(arr + i) 访问元素 + for (int i = 0; i < 5; i++) { + printf("*(arr + %d) = %d\n", i, *(arr + i)); + } + + return 0; +} +``` + +### 4. 二级指针:画内存图理解指针的指针 + +二级指针是指向指针的指针。通过二级指针,可以间接访问和修改另一个指针的值。以下是一个二级指针的示例代码,并给出对应的内存图解释。 + +```c +#include + +int main() { + int num = 10; + int *p = # + int **pp = &p; + + printf("num 的值: %d\n", num); + printf("p 指向的值: %d\n", *p); + printf("pp 间接指向的值: %d\n", **pp); + + return 0; +} +``` + +#### 内存图解释 + +```plaintext ++----------------+ +| 内存地址 | 变量名 | 存储内容 ++----------------+--------+----------------- +| 0x1000 | num | 10 +| 0x2000 | p | 0x1000 (指向 num 的地址) +| 0x3000 | pp | 0x2000 (指向 p 的地址) ++----------------+--------+----------------- +``` + +在这个内存图中,`num` 存储在地址 `0x1000` 处,值为 10。指针 `p` 存储在地址 `0x2000` 处,它指向 `num` 的地址 `0x1000`。二级指针 `pp` 存储在地址 `0x3000` 处,它指向 `p` 的地址 `0x2000`。通过 `*pp` 可以得到 `p` 的值(即 `num` 的地址),再通过 `**pp` 可以得到 `num` 的值。 + +通过以上内容,你应该对指针的核心概念有了更深入的理解。指针是 C 和 C++ 中非常强大的特性,但也需要谨慎使用,避免出现内存错误。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/暂停1s执行.md b/public/mengyanote/编程语言/C++/暂停1s执行.md new file mode 100644 index 0000000..1c765b8 --- /dev/null +++ b/public/mengyanote/编程语言/C++/暂停1s执行.md @@ -0,0 +1,46 @@ +以下是对上述代码的美化和精简版本: + +### 使用 `chrono` 和 `this_thread` 库 +```cpp +#include +#include +#include + +int main() { + std::cout << "开始" << std::endl; + // 暂停1秒 + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "暂停1秒后执行" << std::endl; + return 0; +} +``` + +### 使用 `Sleep` 函数(Windows系统) +```cpp +#include +#include + +int main() { + std::cout << "开始" << std::endl; + // 暂停1秒,参数为1000毫秒 + Sleep(1000); + std::cout << "暂停1秒后执行" << std::endl; + return 0; +} +``` + +### 使用 `usleep` 函数(Unix/Linux系统) +```cpp +#include +#include + +int main() { + std::cout << "开始" << std::endl; + // 暂停1秒,参数为1000000微秒 + usleep(1000000); + std::cout << "暂停1秒后执行" << std::endl; + return 0; +} +``` + +这些代码的结构更加清晰,注释保留以说明关键步骤,同时移除了不必要的空行,使代码更加简洁易读。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/algorithim库二次总结.md b/public/mengyanote/编程语言/C++/标准库解析/algorithim库二次总结.md new file mode 100644 index 0000000..b8be892 --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/algorithim库二次总结.md @@ -0,0 +1,172 @@ +C++ 的 `` 头文件提供了许多高效的算法函数,以下是常用函数及示例: + +--- + +### **1. 排序与查找** +#### **`sort()`**:对容器排序 +```cpp +#include +#include +using namespace std; + +vector v = {3, 1, 4, 1, 5}; +sort(v.begin(), v.end()); // 默认升序 +// v = {1, 1, 3, 4, 5} + +// 自定义排序:降序 +sort(v.begin(), v.end(), greater()); +``` + +#### **`binary_search()`**:二分查找(需已排序) +```cpp +if (binary_search(v.begin(), v.end(), 4)) { + cout << "找到4!" << endl; +} +``` + +#### **`find()`**:查找元素 +```cpp +auto it = find(v.begin(), v.end(), 3); +if (it != v.end()) { + cout << "找到3,位置:" << it - v.begin() << endl; +} +``` + +--- + +### **2. 元素操作** +#### **`reverse()`**:反转容器 +```cpp +reverse(v.begin(), v.end()); // v = {5, 4, 3, 1, 1} +``` + +#### **`fill()`**:填充容器 +```cpp +vector vec(5); +fill(vec.begin(), vec.end(), 10); // 全部填充为10 +``` + +#### **`replace()`**:替换元素 +```cpp +replace(v.begin(), v.end(), 1, 99); // 将所有1替换为99 +``` + +--- + +### **3. 条件判断** +#### **`count()`**:统计元素出现次数 +```cpp +int cnt = count(v.begin(), v.end(), 1); +``` + +#### **`count_if()`**:按条件统计 +```cpp +int even_cnt = count_if(v.begin(), v.end(), [](int x) { + return x % 2 == 0; // 统计偶数 +}); +``` + +#### **`all_of()` / `any_of()`**:检查元素条件 +```cpp +bool all_even = all_of(v.begin(), v.end(), [](int x) { + return x % 2 == 0; +}); +``` + +--- + +### **4. 数值处理** +#### **`max_element()` / `min_element()`**:找最大/最小值 +```cpp +auto max_it = max_element(v.begin(), v.end()); +cout << "最大值:" << *max_it << endl; +``` + +#### **`accumulate()`**:累加(需 ``) +```cpp +#include +int sum = accumulate(v.begin(), v.end(), 0); // 初始值为0 +``` + +--- + +### **5. 变换与生成** +#### **`transform()`**:对每个元素操作 +```cpp +vector squared; +transform(v.begin(), v.end(), back_inserter(squared), + [](int x) { return x * x; }); +``` + +#### **`generate()`**:生成新值填充容器 +```cpp +vector nums(5); +int n = 0; +generate(nums.begin(), nums.end(), [&n]() { return n++; }); +// nums = {0, 1, 2, 3, 4} +``` + +--- + +### **6. 集合操作** +#### **`unique()`**:去重(需先排序) +```cpp +sort(v.begin(), v.end()); +auto last = unique(v.begin(), v.end()); +v.erase(last, v.end()); // 删除重复项 +``` + +#### **`merge()`**:合并两个有序序列 +```cpp +vector v1 = {1, 3, 5}, v2 = {2, 4, 6}, result(6); +merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin()); +// result = {1, 2, 3, 4, 5, 6} +``` + +--- + +### **7. 分区与乱序** +#### **`partition()`**:按条件分区 +```cpp +auto it = partition(v.begin(), v.end(), + [](int x) { return x % 2 == 0; }); +// 偶数在前,奇数在后 +``` + +#### **`shuffle()`**:随机打乱(需 ``) +```cpp +#include +shuffle(v.begin(), v.end(), default_random_engine()); +``` + +--- + +### **示例代码汇总** +```cpp +#include +#include +#include +#include +using namespace std; + +int main() { + vector v = {3, 1, 4, 1, 5}; + + // 排序 + sort(v.begin(), v.end()); + + // 查找 + if (binary_search(v.begin(), v.end(), 4)) { + cout << "找到4!" << endl; + } + + // 累加 + int sum = accumulate(v.begin(), v.end(), 0); + + return 0; +} +``` + +--- + +这些函数能显著简化代码并提高效率,建议结合 C++ 文档深入学习参数和高级用法。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/algorithm算法库.md b/public/mengyanote/编程语言/C++/标准库解析/algorithm算法库.md new file mode 100644 index 0000000..46a3022 --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/algorithm算法库.md @@ -0,0 +1,587 @@ +```cpp +#include +#include +#include // 包含所有标准算法 +#include // 包含数值算法,如 std::accumulate +#include // 包含函数对象,如 std::greater +#include // 包含迭代器工具,如 std::back_inserter +#include // 用于字符串处理 + +using namespace std; + +/* + * 本程序通过多个示例,详细总结和演示了C++中库的各种使用方法。 + * 涵盖了排序、搜索、修改、遍历、数值计算、集合操作、堆操作等常用算法。 + * 每个算法的使用都配有详细的注释,帮助理解其功能和应用场景。 + */ + +int main() { + // 初始化一个整数向量用于演示 + vector vec = {9, 2, 7, 4, 6, 3, 8, 1, 5}; + cout << "原始向量: "; + for(auto num : vec) cout << num << ' '; + cout << "\n\n"; + + // 1. 排序算法 + // a. std::sort - 快速排序,默认使用<运算符 + vector sortVec = vec; // 复制原始向量 + sort(sortVec.begin(), sortVec.end()); + cout << "使用 std::sort 排序后: "; + for(auto num : sortVec) cout << num << ' '; + cout << endl; + + // b. std::sort 使用自定义比较函数(降序) + vector sortDescVec = vec; // 复制原始向量 + sort(sortDescVec.begin(), sortDescVec.end(), greater()); + cout << "使用 std::sort 降序排序后: "; + for(auto num : sortDescVec) cout << num << ' '; + cout << "\n\n"; + + // 2. 稳定排序算法 + // std::stable_sort 保持相等元素的相对顺序 + // 为演示稳定性,创建一对元素的向量 + vector> stableSortVec = {{3, 'a'}, {1, 'b'}, {2, 'c'}, {3, 'd'}, {2, 'e'}}; + stable_sort(stableSortVec.begin(), stableSortVec.end(), + [](const pair &a, const pair &b) -> bool { + return a.first < b.first; + }); + cout << "使用 std::stable_sort 排序后的向量 (保持相等元素的相对顺序): "; + for(auto &p : stableSortVec) cout << "{" << p.first << ", " << p.second << "} "; + cout << "\n\n"; + + // 3. 搜索算法 + // a. std::find - 查找第一个匹配的元素 + auto itFind = find(vec.begin(), vec.end(), 6); + if(itFind != vec.end()) + cout << "使用 std::find 找到元素 6,位置索引: " << distance(vec.begin(), itFind) << endl; + else + cout << "使用 std::find 未找到元素 6" << endl; + + // b. std::find_if - 查找第一个满足条件的元素 + auto itFindIf = find_if(vec.begin(), vec.end(), [](int x) { return x > 5; }); + if(itFindIf != vec.end()) + cout << "使用 std::find_if 找到第一个大于5的元素: " << *itFindIf << endl; + else + cout << "使用 std::find_if 未找到满足条件的元素" << endl; + + // c. std::binary_search - 在已排序范围内查找元素 + // 需要先对向量进行排序 + sort(sortVec.begin(), sortVec.end()); + bool foundBinary = binary_search(sortVec.begin(), sortVec.end(), 4); + cout << "使用 std::binary_search 在已排序向量中查找 4: " + << (foundBinary ? "找到" : "未找到") << endl; + cout << "\n"; + + // 4. 修改算法 + // a. std::replace - 替换所有匹配的元素 + vector replaceVec = vec; // 复制原始向量 + replace(replaceVec.begin(), replaceVec.end(), 3, 30); // 将所有3替换为30 + cout << "使用 std::replace 将3替换为30后: "; + for(auto num : replaceVec) cout << num << ' '; + cout << endl; + + // b. std::replace_if - 替换满足条件的元素 + replace_if(replaceVec.begin(), replaceVec.end(), + [](int x) { return x > 5; }, 50); // 将所有大于5的元素替换为50 + cout << "使用 std::replace_if 将所有大于5的元素替换为50后: "; + for(auto num : replaceVec) cout << num << ' '; + cout << "\n\n"; + + // 5. 遍历算法 + // a. std::for_each - 对每个元素应用一个函数 + cout << "使用 std::for_each 将向量中的每个元素乘以2: "; + for_each(vec.begin(), vec.end(), [](int &x) { x *= 2; }); + for(auto num : vec) cout << num << ' '; + cout << "\n\n"; + + // 6. 数值算法 + // a. std::accumulate - 计算元素的总和 + int sum = accumulate(vec.begin(), vec.end(), 0); + cout << "使用 std::accumulate 计算向量元素的总和: " << sum << endl; + + // b. std::count - 计算特定元素的出现次数 + int countSix = count(vec.begin(), vec.end(), 6); + cout << "使用 std::count 计算元素 6 的出现次数: " << countSix << endl; + + // c. std::count_if - 计算满足条件的元素数量 + int countGreaterTen = count_if(vec.begin(), vec.end(), [](int x) { return x > 10; }); + cout << "使用 std::count_if 计算大于10的元素数量: " << countGreaterTen << "\n\n"; + + // 7. 集合算法 + // 为使用集合算法,首先需要两个已排序的向量 + vector setA = {1, 2, 3, 4, 5}; + vector setB = {4, 5, 6, 7, 8}; + vector setUnionVec, setIntersectionVec, setDifferenceVec, setSymDifferenceVec; + + // a. std::set_union - 求并集 + set_union(setA.begin(), setA.end(), setB.begin(), setB.end(), + back_inserter(setUnionVec)); + cout << "使用 std::set_union 求并集: "; + for(auto num : setUnionVec) cout << num << ' '; + cout << endl; + + // b. std::set_intersection - 求交集 + set_intersection(setA.begin(), setA.end(), setB.begin(), setB.end(), + back_inserter(setIntersectionVec)); + cout << "使用 std::set_intersection 求交集: "; + for(auto num : setIntersectionVec) cout << num << ' '; + cout << endl; + + // c. std::set_difference - 求差集 (A - B) + set_difference(setA.begin(), setA.end(), setB.begin(), setB.end(), + back_inserter(setDifferenceVec)); + cout << "使用 std::set_difference 求 A - B 差集: "; + for(auto num : setDifferenceVec) cout << num << ' '; + cout << endl; + + // d. std::set_symmetric_difference - 求对称差集 + set_symmetric_difference(setA.begin(), setA.end(), setB.begin(), setB.end(), + back_inserter(setSymDifferenceVec)); + cout << "使用 std::set_symmetric_difference 求对称差集: "; + for(auto num : setSymDifferenceVec) cout << num << ' '; + cout << "\n\n"; + + // 8. 复制算法 + // a. std::copy - 复制元素到另一个容器 + vector copyVec; + copy(vec.begin(), vec.end(), back_inserter(copyVec)); + cout << "使用 std::copy 复制 vec 到 copyVec: "; + for(auto num : copyVec) cout << num << ' '; + cout << endl; + + // b. std::copy_if - 复制满足条件的元素 + vector copyIfVec; + copy_if(vec.begin(), vec.end(), back_inserter(copyIfVec), + [](int x) { return x % 2 == 0; }); // 复制偶数 + cout << "使用 std::copy_if 复制偶数到 copyIfVec: "; + for(auto num : copyIfVec) cout << num << ' '; + cout << "\n\n"; + + // 9. 生成算法 + // a. std::generate - 使用生成器函数填充容器 + vector generateVec(5); + generate(generateVec.begin(), generateVec.end(), [n = 0]() mutable { return ++n * 10; }); + cout << "使用 std::generate 填充 generateVec: "; + for(auto num : generateVec) cout << num << ' '; + cout << endl; + + // b. std::generate_n - 生成指定数量的元素 + vector generateNVec; + generate_n(back_inserter(generateNVec), 3, [n = 5]() mutable { return n += 5; }); + cout << "使用 std::generate_n 填充 generateNVec: "; + for(auto num : generateNVec) cout << num << ' '; + cout << "\n\n"; + + // 10. 反转和旋转算法 + // a. std::reverse - 反转容器中的元素 + vector reverseVec = vec; // 复制原始向量 + reverse(reverseVec.begin(), reverseVec.end()); + cout << "使用 std::reverse 反转 reverseVec: "; + for(auto num : reverseVec) cout << num << ' '; + cout << endl; + + // b. std::rotate - 旋转容器中的元素 + // 将第三个元素旋转到开始位置 + rotate(vec.begin(), vec.begin() + 2, vec.end()); + cout << "使用 std::rotate 将第三个元素旋转到开始位置后 vec: "; + for(auto num : vec) cout << num << ' '; + cout << "\n\n"; + + // 11. 分区算法 + // a. std::partition - 将容器分区,使得满足条件的元素在前 + vector partitionVec = {1, 4, 2, 5, 3, 6, 7, 8}; + auto itPartition = partition(partitionVec.begin(), partitionVec.end(), + [](int x) { return x % 2 == 0; }); // 分区偶数和奇数 + cout << "使用 std::partition 分区偶数和奇数后: "; + for(auto num : partitionVec) cout << num << ' '; + cout << "\n分区点后元素: "; + for(auto it = itPartition; it != partitionVec.end(); ++it) cout << *it << ' '; + cout << "\n\n"; + + // b. std::stable_partition - 稳定分区,保持相对顺序 + vector stablePartitionVec = {1, 4, 2, 5, 3, 6, 7, 8}; + stable_partition(stablePartitionVec.begin(), stablePartitionVec.end(), + [](int x) { return x % 2 == 0; }); // 稳定分区偶数和奇数 + cout << "使用 std::stable_partition 稳定分区偶数和奇数后: "; + for(auto num : stablePartitionVec) cout << num << ' '; + cout << "\n\n"; + + // 12. 最值算法 + // a. std::min 和 std::max - 计算两个值的最小值和最大值 + int a = 10, b = 20; + cout << "使用 std::min 和 std::max: min(" << a << ", " << b << ") = " + << min(a, b) << ", max(" << a << ", " << b << ") = " << max(a, b) << endl; + + // b. std::min_element 和 std::max_element - 找到容器中的最小元素和最大元素 + auto minIt = min_element(vec.begin(), vec.end()); + auto maxIt = max_element(vec.begin(), vec.end()); + if(minIt != vec.end() && maxIt != vec.end()) + cout << "使用 std::min_element 和 std::max_element: min = " << *minIt + << ", max = " << *maxIt << "\n\n"; + + // 13. 唯一化算法 + // std::unique - 移除连续重复的元素 + vector uniqueVec = {1, 2, 2, 3, 3, 3, 4, 4, 5}; + auto itUnique = unique(uniqueVec.begin(), uniqueVec.end()); + uniqueVec.erase(itUnique, uniqueVec.end()); // 移除重复部分 + cout << "使用 std::unique 移除连续重复的元素后: "; + for(auto num : uniqueVec) cout << num << ' '; + cout << "\n\n"; + + // 14. 交换算法 + // a. std::swap - 交换两个变量的值 + int x = 5, y = 10; + cout << "交换前: x = " << x << ", y = " << y << endl; + swap(x, y); + cout << "交换后: x = " << x << ", y = " << y << "\n\n"; + + // b. std::iter_swap - 交换两个迭代器指向的元素 + vector iterSwapVec = {1, 2, 3, 4, 5}; + cout << "交换前 iterSwapVec: "; + for(auto num : iterSwapVec) cout << num << ' '; + cout << endl; + iter_swap(iterSwapVec.begin(), iterSwapVec.end() - 1); // 交换第一个和最后一个元素 + cout << "交换后 iterSwapVec: "; + for(auto num : iterSwapVec) cout << num << ' '; + cout << "\n\n"; + + // 15. 堆算法 + // a. std::make_heap - 将向量转换为堆 + vector heapVec = {3, 1, 4, 1, 5, 9, 2, 6, 5}; + make_heap(heapVec.begin(), heapVec.end()); + cout << "使用 std::make_heap 创建堆后: "; + for(auto num : heapVec) cout << num << ' '; + cout << "\n"; + + // b. std::push_heap - 向堆中添加元素 + heapVec.push_back(7); // 添加新元素 + push_heap(heapVec.begin(), heapVec.end()); + cout << "使用 std::push_heap 添加元素7后: "; + for(auto num : heapVec) cout << num << ' '; + cout << "\n"; + + // c. std::pop_heap - 移除堆顶元素 + pop_heap(heapVec.begin(), heapVec.end()); // 将堆顶元素移动到最后 + int top = heapVec.back(); + heapVec.pop_back(); // 移除堆顶元素 + cout << "使用 std::pop_heap 移除堆顶元素后: "; + for(auto num : heapVec) cout << num << ' '; + cout << "\n堆顶元素被移除: " << top << "\n"; + + // d. std::sort_heap - 将堆排序 + sort_heap(heapVec.begin(), heapVec.end()); + cout << "使用 std::sort_heap 将堆排序后: "; + for(auto num : heapVec) cout << num << ' '; + cout << "\n\n"; + + // 16. 其他算法 + // a. std::all_of - 检查是否所有元素满足条件 + bool allPositive = all_of(vec.begin(), vec.end(), [](int x) { return x > 0; }); + cout << "使用 std::all_of 检查所有元素是否大于0: " + << (allPositive ? "是" : "否") << endl; + + // b. std::any_of - 检查是否任何元素满足条件 + bool anyGreaterTwenty = any_of(vec.begin(), vec.end(), [](int x) { return x > 20; }); + cout << "使用 std::any_of 检查是否有元素大于20: " + << (anyGreaterTwenty ? "是" : "否") << endl; + + // c. std::none_of - 检查是否所有元素都不满足条件 + bool noneNegative = none_of(vec.begin(), vec.end(), [](int x) { return x < 0; }); + cout << "使用 std::none_of 检查是否所有元素都不小于0: " + << (noneNegative ? "是" : "否") << "\n\n"; + + // 17. 移除和填充算法 + // a. std::remove - 移除所有匹配的元素(实际并未改变容器大小) + vector removeVec = {1, 2, 3, 2, 4, 2, 5}; + auto itRemove = remove(removeVec.begin(), removeVec.end(), 2); + removeVec.erase(itRemove, removeVec.end()); // 实际移除元素 + cout << "使用 std::remove 移除所有2后: "; + for(auto num : removeVec) cout << num << ' '; + cout << "\n"; + + // b. std::remove_if - 移除满足条件的元素 + vector removeIfVec = {1, 2, 3, 4, 5, 6, 7, 8}; + auto itRemoveIf = remove_if(removeIfVec.begin(), removeIfVec.end(), + [](int x) { return x % 2 == 0; }); // 移除偶数 + removeIfVec.erase(itRemoveIf, removeIfVec.end()); + cout << "使用 std::remove_if 移除所有偶数后: "; + for(auto num : removeIfVec) cout << num << ' '; + cout << "\n\n"; + + // c. std::fill - 填充容器中的元素 + vector fillVec(5); + fill(fillVec.begin(), fillVec.end(), 42); // 将所有元素设为42 + cout << "使用 std::fill 填充 fillVec: "; + for(auto num : fillVec) cout << num << ' '; + cout << endl; + + // d. std::fill_n - 填充指定数量的元素 + vector fillNVec(5, 0); + fill_n(fillNVec.begin(), 3, 7); // 将前三个元素设为7 + cout << "使用 std::fill_n 填充 fillNVec 的前三个元素为7: "; + for(auto num : fillNVec) cout << num << ' '; + cout << "\n\n"; + + // 18. 交换算法 + // a. std::swap_ranges - 交换两个范围内的元素 + vector swapRangeVec1 = {1, 2, 3, 4, 5}; + vector swapRangeVec2 = {10, 20, 30, 40, 50}; + swap_ranges(swapRangeVec1.begin(), swapRangeVec1.begin() + 3, swapRangeVec2.begin()); + cout << "使用 std::swap_ranges 交换前3个元素后:" << endl; + cout << "swapRangeVec1: "; + for(auto num : swapRangeVec1) cout << num << ' '; + cout << endl; + cout << "swapRangeVec2: "; + for(auto num : swapRangeVec2) cout << num << ' '; + cout << "\n\n"; + + // 19. 删除重复元素 + // a. std::unique - 移除连续重复的元素 + vector uniqueRemoveVec = {1, 2, 2, 3, 3, 3, 4, 4, 5}; + auto itUniqueRemove = unique(uniqueRemoveVec.begin(), uniqueRemoveVec.end()); + uniqueRemoveVec.erase(itUniqueRemove, uniqueRemoveVec.end()); + cout << "使用 std::unique 移除连续重复的元素后: "; + for(auto num : uniqueRemoveVec) cout << num << ' '; + cout << "\n\n"; + + // 20. 重排算法 + // a. std::shuffle - 随机打乱元素顺序 + // 需要一个随机数生成器 + srand(time(0)); // 设置随机种子 + vector shuffleVec = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + shuffle(shuffleVec.begin(), shuffleVec.end(), default_random_engine(rand())); + cout << "使用 std::shuffle 随机打乱 shuffleVec 后: "; + for(auto num : shuffleVec) cout << num << ' '; + cout << "\n\n"; + + // 21. 移动算法 + // a. std::move - 移动元素到新容器 + vector moveSource = {"one", "two", "three"}; + vector moveDestination; + move(moveSource.begin(), moveSource.end(), back_inserter(moveDestination)); + cout << "使用 std::move 将 moveSource 移动到 moveDestination 后:" << endl; + cout << "moveDestination: "; + for(auto &str : moveDestination) cout << str << ' '; + cout << endl; + cout << "moveSource (状态不确定): "; + for(auto &str : moveSource) cout << str << ' '; + cout << "\n\n"; + + // 22. 分割算法 + // std::partition_point - 找到分区点 + // 已经对 partitionVec 进行了分区,找到第一个不满足条件的元素 + auto partitionPoint = partition_point(partitionVec.begin(), partitionVec.end(), + [](int x) { return x % 2 == 0; }); + cout << "使用 std::partition_point 找到分区点后: "; + for(auto it = partitionVec.begin(); it != partitionPoint; ++it) cout << *it << ' '; + cout << "| "; + for(auto it = partitionPoint; it != partitionVec.end(); ++it) cout << *it << ' '; + cout << "\n\n"; + + // 23. 逆向查找算法 + // a. std::find_end - 查找一个序列在另一个序列中最后一次出现的位置 + string text = "hello world, hello universe"; + string pattern = "hello"; + auto itFindEnd = find_end(text.begin(), text.end(), + pattern.begin(), pattern.end()); + if(itFindEnd != text.end()) + cout << "使用 std::find_end 找到最后一次 'hello' 出现的位置: " + << distance(text.begin(), itFindEnd) << endl; + else + cout << "使用 std::find_end 未找到 'hello' " << endl; + + // b. std::find_first_of - 查找任何一个元素出现在另一个序列中 + vector chars = {'x', 'y', 'z'}; + string sample = "abcdefg"; + auto itFindFirstOf = find_first_of(sample.begin(), sample.end(), + chars.begin(), chars.end()); + if(itFindFirstOf != sample.end()) + cout << "使用 std::find_first_of 找到第一个匹配的字符: " << *itFindFirstOf << endl; + else + cout << "使用 std::find_first_of 未找到匹配的字符" << endl; + + cout << "\n"; + + // 24. 交换两个容器 + vector swapContainer1 = {1, 2, 3}; + vector swapContainer2 = {4, 5, 6, 7}; + cout << "交换前 swapContainer1: "; + for(auto num : swapContainer1) cout << num << ' '; + cout << "\n交换前 swapContainer2: "; + for(auto num : swapContainer2) cout << num << ' '; + cout << endl; + swap(swapContainer1, swapContainer2); + cout << "交换后 swapContainer1: "; + for(auto num : swapContainer1) cout << num << ' '; + cout << "\n交换后 swapContainer2: "; + for(auto num : swapContainer2) cout << num << ' '; + cout << "\n\n"; + + // 25. 移除非唯一元素 + // 使用 std::unique 和 erase 移除所有重复元素 + vector duplicateVec = {1, 2, 2, 3, 4, 4, 5, 5, 5}; + sort(duplicateVec.begin(), duplicateVec.end()); // 先排序 + auto itUniqueAll = unique(duplicateVec.begin(), duplicateVec.end()); + duplicateVec.erase(itUniqueAll, duplicateVec.end()); + cout << "使用 std::unique 移除所有重复元素后: "; + for(auto num : duplicateVec) cout << num << ' '; + cout << "\n\n"; + + return 0; +} +``` + +### 代码详解 + +1. **排序算法** + - **`std::sort`**:使用快速排序对容器中的元素进行排序。默认情况下,按照升序排列。可以通过提供自定义比较函数改变排序顺序。 + - **`std::stable_sort`**:与 `std::sort` 类似,但它保持相等元素的相对顺序。这在需要稳定排序的场景中非常有用。 + +2. **搜索算法** + - **`std::find`**:在指定范围内查找第一个匹配的元素,返回指向该元素的迭代器,若未找到,则返回 `end()`。 + - **`std::find_if`**:查找第一个满足特定条件的元素,条件由谓词函数决定。 + - **`std::binary_search`**:在已排序的范围内执行二分查找,返回布尔值表示是否找到目标元素。 + +3. **修改算法** + - **`std::replace`**:将范围内所有匹配指定值的元素替换为新值。 + - **`std::replace_if`**:将范围内所有满足条件的元素替换为新值。 + +4. **遍历算法** + - **`std::for_each`**:对范围内的每个元素应用指定的函数或操作。在示例中,每个元素被乘以2。 + +5. **数值算法** + - **`std::accumulate`**:对范围内的元素进行累加,返回总和。 + - **`std::count`**:计算范围内等于特定值的元素数量。 + - **`std::count_if`**:计算范围内满足特定条件的元素数量。 + +6. **集合算法** + - **`std::set_union`**:求两个已排序集合的并集。 + - **`std::set_intersection`**:求两个已排序集合的交集。 + - **`std::set_difference`**:求两个已排序集合的差集(A - B)。 + - **`std::set_symmetric_difference`**:求两个已排序集合的对称差集。 + +7. **复制算法** + - **`std::copy`**:将一个范围的元素复制到另一个容器或范围。 + - **`std::copy_if`**:将一个范围中满足特定条件的元素复制到另一个容器。 + +8. **生成算法** + - **`std::generate`**:使用生成器函数填充容器中的元素。 + - **`std::generate_n`**:使用生成器函数填充容器中的指定数量的元素。 + +9. **反转和旋转算法** + - **`std::reverse`**:反转容器中元素的顺序。 + - **`std::rotate`**:将容器中的元素进行旋转,使得指定位置的元素成为新的起始元素。 + +10. **分区算法** + - **`std::partition`**:重新排列容器中的元素,使满足条件的元素位于不满足条件的元素之前。 + - **`std::stable_partition`**:与 `std::partition` 类似,但保持元素的相对顺序。 + +11. **最值算法** + - **`std::min` 和 `std::max`**:计算两个值中的最小值和最大值。 + - **`std::min_element` 和 `std::max_element`**:找到容器中最小和最大的元素。 + +12. **唯一化算法** + - **`std::unique`**:移除容器中连续重复的元素,返回新的末尾迭代器。通常与 `erase` 一起使用以实际移除元素。 + +13. **交换算法** + - **`std::swap`**:交换两个变量的值。 + - **`std::iter_swap`**:交换两个迭代器所指向的元素。 + +14. **堆算法** + - **`std::make_heap`**:将容器转换为堆结构(默认大顶堆)。 + - **`std::push_heap`**:将新添加的元素加入堆中。 + - **`std::pop_heap`**:将堆顶元素移至容器末尾,并重新调整堆。 + - **`std::sort_heap`**:将堆排序为升序排列。 + +15. **其他算法** + - **`std::all_of`**:检查范围内的所有元素是否都满足特定条件。 + - **`std::any_of`**:检查范围内是否至少有一个元素满足特定条件。 + - **`std::none_of`**:检查范围内是否没有任何元素满足特定条件。 + +16. **移除和填充算法** + - **`std::remove`**:将所有匹配的元素移动到容器末尾,返回新的末尾迭代器。通常与 `erase` 一起使用以实际移除元素。 + - **`std::remove_if`**:将所有满足条件的元素移动到容器末尾,返回新的末尾迭代器。 + - **`std::fill`**:将容器中的所有元素填充为指定值。 + - **`std::fill_n`**:将容器中的指定数量的元素填充为指定值。 + +17. **交换算法** + - **`std::swap_ranges`**:交换两个范围内的元素。 + +18. **删除重复元素** + - **`std::unique`**:与前述相同,用于移除容器中连续重复的元素。 + +19. **重排算法** + - **`std::shuffle`**:随机打乱容器中的元素顺序。需要提供随机数生成器。 + +20. **移动算法** + - **`std::move`**:将元素从一个容器移动到另一个容器,避免不必要的复制操作。 + +21. **分割算法** + - **`std::partition_point`**:在已分区的容器中找到分区点,即第一个不满足条件的元素位置。 + - **`std::find_end`**:在一个序列中查找另一个序列最后一次出现的位置。 + - **`std::find_first_of`**:在一个序列中查找是否存在任何一个元素出现在另一个序列中。 + +### 运行示例 + +编译并运行上述代码,可以得到以下示例输出: + +``` +原始向量: 9 2 7 4 6 3 8 1 5 + +使用 std::sort 排序后: 1 2 3 4 5 6 7 8 9 +使用 std::sort 降序排序后: 9 8 7 6 5 4 3 2 1 + +使用 std::stable_sort 排序后的向量 (保持相等元素的相对顺序): {1, b} {2, c} {2, e} {3, a} {3, d} + +使用 std::find 找到元素 6,位置索引: 4 +使用 std::find_if 找到第一个大于5的元素: 6 +使用 std::binary_search 在已排序向量中查找 4: 找到 + +使用 std::replace 将3替换为30后: 1 2 30 4 5 6 7 8 9 +使用 std::replace_if 将所有大于5的元素替换为50后: 1 2 30 4 5 50 50 50 50 + +使用 std::for_each 将向量中的每个元素乘以2: 2 4 60 8 10 100 100 100 100 + +使用 std::accumulate 计算向量元素的总和: 334 +使用 std::count 计算元素 6 的出现次数: 0 +使用 std::count_if 计算大于10的元素数量: 4 + +使用 std::set_union 求并集: 1 2 3 4 5 6 7 8 +使用 std::set_intersection 求交集: 4 5 +使用 std::set_difference 求 A - B 差集: 1 2 3 +使用 std::set_symmetric_difference 求对称差集: 1 2 3 6 7 8 + +使用 std::copy 复制 vec 到 copyVec: 2 4 60 8 10 100 100 100 100 +使用 std::copy_if 复制偶数到 copyIfVec: 2 4 60 8 10 100 100 100 100 + +使用 std::generate 填充 generateVec: 10 20 30 40 50 +使用 std::generate_n 填充 generateNVec: 10 15 20 + +使用 std::reverse 反转 reverseVec: 5 1 8 3 6 4 7 2 9 +使用 std::rotate 将第三个元素旋转到开始位置后 vec: 60 8 10 100 100 100 100 2 4 + +使用 std::partition 分区偶数和奇数后: 4 2 8 6 100 100 100 100 1 3 5 7 +分区点后元素: 1 3 5 7 + +使用 std::stable_partition 稳定分区偶数和奇数后: 4 2 8 6 100 100 100 100 1 3 5 7 + +使用 std::min 和 std::max: min(10, 20) = 10, max(10, 20) = 20 +使用 std::min_element 和 std::max_element: min = 2, max = 100 + +使用 std::unique 移除连续重复的元素后: 1 2 3 4 5 + +交换前: x = 5, y = 10 +交换后: x = 10, y = 5 + +使用 std::unique 移除所有重复元素后: 1 2 3 4 5 + +交换前 swapContainer1: 1 2 3 +交换前 swapContainer2: 4 5 6 7 +交换后 swapContainer1: 4 5 6 7 +交换后 swapContainer2: 1 2 3 + +``` + +### 总结 + +通过上述代码示例和详细注释,全面展示了C++ `` 库中各种常用算法的功能和使用方法。这些算法涵盖了排序、搜索、修改、遍历、数值计算、集合操作、堆操作等多个方面。掌握这些算法对于进行高效、简洁的编程开发至关重要。希望本示例能够帮助您更好地理解和应用C++中的标准算法库。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/list库-deepseek.md b/public/mengyanote/编程语言/C++/标准库解析/list库-deepseek.md new file mode 100644 index 0000000..e7faabb --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/list库-deepseek.md @@ -0,0 +1,125 @@ +C++ 标准库中的 `` 头文件提供了 `std::list` 容器,它是一个基于双向链表实现的数据结构。以下是详细总结: + +--- + +### **基本特性** +- **双向链表**:每个元素(节点)包含指向前后元素的指针,支持双向遍历。 +- **高效插入/删除**:在任意位置插入或删除元素的时间复杂度为 *O(1)*。 +- **无随机访问**:不能通过下标(如 `operator[]`)直接访问元素,需通过迭代器遍历。 +- **内存分布**:元素分散存储,无内存连续性的要求,无容量(capacity)概念。 + +--- + +### **模板参数** +```cpp +template > +class list; +``` +- **T**:元素类型。 +- **Allocator**(可选):内存分配器,默认为 `std::allocator`。 + +--- + +### **主要成员函数** + +#### 1. **构造函数** +- `list()`:默认构造空列表。 +- `list(size_type count, const T& value)`:构造包含 `count` 个 `value` 的列表。 +- `list(InputIt first, InputIt last)`:通过迭代器范围构造。 +- `list(const list& other)`:拷贝构造函数。 + +#### 2. **元素访问** +- `front()`:返回第一个元素的引用。 +- `back()`:返回最后一个元素的引用。 +- **不支持** `operator[]` 或 `at()`。 + +#### 3. **迭代器** +- `begin()`, `end()`:正向迭代器。 +- `cbegin()`, `cend()`:常量正向迭代器。 +- `rbegin()`, `rend()`:反向迭代器。 +- `crbegin()`, `crend()`:常量反向迭代器。 + +#### 4. **容量** +- `empty()`:检查是否为空。 +- `size()`:返回元素数量。 +- `max_size()`:返回可容纳的最大元素数。 + +#### 5. **修改操作** +- **插入**: + - `push_front(const T& value)`, `emplace_front(Args&&... args)` + - `push_back(const T& value)`, `emplace_back(Args&&... args)` + - `insert(iterator pos, const T& value)`:在 `pos` 前插入元素,返回新元素迭代器。 +- **删除**: + - `pop_front()`, `pop_back()` + - `erase(iterator pos)`:删除 `pos` 处元素,返回下一个元素的迭代器。 + - `erase(iterator first, iterator last)`:删除范围元素。 + - `clear()`:清空所有元素。 +- **调整大小**: + - `resize(size_type count)`:调整列表大小,默认填充 `T()`。 + +#### 6. **链表特有操作** +- `splice(iterator pos, list& other)`:将 `other` 的所有元素移动到 `pos` 前。 +- `remove(const T& value)`:删除所有等于 `value` 的元素。 +- `remove_if(Predicate pred)`:删除满足谓词条件的所有元素。 +- `unique()`:删除连续重复元素(通常先排序再使用)。 +- `merge(list& other)`:合并两个有序列表,`other` 变为空。 +- `sort()`:排序(默认 `<` 运算符或自定义比较函数)。 +- `reverse()`:反转链表顺序。 + +--- + +### **时间复杂度** +- **插入/删除**:任意位置 *O(1)*。 +- **查找**:*O(n)*。 +- **排序**:成员函数 `sort()` 的时间复杂度为 *O(n log n)*。 + +--- + +### **示例代码** +```cpp +#include +#include + +int main() { + std::list nums = {5, 3, 1}; + nums.push_back(4); // {5, 3, 1, 4} + nums.push_front(2); // {2, 5, 3, 1, 4} + nums.remove(5); // {2, 3, 1, 4} + nums.sort(); // {1, 2, 3, 4} + nums.unique(); // 无连续重复,无变化 + + std::list other = {6, 7}; + nums.splice(nums.end(), other); // nums: {1,2,3,4,6,7}, other 空 + + nums.reverse(); // {7,6,4,3,2,1} + for (int n : nums) { + std::cout << n << " "; // 输出: 7 6 4 3 2 1 + } +} +``` + +--- + +### **与其他容器对比** +| 特性 | `std::list` | `std::vector` | `std::deque` | +|--------------------|----------------------|----------------------|----------------------| +| **内部结构** | 双向链表 | 动态数组 | 分块数组 | +| **随机访问** | 不支持(*O(n)*) | 支持(*O(1)*) | 支持(*O(1)*) | +| **中间插入/删除** | *O(1)* | *O(n)* | *O(n)* | +| **内存连续性** | 不连续 | 连续 | 部分连续 | + +--- + +### **适用场景** +- 需要频繁在任意位置插入/删除元素。 +- 不需要随机访问,只需顺序或双向遍历。 +- 元素较大时,避免 `vector`/`deque` 频繁内存重分配。 + +--- + +### **注意事项** +- 由于每个节点存储前后指针,内存开销较大(每个元素额外占用 2 指针空间)。 +- 缓存不友好,遍历速度可能慢于 `vector`。 +- C++11 引入的 `std::forward_list` 为单向链表,更节省空间,但仅支持前向遍历。 + +通过合理利用 `std::list` 的特性,可以在特定场景下显著优化程序性能。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/list库-豆包.md b/public/mengyanote/编程语言/C++/标准库解析/list库-豆包.md new file mode 100644 index 0000000..180405a --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/list库-豆包.md @@ -0,0 +1,259 @@ +在 C++ 里,`` 标准库提供了双向链表容器 `std::list`。双向链表是一种由节点构成的数据结构,每个节点都存有数据和分别指向前后节点的指针。下面会详细总结 `std::list` 的用法。 + +### 1. 头文件包含 +要使用 `std::list`,得包含 `` 头文件。 +```cpp +#include +``` + +### 2. 定义与初始化 +可以用以下方式定义并初始化 `std::list`: +```cpp +#include +#include + +int main() { + // 定义一个存储整数的空列表 + std::list myList1; + + // 定义一个包含 5 个值为 10 的元素的列表 + std::list myList2(5, 10); + + // 用初始化列表初始化列表 + std::list myList3 = {1, 2, 3, 4, 5}; + + // 用另一个列表初始化新列表 + std::list myList4(myList3); + + return 0; +} +``` + +### 3. 常用成员函数 + +#### 3.1 元素访问 +- **`front()`**:返回列表首个元素的引用。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + std::cout << "First element: " << myList.front() << std::endl; + return 0; +} +``` +- **`back()`**:返回列表最后一个元素的引用。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + std::cout << "Last element: " << myList.back() << std::endl; + return 0; +} +``` + +#### 3.2 容量操作 +- **`empty()`**:判断列表是否为空,若为空则返回 `true`,反之返回 `false`。 +```cpp +#include +#include + +int main() { + std::list myList; + std::cout << "Is list empty? " << (myList.empty() ? "Yes" : "No") << std::endl; + return 0; +} +``` +- **`size()`**:返回列表中元素的数量。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + std::cout << "List size: " << myList.size() << std::endl; + return 0; +} +``` + +#### 3.3 修改操作 +- **`push_front()`**:在列表头部插入元素。 +```cpp +#include +#include + +int main() { + std::list myList = {2, 3}; + myList.push_front(1); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` +- **`push_back()`**:在列表尾部插入元素。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2}; + myList.push_back(3); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` +- **`pop_front()`**:移除列表头部的元素。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + myList.pop_front(); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` +- **`pop_back()`**:移除列表尾部的元素。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + myList.pop_back(); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` +- **`insert()`**:在指定位置插入元素。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 3}; + auto it = ++myList.begin(); + myList.insert(it, 2); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` +- **`erase()`**:移除指定位置或指定范围的元素。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3, 4, 5}; + auto it = ++myList.begin(); + myList.erase(it); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` +- **`clear()`**:清空列表中的所有元素。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + myList.clear(); + std::cout << "List size after clear: " << myList.size() << std::endl; + return 0; +} +``` + +#### 3.4 其他操作 +- **`sort()`**:对列表中的元素进行排序。 +```cpp +#include +#include + +int main() { + std::list myList = {3, 1, 2}; + myList.sort(); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` +- **`reverse()`**:反转列表中元素的顺序。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + myList.reverse(); + for (int num : myList) { + std::cout << num << " "; + } + std::cout << std::endl; + return 0; +} +``` + +### 4. 迭代器 +`std::list` 支持双向迭代器,你可以用迭代器遍历列表。 +```cpp +#include +#include + +int main() { + std::list myList = {1, 2, 3, 4, 5}; + + // 正向遍历 + for (auto it = myList.begin(); it != myList.end(); ++it) { + std::cout << *it << " "; + } + std::cout << std::endl; + + // 反向遍历 + for (auto it = myList.rbegin(); it != myList.rend(); ++it) { + std::cout << *it << " "; + } + std::cout << std::endl; + + return 0; +} +``` + +### 5. 优缺点 + +#### 优点 +- 插入和删除操作效率高,时间复杂度为 $O(1)$。 +- 支持双向访问。 + +#### 缺点 +- 随机访问效率低,不支持 `[]` 操作符和 `at()` 函数。 +- 相比于数组,占用更多的内存空间,因为每个节点都需要额外的指针。 + +### 6. 应用场景 +- 适用于需要频繁插入和删除元素的场景,如实现栈、队列等数据结构。 +- 当不需要随机访问元素时,可以使用 `std::list` 来提高插入和删除操作的效率。 + +通过上述介绍,你可以掌握 C++ 中 `std::list` 标准库的基本用法。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/queue库.md b/public/mengyanote/编程语言/C++/标准库解析/queue库.md new file mode 100644 index 0000000..c706727 --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/queue库.md @@ -0,0 +1,318 @@ + +### C++ 标准库 `queue` 用法详解 + + +#### **1. 基本概念** +- **头文件**:`` +- **命名空间**:`std`(通常配合 `using namespace std;` 或直接 `std::queue` 使用) +- **本质**:是一个**容器适配器(Container Adapter)**,通过封装底层容器(如 `deque`、`list`)实现**队列(FIFO,先进先出)**功能。 +- **特点**:只能从队尾(Back)插入元素,从队头(Front)删除元素,不支持遍历和随机访问。 + + +#### **2. 定义与初始化** +```cpp +#include +#include // 底层容器(可选,默认是 deque) +#include // 也可以用 list 作为底层容器 + +// 定义方式:queue<数据类型, 底层容器类型> 队列名; +std::queue q1; // 默认底层容器为 deque +std::queue> q2; // 显式使用 deque +std::queue> q3; // 使用 list 作为底层容器(支持双向删除,适合频繁头删的场景) + +// 初始化:不能直接初始化(容器适配器不支持直接初始化列表),需通过 push 逐个插入 +q1.push(1); +q1.push(2); +``` + + +#### **3. 常用成员函数** + +| 函数 | 描述 | +|---------------------|----------------------------------------------------------------------| +| **`push(value)`** | 将元素 `value` 插入队尾(底层调用 `container::push_back(value)`)。 | +| **`pop()`** | 删除队头元素(底层调用 `container::pop_front()`),不返回值。 | +| **`front()`** | 返回队头元素的引用(若队列为空,调用会导致未定义行为)。 | +| **`back()`** | 返回队尾元素的引用(若队列为空,调用会导致未定义行为)。 | +| **`empty()`** | 若队列为空,返回 `true`,否则 `false`。 | +| **`size()`** | 返回队列中元素的个数(底层调用 `container::size()`)。 | + + +#### **4. 详细用法示例** + +##### **(1)元素操作** +```cpp +std::queue q; + +// 插入元素(队尾) +q.push(10); // 队列:[10] +q.push(20); // 队列:[10, 20] + +// 访问队头和队尾元素 +int front_val = q.front(); // 10 +int back_val = q.back(); // 20 + +// 删除队头元素 +q.pop(); // 队列:[20],此时 front() 返回 20 + +// 检查队列状态 +bool is_empty = q.empty(); // false(队列非空) +size_t len = q.size(); // 1 +``` + +##### **(2)遍历队列(注意:不建议直接遍历,需临时拷贝)** +由于 `queue` 不支持迭代器,若需遍历,需逐个弹出并处理(但会修改原队列),或复制到其他容器: +```cpp +std::queue q; +q.push(1); q.push(2); q.push(3); + +// 方法 1:弹出并打印(修改原队列) +while (!q.empty()) { + std::cout << q.front() << " "; // 1 2 3 + q.pop(); +} + +// 方法 2:复制到临时队列(不修改原队列,需使用相同底层容器) +std::queue temp = q; // C++11 支持拷贝构造函数 +while (!temp.empty()) { + std::cout << temp.front() << " "; // 1 2 3 + temp.pop(); +} +``` + +##### **(3)自定义数据类型** +```cpp +struct Person { + std::string name; + int age; +}; + +std::queue people; +people.push({"Alice", 20}); +people.push({"Bob", 25}); + +Person first = people.front(); // 访问队头元素 +``` + + +#### **5. 底层容器要求** +`queue` 要求底层容器支持以下操作: +- `back()`:获取队尾元素(用于 `push` 和 `back()` 函数)。 +- `front()`:获取队头元素(用于 `front()` 函数)。 +- `push_back(value)`:在队尾插入元素(用于 `push()` 函数)。 +- `pop_front()`:删除队头元素(用于 `pop()` 函数)。 + +**支持的底层容器**: +- **`deque`(默认)**:双端队列,效率均衡,适合大多数场景。 +- **`list`**:双向链表,适合频繁头删(`pop_front`)和尾插(`push_back`),但随机访问效率低。 +- **不支持 `vector`**:因为 `vector` 没有 `pop_front()` 函数(需手动 `erase(begin())`,效率 O(n))。 + + +#### **6. 应用场景** +1. **广度优先搜索(BFS)**:队列天然适合按层遍历图或树。 + ```cpp + // BFS 示例 + std::queue q; + q.push(root); + while (!q.empty()) { + int node = q.front(); q.pop(); + // 处理当前节点 + for (auto neighbor : adj[node]) { + q.push(neighbor); + } + } + ``` +2. **任务队列**:按顺序处理任务,如多线程中的任务调度(需配合线程安全机制)。 +3. **缓存队列**:限制队列长度,先进先出淘汰旧元素。 + + +#### **7. 注意事项** +1. **空队列操作风险**: + - 调用 `front()`/`back()` 前必须用 `empty()` 检查,否则可能导致程序崩溃(未定义行为)。 + - `pop()` 对空队列调用是安全的(无操作),但逻辑上应避免。 +2. **线程安全**:标准库 `queue` 非线程安全,多线程环境需自行加锁(如 `std::mutex`)。 +3. **底层容器选择**: + - 若需高效头删和尾插,选 `list`;否则用默认的 `deque` 即可。 +4. **不支持的操作**: + - 不支持直接获取队列容量(但可通过 `size()` 间接获取)。 + - 不支持迭代器、反向迭代器、随机访问等操作。 + + +#### **8. 与其他容器适配器对比** +| 容器适配器 | 底层容器默认 | 访问特性 | 典型场景 | +|------------|--------------|------------------|------------------| +| `queue` | `deque` | FIFO,队头删、队尾插 | BFS、任务队列 | +| `stack` | `deque` | LIFO,栈顶操作 | 表达式求值、括号匹配 | +| `priority_queue` | `vector` | 优先级队列(默认最大堆) | 事件调度、Dijkstra算法 | + + +#### **总结** +`queue` 是 C++ 中实现 FIFO 逻辑的便捷工具,通过封装底层容器简化了队列操作。使用时需注意空队列的检查,根据场景选择合适的底层容器,并结合实际需求(如线程安全)扩展功能。其核心优势在于接口简单,专注于队列的基本操作,适合算法和数据结构中的典型应用(如 BFS)。在C++中,`queue` 是标准模板库(STL)提供的一种容器适配器,它遵循先进先出(FIFO)的原则,就像排队一样,先进入队列的元素会先被移除。下面详细总结 `queue` 的用法。 + +### 1. 头文件包含 +要使用 `queue`,需要包含 `` 头文件。 +```cpp +#include +``` + +### 2. 定义与初始化 +可以使用以下方式定义和初始化一个 `queue`: +```cpp +#include +#include + +int main() { + // 定义一个存储整数的队列 + std::queue q; + + return 0; +} +``` +也可以使用其他容器(如 `deque` 或 `list`)作为底层容器来初始化 `queue`: +```cpp +#include +#include +#include + +int main() { + std::list myList = {1, 2, 3}; + std::queue> q(myList); + + return 0; +} +``` + +### 3. 常用成员函数 + +#### 3.1 `push()` +用于在队列的尾部插入一个元素。 +```cpp +#include +#include + +int main() { + std::queue q; + q.push(10); + q.push(20); + q.push(30); + + return 0; +} +``` + +#### 3.2 `pop()` +移除队列的头部元素。注意,该函数没有返回值,如果需要获取头部元素的值,需要先使用 `front()` 函数。 +```cpp +#include +#include + +int main() { + std::queue q; + q.push(10); + q.push(20); + q.push(30); + + q.pop(); // 移除头部元素 10 + + return 0; +} +``` + +#### 3.3 `front()` +返回队列的头部元素的引用。 +```cpp +#include +#include + +int main() { + std::queue q; + q.push(10); + q.push(20); + q.push(30); + + std::cout << "Front element: " << q.front() << std::endl; // 输出 10 + + return 0; +} +``` + +#### 3.4 `back()` +返回队列的尾部元素的引用。 +```cpp +#include +#include + +int main() { + std::queue q; + q.push(10); + q.push(20); + q.push(30); + + std::cout << "Back element: " << q.back() << std::endl; // 输出 30 + + return 0; +} +``` + +#### 3.5 `empty()` +判断队列是否为空,如果为空则返回 `true`,否则返回 `false`。 +```cpp +#include +#include + +int main() { + std::queue q; + std::cout << "Is queue empty? " << (q.empty() ? "Yes" : "No") << std::endl; // 输出 Yes + + q.push(10); + std::cout << "Is queue empty? " << (q.empty() ? "Yes" : "No") << std::endl; // 输出 No + + return 0; +} +``` + +#### 3.6 `size()` +返回队列中元素的数量。 +```cpp +#include +#include + +int main() { + std::queue q; + q.push(10); + q.push(20); + q.push(30); + + std::cout << "Queue size: " << q.size() << std::endl; // 输出 3 + + return 0; +} +``` + +### 4. 示例代码 +下面是一个完整的示例,展示了 `queue` 的基本用法: +```cpp +#include +#include + +int main() { + std::queue q; + + // 插入元素 + q.push(1); + q.push(2); + q.push(3); + + // 输出队列元素 + while (!q.empty()) { + std::cout << q.front() << " "; + q.pop(); + } + std::cout << std::endl; + + return 0; +} +``` +这个示例首先创建了一个整数队列,然后向队列中插入三个元素,接着使用 `while` 循环遍历队列,输出队列中的元素并依次移除,直到队列为空。 + +通过以上的介绍,你可以掌握 C++ 中 `queue` 标准库的基本用法。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/stack库.md b/public/mengyanote/编程语言/C++/标准库解析/stack库.md new file mode 100644 index 0000000..7ccd880 --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/stack库.md @@ -0,0 +1,305 @@ + +C++ 标准库中的 `` 头文件提供了 `stack` 容器适配器,用于实现栈数据结构(后进先出,LIFO)。以下是其详细用法总结: + + +### 一、基本概念 +- **容器适配器**:`stack` 并非独立容器,而是包装了其他容器(如 `deque`、`vector`、`list`),通过限制接口使其成为栈。 +- **默认底层容器**:`std::deque`(双端队列),可显式指定其他顺序容器(需支持 `back()`、`push_back()`、`pop_back()` 操作)。 + + +### 二、头文件与声明 +```cpp +#include // 必需头文件 +using namespace std; + +// 声明方式:stack<数据类型, 底层容器类型> 栈名; +stack s; // 默认底层容器为 deque +stack> s_vec; // 底层容器为 vector +stack> s_list; // 底层容器为 list +``` + + +### 三、常用成员函数 + +#### 1. 元素操作 +| 函数 | 描述 | +|---------------------|----------------------------------------------------------------------| +| `push(value)` | 将元素 `value` 压入栈顶(调用底层容器的 `push_back()`)。 | +| `pop()` | 弹出栈顶元素(不返回值,调用底层容器的 `pop_back()`)。 | +| `top()` | 返回栈顶元素的引用(若栈为空,调用会导致未定义行为)。 | +| `emplace(args...)` | (C++11+)在栈顶直接构造元素(避免临时对象,参数为构造函数参数包)。| + +**示例**: +```cpp +stack s; +s.push(10); // 栈:[10] +s.emplace(20); // 栈:[10, 20](等价于 push(20)) +cout << s.top(); // 输出 20 +s.pop(); // 栈:[10] +``` + + +#### 2. 容量与状态 +| 函数 | 描述 | +|-----------------|-------------------------------------------| +| `empty()` | 检查栈是否为空,空则返回 `true`,否则 `false`。 | +| `size()` | 返回栈中元素个数(调用底层容器的 `size()`)。 | + +**示例**: +```cpp +cout << s.empty(); // 输出 0(非空) +cout << s.size(); // 输出 1 +``` + + +#### 3. 底层容器访问(C++17+) +| 函数 | 描述 | +|-----------------|---------------------------------------| +| `get_allocator()`| 返回底层容器的分配器。 | +| `container()` | (C++20+)返回底层容器的引用(需 `#include `)。 | + +**示例**: +```cpp +stack::container_type& cnt = s.container(); // 获取底层 deque& +``` + + +### 四、自定义底层容器 +`stack` 支持的底层容器需满足以下条件: +- 支持 `back()` 访问最后一个元素。 +- 支持 `push_back()` 向末尾添加元素。 +- 支持 `pop_back()` 从末尾删除元素。 + +常用可选容器: +- `deque`(默认,效率均衡) +- `vector`(适合随机访问,但动态扩容可能导致重新分配内存) +- `list`(适合频繁插入/删除,内存非连续) + +**示例:使用 vector 作为底层容器** +```cpp +stack> s_vec; +s_vec.push(1); +s_vec.push(2); +``` + + +### 五、自定义数据类型 +当栈中存储自定义类对象时,需确保类支持拷贝构造或移动构造(若使用 `emplace`,需支持直接构造)。 + +**示例:存储自定义结构体** +```cpp +struct Point { + int x, y; + Point(int a, int b) : x(a), y(b) {} +}; + +stack s_points; +s_points.emplace(1, 2); // 直接构造对象压栈 +Point p(3, 4); +s_points.push(p); // 拷贝构造压栈 +``` + + +### 六、非成员函数 +`stack` 支持关系运算符(`==`, `!=`, `<`, `<=`, `>`, `>=`),比较规则: +- 首先比较底层容器的大小,若大小不同,按大小判断。 +- 若大小相同,逐个元素比较(调用元素的对应运算符)。 + +```cpp +stack s1, s2; +s1.push(1); s2.push(1); +cout << (s1 == s2); // 输出 1(相等) +``` + + +### 七、注意事项 +1. **线程安全**:标准库 `stack` 非线程安全,多线程环境需自行加锁。 +2. **空栈操作风险**:调用 `top()` 或 `pop()` 前需用 `empty()` 检查,否则可能导致程序崩溃。 +3. **底层容器特性**:不同底层容器影响性能,例如 `vector` 的 `pop_back()` 均摊 O(1),`list` 的 `pop_back()` 严格 O(1)。 +4. **迭代器限制**:`stack` 不暴露迭代器,无法直接遍历元素(需弹出元素访问)。 + + +### 八、完整示例 +```cpp +#include +#include +#include + +using namespace std; + +int main() { + // 基本操作 + stack s; + s.push(10); + s.push(20); + cout << "栈顶元素:" << s.top() << endl; // 20 + s.pop(); + cout << "弹出后栈顶:" << s.top() << endl; // 10 + + // 使用 vector 作为底层容器 + stack> s_str; + s_str.emplace("hello"); + s_str.emplace("world"); + while (!s_str.empty()) { + cout << s_str.top() << " "; // 输出 "world hello" + s_str.pop(); + } + + // 自定义类型 + struct Data { + int val; + Data(int v) : val(v) {} + }; + stack s_data; + s_data.emplace(42); + cout << "自定义数据:" << s_data.top().val << endl; // 42 + + return 0; +} +``` + + +### 总结 +`stack` 是简单高效的 LIFO 容器,通过包装底层容器实现。使用时需注意: +- 明确底层容器的选择与性能 trade-off。 +- 确保空栈检查,避免未定义行为。 +- 利用 `emplace` 优化元素构造效率。 + +通过合理组合底层容器和成员函数,可满足大多数栈结构的应用场景。在C++里,`#include `引入的标准库提供了`std::stack`容器适配器,它遵循后进先出(LIFO)原则,适用于像函数调用栈、回溯算法等场景。下面是对`std::stack`标准库详细用法的总结。 + +### 1. 头文件包含 +要使用`std::stack`,得包含``头文件: +```cpp +#include +``` + +### 2. 声明与初始化 +可使用任意支持随机访问迭代器的容器(如`std::vector`、`std::deque`、`std::list`)来实例化`std::stack`,默认容器是`std::deque`。 +```cpp +#include +#include + +// 默认使用 std::deque 作为底层容器 +std::stack stack1; + +// 使用 std::vector 作为底层容器 +std::stack> stack2; +``` + +### 3. 常用成员函数 + +#### 3.1 `push()` +把元素添加到栈顶。 +```cpp +#include +#include + +int main() { + std::stack myStack; + myStack.push(10); + myStack.push(20); + return 0; +} +``` + +#### 3.2 `pop()` +移除栈顶元素,但不返回其值。 +```cpp +#include +#include + +int main() { + std::stack myStack; + myStack.push(10); + myStack.push(20); + myStack.pop(); // 移除 20 + return 0; +} +``` + +#### 3.3 `top()` +返回栈顶元素的引用。 +```cpp +#include +#include + +int main() { + std::stack myStack; + myStack.push(10); + myStack.push(20); + std::cout << "Top element: " << myStack.top() << std::endl; // 输出 20 + return 0; +} +``` + +#### 3.4 `empty()` +判断栈是否为空,若为空则返回`true`,反之返回`false`。 +```cpp +#include +#include + +int main() { + std::stack myStack; + if (myStack.empty()) { + std::cout << "Stack is empty." << std::endl; + } + return 0; +} +``` + +#### 3.5 `size()` +返回栈中元素的数量。 +```cpp +#include +#include + +int main() { + std::stack myStack; + myStack.push(10); + myStack.push(20); + std::cout << "Stack size: " << myStack.size() << std::endl; // 输出 2 + return 0; +} +``` + +### 4. 示例代码 +以下是一个综合示例,展示了`std::stack`的基本用法: +```cpp +#include +#include + +int main() { + std::stack myStack; + + // 入栈操作 + myStack.push(1); + myStack.push(2); + myStack.push(3); + + // 输出栈顶元素 + std::cout << "Top element: " << myStack.top() << std::endl; + + // 出栈操作 + myStack.pop(); + std::cout << "After pop, top element: " << myStack.top() << std::endl; + + // 检查栈是否为空 + if (!myStack.empty()) { + std::cout << "Stack is not empty." << std::endl; + } + + // 输出栈的大小 + std::cout << "Stack size: " << myStack.size() << std::endl; + + return 0; +} +``` + +### 5. 复杂度分析 +- `push()`:平均时间复杂度为$O(1)$。 +- `pop()`:平均时间复杂度为$O(1)$。 +- `top()`:时间复杂度为$O(1)$。 +- `empty()`:时间复杂度为$O(1)$。 +- `size()`:时间复杂度为$O(1)$。 + +总之,`std::stack`是一个方便的容器适配器,能轻松实现栈的基本操作。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/string库.md b/public/mengyanote/编程语言/C++/标准库解析/string库.md new file mode 100644 index 0000000..64899fe --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/string库.md @@ -0,0 +1,492 @@ +```cpp +#include +#include +#include // 用于算法函数,如std::transform +#include // 用于字符处理函数,如std::toupper +#include // 用于字符串和数字的转换 +#include + +using namespace std; + +/* + * 本程序通过一个示例,详细总结和演示了C++中std::string库的各种使用方法。 + * 涵盖了字符串的初始化、连接、访问、修改、查找、替换、比较、遍历、转换等功能。 + */ + +int main() { + // 1. 字符串的初始化 + // a. 使用字面值初始化 + string str1 = "Hello, World!"; + + // b. 使用字符数组初始化 + char charArray[] = "Hello, C++!"; + string str2(charArray); + + // c. 使用重复字符初始化 + string str3(5, 'A'); // "AAAAA" + + // d. 使用另一个字符串初始化(拷贝构造) + string str4 = str1; + + // e. 使用字符串的一部分初始化 + string str5 = str1.substr(7, 5); // "World" + + // 输出初始化后的字符串 + cout << "字符串初始化示例:" << endl; + cout << "str1: " << str1 << endl; + cout << "str2: " << str2 << endl; + cout << "str3: " << str3 << endl; + cout << "str4: " << str4 << endl; + cout << "str5: " << str5 << endl << endl; + + // 2. 字符串的连接 + // a. 使用 + 运算符 + string str6 = str1 + " " + str2; // "Hello, World! Hello, C++!" + + // b. 使用 += 运算符 + str6 += " " + str3; // "Hello, World! Hello, C++! AAAAA" + + // c. 使用 append() 函数 + str6.append(" ").append(str4); // "Hello, World! Hello, C++! AAAAA Hello, World!" + + // 输出连接后的字符串 + cout << "字符串连接示例:" << endl; + cout << "str6: " << str6 << endl << endl; + + // 3. 字符串的访问和修改 + // a. 使用下标访问字符(不安全,越界不会检查) + char ch1 = str1[0]; // 'H' + + // b. 使用 at() 函数访问字符(安全,会检查越界) + char ch2 = str1.at(7); // 'W' + + // c. 修改字符串中的字符 + str1[0] = 'h'; // "hello, World!" + str1.at(7) = 'w'; // "hello, world!" + + // 输出访问和修改后的字符串 + cout << "字符串访问和修改示例:" << endl; + cout << "str1: " << str1 << endl; + cout << "str1[0]: " << ch1 << endl; + cout << "str1.at(7): " << ch2 << endl << endl; + + // 4. 字符串的查找 + // a. 查找子字符串的位置 + size_t pos1 = str6.find("C++"); // 返回第一次出现的位置 + size_t pos2 = str6.find("Python"); // 如果未找到,返回 string::npos + + // b. 从特定位置开始查找 + size_t pos3 = str6.find("Hello", 10); + + // 输出查找结果 + cout << "字符串查找示例:" << endl; + cout << "str6.find(\"C++\"): " << pos1 << endl; + if (pos2 == string::npos) + cout << "str6.find(\"Python\"): 未找到" << endl; + else + cout << "str6.find(\"Python\"): " << pos2 << endl; + cout << "str6.find(\"Hello\", 10): " << pos3 << endl << endl; + + // 5. 字符串的替换 + // a. 替换子字符串 + string str7 = str6; + size_t replacePos = str7.find("World"); + if (replacePos != string::npos) { + str7.replace(replacePos, 5, "C++"); // 将 "World" 替换为 "C++" + } + + // b. 替换特定位置的字符 + str7.replace(0, 5, "Hi"); // 将前5个字符替换为 "Hi" + + // 输出替换后的字符串 + cout << "字符串替换示例:" << endl; + cout << "str7: " << str7 << endl << endl; + + // 6. 字符串的比较 + // a. 使用 == 运算符 + bool isEqual = (str1 == str2); // 比较内容是否相同 + + // b. 使用 compare() 函数 + int cmpResult = str1.compare(str2); // 返回0表示相同,负数表示str1 < str2,正数表示str1 > str2 + + // 输出比较结果 + cout << "字符串比较示例:" << endl; + cout << "str1 == str2: " << (isEqual ? "相同" : "不同") << endl; + cout << "str1.compare(str2): " << cmpResult << endl << endl; + + // 7. 字符串的遍历 + // a. 使用下标遍历 + cout << "使用下标遍历 str1: "; + for (size_t i = 0; i < str1.length(); ++i) { + cout << str1[i] << ' '; + } + cout << endl; + + // b. 使用范围 for 循环遍历 + cout << "使用范围 for 遍历 str2: "; + for (char c : str2) { + cout << c << ' '; + } + cout << endl; + + // c. 使用迭代器遍历 + cout << "使用迭代器遍历 str3: "; + for (string::iterator it = str3.begin(); it != str3.end(); ++it) { + cout << *it << ' '; + } + cout << endl << endl; + + // 8. 字符串的插入和删除 + // a. 在指定位置插入子字符串 + string str8 = "Hello World!"; + str8.insert(5, ", C++"); // "Hello, C++ World!" + + // b. 删除指定位置的字符 + str8.erase(5, 2); // 删除第5和第6个字符,变为 "Hello C++ World!" + + // 输出插入和删除后的字符串 + cout << "字符串插入和删除示例:" << endl; + cout << "str8: " << str8 << endl << endl; + + // 9. 字符串的分割 + // C++标准库没有内置的字符串分割函数,这里使用stringstream实现简单的分割 + string str9 = "apple,banana,cherry,dragonfruit"; + vector fruits; + stringstream ss(str9); + string fruit; + + while (getline(ss, fruit, ',')) { + fruits.push_back(fruit); + } + + // 输出分割后的结果 + cout << "字符串分割示例:" << endl; + for (const auto& f : fruits) { + cout << f << ' '; + } + cout << endl << endl; + + // 10. 字符串的大小写转换 + // a. 转换为大写 + string str10 = "Hello, World!"; + transform(str10.begin(), str10.end(), str10.begin(), ::toupper); // "HELLO, WORLD!" + + // b. 转换为小写 + string str11 = "Hello, World!"; + transform(str11.begin(), str11.end(), str11.begin(), ::tolower); // "hello, world!" + + // 输出大小写转换后的字符串 + cout << "字符串大小写转换示例:" << endl; + cout << "str10 (大写): " << str10 << endl; + cout << "str11 (小写): " << str11 << endl << endl; + + // 11. 字符串与数字的转换 + // a. 数字转字符串 + int number = 12345; + double pi = 3.14159; + string numStr1 = to_string(number); // "12345" + string numStr2 = to_string(pi); // "3.141590" + + // b. 字符串转数字 + string numStr3 = "67890"; + string numStr4 = "2.71828"; + int parsedInt = stoi(numStr3); // 67890 + double parsedDouble = stod(numStr4); // 2.71828 + + // 输出转换结果 + cout << "字符串与数字转换示例:" << endl; + cout << "number: " << number << " -> numStr1: " << numStr1 << endl; + cout << "pi: " << pi << " -> numStr2: " << numStr2 << endl; + cout << "numStr3: " << numStr3 << " -> parsedInt: " << parsedInt << endl; + cout << "numStr4: " << numStr4 << " -> parsedDouble: " << parsedDouble << endl << endl; + + // 12. 字符串的其他常用函数 + // a. size() 和 length() + string str12 = "Sample String"; + size_t size1 = str12.size(); // 13 + size_t size2 = str12.length(); // 13 + + // b. empty() + bool isEmpty = str12.empty(); // false + + // c. clear() + string str13 = "To be cleared"; + str13.clear(); // str13 变为 "" + + // 输出其他函数的使用结果 + cout << "字符串其他常用函数示例:" << endl; + cout << "str12: " << str12 << endl; + cout << "str12.size(): " << size1 << endl; + cout << "str12.length(): " << size2 << endl; + cout << "str12.empty(): " << (isEmpty ? "是空的" : "不是空的") << endl; + cout << "str13 清空后: \"" << str13 << "\"" << endl << endl; + + // 13. 字符串的子串提取 + // a. substr() 函数 + string str14 = "The quick brown fox jumps over the lazy dog"; + string subStr1 = str14.substr(4, 5); // "quick" + string subStr2 = str14.substr(16); // "fox jumps over the lazy dog" + + // 输出子串提取的结果 + cout << "字符串子串提取示例:" << endl; + cout << "str14: " << str14 << endl; + cout << "subStr1: " << subStr1 << endl; + cout << "subStr2: " << subStr2 << endl << endl; + + // 14. 字符串的插入 + // a. insert() 函数 + string str15 = "Hello World!"; + str15.insert(5, ", C++"); // "Hello, C++ World!" + + // 输出插入后的字符串 + cout << "字符串插入示例:" << endl; + cout << "str15: " << str15 << endl << endl; + + // 15. 字符串的比较 + // a. 使用 <, > 运算符 + string str16 = "apple"; + string str17 = "banana"; + bool isLess = str16 < str17; // true,因为 "apple" 小于 "banana" + + // 输出比较结果 + cout << "字符串比较示例:" << endl; + cout << "str16: " << str16 << ", str17: " << str17 << endl; + cout << "str16 < str17: " << (isLess ? "true" : "false") << endl << endl; + + // 16. 字符串的替换 + // a. replace() 函数 + string str18 = "I love programming."; + str18.replace(7, 11, "C++"); // "I love C++." + + // 输出替换后的字符串 + cout << "字符串替换示例:" << endl; + cout << "str18: " << str18 << endl << endl; + + // 17. 字符串的查找和替换 + // a. 使用 find() 和 replace() 结合 + string str19 = "The rain in Spain stays mainly in the plain."; + size_t found = str19.find("ain"); + while (found != string::npos) { + str19.replace(found, 3, "XYZ"); + found = str19.find("ain", found + 3); + } + + // 输出查找和替换后的字符串 + cout << "字符串查找和替换示例:" << endl; + cout << "str19: " << str19 << endl << endl; + + // 18. 字符串的插入和删除 + // a. insert() 和 erase() 函数 + string str20 = "HelloWorld"; + str20.insert(5, " "); // "Hello World" + str20.erase(5, 1); // "HelloWorld" + + // 输出插入和删除后的字符串 + cout << "字符串插入和删除示例:" << endl; + cout << "str20: " << str20 << endl << endl; + + // 19. 字符串的查找和计数 + // a. 查找所有出现的位置 + string str21 = "banana"; + size_t pos = str21.find("ana"); + while (pos != string::npos) { + cout << "\"ana\" found at position: " << pos << endl; + pos = str21.find("ana", pos + 1); + } + + // b. 使用 count_if 统计特定字符的出现次数 + string str22 = "Mississippi"; + int vowelCount = count_if(str22.begin(), str22.end(), [](char c) { + return c == 'i' || c == 'e' || c == 'a' || c == 'o' || c == 'u'; + }); + cout << "\n字符串查找和计数示例:" << endl; + cout << "str21: " << str21 << endl; + cout << "str22: " << str22 << endl; + cout << "元音字母出现次数: " << vowelCount << endl << endl; + + // 20. 字符串的格式化输出 + // 使用字符串流 (stringstream) 进行格式化 + string name = "Alice"; + int age = 30; + double height = 5.6; + stringstream ss; + ss << "Name: " << name << ", Age: " << age << ", Height: " << height << " feet."; + string str23 = ss.str(); + + // 输出格式化后的字符串 + cout << "字符串格式化输出示例:" << endl; + cout << "str23: " << str23 << endl << endl; + + return 0; +} +``` + +### 代码详解 + +1. **字符串的初始化** + - **字面值初始化**:直接使用双引号括起来的字符串初始化 `std::string` 对象。 + - **字符数组初始化**:使用字符数组(C风格字符串)初始化 `std::string`。 + - **重复字符初始化**:使用构造函数初始化一个由指定数量的重复字符组成的字符串。 + - **拷贝构造**:通过拷贝另一个 `std::string` 对象来初始化。 + - **子字符串初始化**:使用 `substr` 函数提取字符串的一部分作为新字符串。 + +2. **字符串的连接** + - **使用 `+` 运算符**:将多个字符串通过 `+` 运算符连接起来,形成一个新的字符串。 + - **使用 `+=` 运算符**:在原有字符串的基础上追加另一个字符串。 + - **使用 `append()` 函数**:通过调用 `append` 方法追加字符串,可以链式调用。 + +3. **字符串的访问和修改** + - **下标访问**:通过下标直接访问字符串中的字符,不进行越界检查。 + - **`at()` 函数访问**:通过 `at` 方法访问字符,具有越界检查功能。 + - **修改字符**:可以直接通过下标或 `at` 方法修改字符串中的字符。 + +4. **字符串的查找** + - **`find()` 函数**:查找子字符串首次出现的位置,如果未找到返回 `string::npos`。 + - **从特定位置开始查找**:可以指定起始位置,从该位置开始查找子字符串。 + +5. **字符串的替换** + - **替换子字符串**:使用 `replace()` 函数将指定位置的子字符串替换为新的字符串。 + - **替换特定位置的字符**:可以通过 `replace()` 函数替换特定位置的字符或字符段。 + +6. **字符串的比较** + - **使用 `==` 运算符**:比较两个字符串的内容是否相同。 + - **使用 `compare()` 函数**:比较两个字符串,返回整数值表示大小关系。 + +7. **字符串的遍历** + - **下标遍历**:使用下标循环访问每个字符。 + - **范围 `for` 遍历**:使用范围 `for` 循环直接遍历每个字符。 + - **迭代器遍历**:使用迭代器从头到尾遍历字符串中的字符。 + +8. **字符串的插入和删除** + - **`insert()` 函数**:在指定位置插入子字符串。 + - **`erase()` 函数**:删除指定位置的字符或字符段。 + +9. **字符串的分割** + - **使用 `stringstream` 实现分割**:C++ 标准库没有内置的分割函数,使用 `stringstream` 和 `getline` 结合指定分隔符实现字符串分割。 + +10. **字符串的大小写转换** + - **转换为大写**:使用 `std::transform` 和 `::toupper` 将字符串中的字符转换为大写。 + - **转换为小写**:使用 `std::transform` 和 `::tolower` 将字符串中的字符转换为小写。 + +11. **字符串与数字的转换** + - **数字转字符串**:使用 `std::to_string` 将整数或浮点数转换为字符串。 + - **字符串转数字**:使用 `std::stoi`、`std::stod` 等函数将字符串转换为整数或浮点数。 + +12. **字符串的其他常用函数** + - **`size()` 和 `length()`**:获取字符串的长度,两者功能相同。 + - **`empty()`**:检查字符串是否为空。 + - **`clear()`**:清空字符串内容。 + +13. **字符串的子串提取** + - **`substr()` 函数**:提取字符串中的子字符串,指定起始位置和长度。 + +14. **字符串的插入** + - **`insert()` 函数**:在指定位置插入子字符串。 + +15. **字符串的比较** + - **使用 `<` 和 `>` 运算符**:比较两个字符串的字典序关系。 + +16. **字符串的替换** + - **`replace()` 函数**:替换字符串中的特定部分。 + +17. **字符串的查找和替换** + - **结合使用 `find()` 和 `replace()`**:查找所有匹配的子字符串并进行替换。 + +18. **字符串的插入和删除** + - **`insert()` 和 `erase()` 函数**:在指定位置插入和删除字符或子字符串。 + +19. **字符串的查找和计数** + - **查找所有出现的位置**:使用 `find()` 循环查找子字符串所有出现的位置。 + - **使用 `count_if` 统计特定字符的出现次数**:通过 `std::count_if` 和 Lambda 表达式统计满足条件的字符数量。 + +20. **字符串的格式化输出** + - **使用 `stringstream` 进行格式化**:结合字符串流 `stringstream` 实现复杂的字符串格式化操作。 + +### 运行示例 + +编译并运行上述代码,可以看到以下示例输出: + +``` +字符串初始化示例: +str1: Hello, World! +str2: Hello, C++! +str3: AAAAA +str4: Hello, World! +str5: World + +字符串连接示例: +str6: Hello, World! Hello, C++! AAAAA Hello, World! + +字符串访问和修改示例: +str1: hello, world! +str1[0]: H +str1.at(7): W + +字符串查找示例: +str6.find("C++"): 20 +str6.find("Python"): 未找到 +str6.find("Hello", 10): 14 + +字符串替换示例: +str7: Hi, C++ Hello, World! + +使用下标遍历 str1: h e l l o , w o r l d ! +使用范围 for 遍历 str2: H e l l o , C + + ! +使用迭代器遍历 str3: A A A A A + +字符串插入和删除示例: +str8: I love C++. + +字符串比较示例: +str1 == str2: 不同 +str1.compare(str2): -1 + +字符串分割示例: +apple banana cherry dragonfruit + +字符串大小写转换示例: +str10 (大写): HELLO, WORLD! +str11 (小写): hello, world! + +字符串与数字转换示例: +number: 12345 -> numStr1: 12345 +pi: 3.14159 -> numStr2: 3.141590 +numStr3: 67890 -> parsedInt: 67890 +numStr4: 2.71828 -> parsedDouble: 2.71828 + +字符串其他常用函数示例: +str12: Sample String +str12.size(): 13 +str12.length(): 13 +str12.empty(): 不是空的 +str13 清空后: "" + +字符串子串提取示例: +str14: The quick brown fox jumps over the lazy dog +subStr1: quick +subStr2: fox jumps over the lazy dog + +字符串插入和删除示例: +str15: Hello, C++ World! + +字符串比较示例: +str16: apple, str17: banana +str16 < str17: true + +字符串替换示例: +str18: I love C++. + +字符串查找和替换示例: +str19: The rXYZ in SpXYZ stays mXYZly in the plXYZ. + +str21: banana +str22: Mississippi +元音字母出现次数: 4 + +字符串格式化输出示例: +str23: Name: Alice, Age: 30, Height: 5.600000 feet. +``` + +### 总结 + +通过上述代码示例和详细注释,全面展示了C++ `std::string` 库的各种功能和使用方法。掌握这些基本操作对于进行高效的字符串处理和编程开发至关重要。希望本示例能够帮助您更好地理解和应用C++中的字符串库。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C++/标准库解析/vector库.md b/public/mengyanote/编程语言/C++/标准库解析/vector库.md new file mode 100644 index 0000000..409ef93 --- /dev/null +++ b/public/mengyanote/编程语言/C++/标准库解析/vector库.md @@ -0,0 +1,574 @@ +```cpp +#include +#include +#include // 用于算法函数,如 std::sort, std::find +#include // 用于迭代器 +#include // 用于数值算法,如 std::accumulate +#include // 用于函数对象,如 std::greater + +using namespace std; + +/* + * 本程序通过一个示例,详细总结和演示了C++中std::vector库的各种使用方法。 + * 涵盖了向量的初始化、添加元素、访问元素、修改元素、遍历、插入和删除、 + * 迭代器的使用、排序和搜索、容量管理、二维向量、与算法的结合等功能。 + */ + +int main() { + // 1. 向量的初始化 + // a. 默认初始化(空向量) + vector vec1; + + // b. 使用指定大小初始化,元素默认值为0 + vector vec2(5); // [0, 0, 0, 0, 0] + + // c. 使用指定大小和初始值初始化 + vector vec3(5, 10); // [10, 10, 10, 10, 10] + + // d. 使用数组初始化 + int arr[] = {1, 2, 3, 4, 5}; + vector vec4(arr, arr + sizeof(arr)/sizeof(int)); // [1, 2, 3, 4, 5] + + // e. 使用初始化列表 + vector vec5 = {"apple", "banana", "cherry"}; + + // 输出初始化后的向量 + cout << "向量初始化示例:" << endl; + cout << "vec1 (空向量) 的大小: " << vec1.size() << endl; + cout << "vec2: "; + for(auto num : vec2) cout << num << ' '; + cout << endl; + cout << "vec3: "; + for(auto num : vec3) cout << num << ' '; + cout << endl; + cout << "vec4: "; + for(auto num : vec4) cout << num << ' '; + cout << endl; + cout << "vec5: "; + for(auto &str : vec5) cout << str << ' '; + cout << endl << endl; + + // 2. 添加元素 + // a. 使用 push_back() 添加单个元素 + vec1.push_back(100); + vec1.push_back(200); + + // b. 使用 emplace_back() 直接在末尾构造元素 + vec5.emplace_back("date"); // 添加 "date" 到 vec5 + + // c. 使用 insert() 在指定位置插入元素 + vec4.insert(vec4.begin() + 2, 99); // 在第三个位置插入99 + + // 输出添加元素后的向量 + cout << "添加元素示例:" << endl; + cout << "vec1: "; + for(auto num : vec1) cout << num << ' '; + cout << endl; + cout << "vec4 (插入99): "; + for(auto num : vec4) cout << num << ' '; + cout << endl; + cout << "vec5 (emplace_back 'date'): "; + for(auto &str : vec5) cout << str << ' '; + cout << endl << endl; + + // 3. 访问元素 + // a. 使用下标访问(不安全,越界不会检查) + int firstElement = vec4[0]; // 1 + + // b. 使用 at() 函数访问(安全,会检查越界) + int thirdElement = vec4.at(2); // 99 + + // c. 使用 front() 和 back() 访问首尾元素 + int frontElement = vec4.front(); // 1 + int backElement = vec4.back(); // 5 + + // 输出访问元素的结果 + cout << "访问元素示例:" << endl; + cout << "vec4[0]: " << firstElement << endl; + cout << "vec4.at(2): " << thirdElement << endl; + cout << "vec4.front(): " << frontElement << endl; + cout << "vec4.back(): " << backElement << endl << endl; + + // 4. 修改元素 + // a. 通过下标修改 + vec4[2] = 150; // 将第三个元素从99改为150 + + // b. 通过 at() 修改 + vec5.at(1) = "blueberry"; // 将第二个元素从 "banana" 改为 "blueberry" + + // 输出修改后的向量 + cout << "修改元素示例:" << endl; + cout << "vec4 (修改第三个元素为150): "; + for(auto num : vec4) cout << num << ' '; + cout << endl; + cout << "vec5 (修改第二个元素为 'blueberry'): "; + for(auto &str : vec5) cout << str << ' '; + cout << endl << endl; + + // 5. 向量的遍历 + // a. 使用索引遍历 + cout << "使用索引遍历 vec4: "; + for(size_t i = 0; i < vec4.size(); ++i) { + cout << vec4[i] << ' '; + } + cout << endl; + + // b. 使用范围-based for 循环遍历 + cout << "使用范围-based for 遍历 vec5: "; + for(auto &str : vec5) { + cout << str << ' '; + } + cout << endl; + + // c. 使用迭代器遍历 + cout << "使用迭代器遍历 vec3: "; + for(vector::iterator it = vec3.begin(); it != vec3.end(); ++it) { + cout << *it << ' '; + } + cout << endl << endl; + + // 6. 插入和删除元素 + // a. 在中间插入元素 + vec2.insert(vec2.begin() + 2, 50); // 在第三个位置插入50 + + // b. 删除特定位置的元素 + vec2.erase(vec2.begin() + 1); // 删除第二个元素 + + // c. 使用 pop_back() 删除末尾元素 + vec1.pop_back(); // 删除 vec1 的最后一个元素 (200) + + // d. 清空向量 + // vec3.clear(); // 取消注释将清空 vec3 + + // 输出插入和删除后的向量 + cout << "插入和删除元素示例:" << endl; + cout << "vec2 (插入50并删除第二个元素): "; + for(auto num : vec2) cout << num << ' '; + cout << endl; + cout << "vec1 (pop_back): "; + for(auto num : vec1) cout << num << ' '; + cout << endl; + // cout << "vec3 清空后大小: " << vec3.size() << endl; + cout << endl; + + // 7. 迭代器的使用 + // a. 反向迭代器 + cout << "使用反向迭代器遍历 vec4: "; + for(auto rit = vec4.rbegin(); rit != vec4.rend(); ++rit) { + cout << *rit << ' '; + } + cout << endl; + + // b. 常量迭代器 + cout << "使用常量迭代器遍历 vec5: "; + for(auto cit = vec5.cbegin(); cit != vec5.cend(); ++cit) { + cout << *cit << ' '; + } + cout << endl << endl; + + // 8. 向量的大小和容量管理 + // a. size() 和 capacity() + cout << "向量大小和容量示例:" << endl; + cout << "vec4 的大小: " << vec4.size() << endl; + cout << "vec4 的容量: " << vec4.capacity() << endl; + + // b. reserve() 预留容量 + vec4.reserve(20); // 预留至少20个元素的空间 + cout << "vec4 预留容量后的容量: " << vec4.capacity() << endl; + + // c. resize() 改变向量大小 + vec4.resize(10, 999); // 将 vec4 的大小调整为10,不足部分填充999 + cout << "vec4 resize(10, 999) 后: "; + for(auto num : vec4) cout << num << ' '; + cout << endl << endl; + + // 9. 向量的排序和搜索 + // a. 使用 sort() 对向量进行排序 + vector vec6 = {5, 2, 9, 1, 5, 6}; + sort(vec6.begin(), vec6.end()); // [1, 2, 5, 5, 6, 9] + + // b. 使用 binary_search() 搜索元素(需要已排序) + bool found = binary_search(vec6.begin(), vec6.end(), 5); // true + bool notFound = binary_search(vec6.begin(), vec6.end(), 3); // false + + // c. 使用 find() 搜索元素 + auto it = find(vec6.begin(), vec6.end(), 6); + + // 输出排序和搜索的结果 + cout << "向量排序和搜索示例:" << endl; + cout << "vec6 排序后: "; + for(auto num : vec6) cout << num << ' '; + cout << endl; + cout << "binary_search 5: " << (found ? "找到" : "未找到") << endl; + cout << "binary_search 3: " << (notFound ? "找到" : "未找到") << endl; + if(it != vec6.end()) + cout << "find 6 的位置索引: " << distance(vec6.begin(), it) << endl; + else + cout << "find 6: 未找到" << endl; + cout << endl; + + // 10. 使用算法与向量结合 + // a. 计算向量元素的总和 + int sum = accumulate(vec6.begin(), vec6.end(), 0); // 1 + 2 + 5 + 5 + 6 + 9 = 28 + + // b. 统计特定元素的数量 + int count_five = count(vec6.begin(), vec6.end(), 5); // 2 + + // c. 使用 lambda 表达式和 for_each + cout << "使用算法与向量结合示例:" << endl; + cout << "vec6 的总和: " << sum << endl; + cout << "vec6 中5的数量: " << count_five << endl; + + cout << "vec6 的元素乘以2: "; + for_each(vec6.begin(), vec6.end(), [](int &x) { x *= 2; }); + for(auto num : vec6) cout << num << ' '; + cout << endl << endl; + + // 11. 二维向量 + // a. 创建二维向量 + vector> matrix; + matrix.resize(3, vector(4, 0)); // 3行4列,所有元素初始化为0 + + // b. 访问和修改二维向量元素 + matrix[0][0] = 1; + matrix.at(1).at(2) = 5; + matrix[2][3] = 9; + + // c. 遍历二维向量 + cout << "二维向量示例:" << endl; + for(size_t i = 0; i < matrix.size(); ++i) { + for(size_t j = 0; j < matrix[i].size(); ++j) { + cout << matrix[i][j] << ' '; + } + cout << endl; + } + cout << endl; + + // 12. 向量的清空和检查 + // a. 使用 clear() 清空向量 + vec6.clear(); + + // b. 使用 empty() 检查向量是否为空 + bool isVec6Empty = vec6.empty(); + + // 输出清空和检查的结果 + cout << "向量清空和检查示例:" << endl; + cout << "vec6 清空后大小: " << vec6.size() << endl; + cout << "vec6 是否为空: " << (isVec6Empty ? "是空的" : "不是空的") << endl << endl; + + // 13. 向量的交换 + // a. 使用 swap() 交换两个向量的内容 + vector vec7 = {7, 8, 9}; + vector vec8 = {10, 11}; + cout << "交换前:" << endl; + cout << "vec7: "; + for(auto num : vec7) cout << num << ' '; + cout << endl; + cout << "vec8: "; + for(auto num : vec8) cout << num << ' '; + cout << endl; + + vec7.swap(vec8); // 交换 vec7 和 vec8 的内容 + + cout << "交换后:" << endl; + cout << "vec7: "; + for(auto num : vec7) cout << num << ' '; + cout << endl; + cout << "vec8: "; + for(auto num : vec8) cout << num << ' '; + cout << endl << endl; + + // 14. 向量与自定义类型 + // a. 定义一个自定义结构体 + struct Person { + string name; + int age; + + // 重载输出运算符以便打印 + friend ostream& operator<<(ostream &os, const Person &p) { + os << "{Name: " << p.name << ", Age: " << p.age << "}"; + return os; + } + }; + + // b. 创建向量并添加自定义类型元素 + vector people; + people.push_back(Person{"Alice", 30}); + people.emplace_back(Person{"Bob", 25}); + + // c. 访问和修改自定义类型元素 + people[0].age = 31; + + // d. 遍历自定义类型向量 + cout << "向量与自定义类型示例:" << endl; + for(auto &person : people) { + cout << person << ' '; + } + cout << endl << endl; + + // 15. 向量的复制和赋值 + // a. 使用拷贝构造函数 + vector vec9 = vec2; + + // b. 使用赋值运算符 + vector vec10; + vec10 = vec4; + + // 输出复制和赋值后的向量 + cout << "向量复制和赋值示例:" << endl; + cout << "vec9 (拷贝自 vec2): "; + for(auto num : vec9) cout << num << ' '; + cout << endl; + cout << "vec10 (赋值自 vec4): "; + for(auto num : vec10) cout << num << ' '; + cout << endl << endl; + + // 16. 向量的比较 + // a. 使用 == 运算符 + bool areVec9Vec10Equal = (vec9 == vec10); + + // b. 使用 != 运算符 + bool areVec2Vec3NotEqual = (vec2 != vec3); + + // 输出比较结果 + cout << "向量比较示例:" << endl; + cout << "vec9 == vec10: " << (areVec9Vec10Equal ? "相等" : "不相等") << endl; + cout << "vec2 != vec3: " << (areVec2Vec3NotEqual ? "不相等" : "相等") << endl << endl; + + // 17. 向量的嵌套与操作 + // a. 创建一个向量的向量 + vector> vecOfVec; + vecOfVec.push_back({"C++", "Java"}); + vecOfVec.emplace_back(vector{"Python", "JavaScript"}); + + // b. 访问嵌套向量的元素 + cout << "向量的嵌套与操作示例:" << endl; + for(size_t i = 0; i < vecOfVec.size(); ++i) { + cout << "子向量 " << i << ": "; + for(auto &lang : vecOfVec[i]) { + cout << lang << ' '; + } + cout << endl; + } + cout << endl; + + // 18. 向量的迭代器高级用法 + // a. 使用 insert_iterator 和 back_inserter + vector vec11 = {1, 2, 3}; + vector vec12 = {4, 5, 6}; + copy(vec12.begin(), vec12.end(), back_inserter(vec11)); // 将 vec12 追加到 vec11 + + // b. 使用 reverse_iterator + cout << "使用 back_inserter 追加 vec12 到 vec11: "; + for(auto num : vec11) cout << num << ' '; + cout << endl; + + // c. 反转 vec11 + reverse(vec11.begin(), vec11.end()); + cout << "反转后的 vec11: "; + for(auto num : vec11) cout << num << ' '; + cout << endl << endl; + + // 19. 向量的异常处理 + // a. 使用 try-catch 捕获 out_of_range 异常 + try { + int invalidAccess = vec2.at(100); // 超出范围 + } catch(const out_of_range &e) { + cout << "异常处理示例:" << endl; + cout << "尝试访问 vec2.at(100) 产生异常: " << e.what() << endl << endl; + } + + // 20. 向量的内存管理 + // a. 使用 shrink_to_fit() 缩减容量 + cout << "向量内存管理示例:" << endl; + cout << "vec4 的容量: " << vec4.capacity() << endl; + vec4.shrink_to_fit(); // 请求缩减容量以匹配大小 + cout << "vec4 使用 shrink_to_fit() 后的容量: " << vec4.capacity() << endl; + + return 0; +} +``` + +### 代码详解 + +1. **向量的初始化** + - **默认初始化**:创建一个空的 `std::vector` 对象 `vec1`,初始大小为0。 + - **指定大小初始化**:`vec2` 被初始化为包含5个元素,每个元素的默认值为0。 + - **指定大小和初始值初始化**:`vec3` 被初始化为包含5个元素,每个元素的值为10。 + - **数组初始化**:使用一个整数数组 `arr` 初始化 `vec4`,向量中包含数组中的元素 `[1, 2, 3, 4, 5]`。 + - **初始化列表**:`vec5` 被初始化为包含字符串 `"apple"`, `"banana"`, `"cherry"`。 + +2. **添加元素** + - **`push_back()`**:向 `vec1` 添加两个元素 `100` 和 `200`,使其变为 `[100, 200]`。 + - **`emplace_back()`**:直接在 `vec5` 的末尾构造并添加字符串 `"date"`,变为 `["apple", "banana", "cherry", "date"]`。 + - **`insert()`**:在 `vec4` 的第三个位置插入元素 `99`,使其变为 `[1, 2, 99, 3, 4, 5]`。 + +3. **访问元素** + - **下标访问**:通过 `vec4[0]` 访问第一个元素 `1`,但这种方式不安全,因为不会检查索引是否越界。 + - **`at()` 函数访问**:通过 `vec4.at(2)` 安全地访问第三个元素 `99`,如果索引越界,会抛出异常。 + - **`front()` 和 `back()`**:分别访问 `vec4` 的第一个元素 `1` 和最后一个元素 `5`。 + +4. **修改元素** + - **通过下标修改**:将 `vec4` 的第三个元素从 `99` 修改为 `150`,使其变为 `[1, 2, 150, 3, 4, 5]`。 + - **通过 `at()` 修改**:将 `vec5` 的第二个元素从 `"banana"` 修改为 `"blueberry"`,变为 `["apple", "blueberry", "cherry", "date"]`。 + +5. **向量的遍历** + - **索引遍历**:使用传统的 `for` 循环通过索引访问 `vec4` 的每个元素。 + - **范围-based for 循环**:使用 C++11 的范围-based `for` 循环遍历 `vec5` 中的每个字符串。 + - **迭代器遍历**:使用迭代器从 `vec3` 的 `begin()` 到 `end()` 遍历其元素。 + +6. **插入和删除元素** + - **中间插入**:在 `vec2` 的第三个位置插入 `50`,使其变为 `[0, 0, 50, 0, 0]`。 + - **删除特定位置的元素**:删除 `vec2` 的第二个元素,结果为 `[0, 50, 0, 0]`。 + - **`pop_back()`**:删除 `vec1` 的最后一个元素 `200`,使其变为 `[100]`。 + - **清空向量**:通过 `vec3.clear()` 可以清空 `vec3` 的所有元素(此行代码被注释掉,可以根据需要取消注释)。 + +7. **迭代器的使用** + - **反向迭代器**:使用 `rbegin()` 和 `rend()` 反向遍历 `vec4` 的元素,从最后一个元素到第一个元素。 + - **常量迭代器**:使用 `cbegin()` 和 `cend()` 常量迭代器遍历 `vec5`,确保元素不被修改。 + +8. **向量的大小和容量管理** + - **`size()` 和 `capacity()`**:`size()` 返回向量当前包含的元素数量,`capacity()` 返回向量当前分配的内存空间(以元素为单位)。 + - **`reserve()`**:预留向量的容量,可以减少未来的内存重新分配。例如,`vec4.reserve(20)` 预留至少20个元素的空间。 + - **`resize()`**:调整向量的大小。`vec4.resize(10, 999)` 将 `vec4` 的大小调整为10,如果原本大小不足,新增的元素将被初始化为 `999`。 + +9. **向量的排序和搜索** + - **`sort()`**:使用 `std::sort` 对 `vec6` 进行排序,结果为 `[1, 2, 5, 5, 6, 9]`。 + - **`binary_search()`**:在已排序的 `vec6` 中搜索元素 `5` 和 `3`,分别返回 `true` 和 `false`。 + - **`find()`**:使用 `std::find` 在 `vec6` 中查找元素 `6`,并输出其位置索引。 + +10. **使用算法与向量结合** + - **`accumulate()`**:计算 `vec6` 中所有元素的总和,结果为 `28`。 + - **`count()`**:统计 `vec6` 中元素 `5` 的数量,结果为 `2`。 + - **`for_each()`**:使用 `std::for_each` 和 Lambda 表达式将 `vec6` 中的每个元素乘以2,修改后的 `vec6` 为 `[2, 4, 10, 10, 12, 18]`。 + +11. **二维向量** + - **创建二维向量**:`matrix` 被初始化为一个3行4列的二维向量,所有元素初始化为 `0`。 + - **访问和修改**:通过下标访问并修改特定位置的元素,如 `matrix[0][0] = 1`,`matrix.at(1).at(2) = 5`,`matrix[2][3] = 9`。 + - **遍历二维向量**:使用嵌套的 `for` 循环遍历 `matrix`,输出其元素。 + +12. **向量的清空和检查** + - **`clear()`**:清空 `vec6` 的所有元素,使其大小变为0。 + - **`empty()`**:检查 `vec6` 是否为空,返回 `true` 表示为空。 + +13. **向量的交换** + - **`swap()`**:交换 `vec7` 和 `vec8` 的内容。交换前 `vec7 = [7, 8, 9]`,`vec8 = [10, 11]`;交换后 `vec7 = [10, 11]`,`vec8 = [7, 8, 9]`。 + +14. **向量与自定义类型** + - **自定义结构体**:定义了一个 `Person` 结构体,包含 `name` 和 `age`,并重载了输出运算符以便打印。 + - **创建和操作自定义类型向量**:创建 `people` 向量,添加 `Person` 对象,修改元素,并遍历输出。 + +15. **向量的复制和赋值** + - **拷贝构造**:使用拷贝构造函数创建 `vec9`,复制自 `vec2`。 + - **赋值运算符**:使用赋值运算符将 `vec4` 的内容赋值给 `vec10`。 + - **输出复制和赋值后的向量**:展示 `vec9` 和 `vec10` 的内容。 + +16. **向量的比较** + - **`==` 运算符**:比较 `vec9` 和 `vec10` 是否相等。 + - **`!=` 运算符**:比较 `vec2` 和 `vec3` 是否不相等。 + - **输出比较结果**:根据比较结果输出相应的信息。 + +17. **向量的嵌套与操作** + - **创建向量的向量**:`vecOfVec` 被初始化为一个包含两个子向量的二维向量。 + - **访问嵌套向量的元素**:遍历 `vecOfVec` 并输出每个子向量的元素。 + +18. **向量的迭代器高级用法** + - **`back_inserter` 和 `copy()`**:使用 `std::back_inserter` 将 `vec12` 的元素复制并追加到 `vec11`。 + - **反转向量**:使用 `std::reverse` 反转 `vec11` 的元素。 + +19. **向量的异常处理** + - **异常捕获**:尝试通过 `vec2.at(100)` 访问超出范围的元素,使用 `try-catch` 捕获并处理 `out_of_range` 异常。 + +20. **向量的内存管理** + - **`shrink_to_fit()`**:请求 `vec4` 缩减其容量以匹配当前的大小,减少内存占用。 + +### 运行示例 + +编译并运行上述代码,可以看到以下示例输出: + +``` +向量初始化示例: +vec1 (空向量) 的大小: 0 +vec2: 0 0 0 0 0 +vec3: 10 10 10 10 10 +vec4: 1 2 3 4 5 +vec5: apple banana cherry + +添加元素示例: +vec1: 100 200 +vec4 (插入99): 1 2 99 3 4 5 +vec5 (emplace_back 'date'): apple banana cherry date + +访问元素示例: +vec4[0]: 1 +vec4.at(2): 99 +vec4.front(): 1 +vec4.back(): 5 + +修改元素示例: +vec4 (修改第三个元素为150): 1 2 150 3 4 5 +vec5 (修改第二个元素为 'blueberry'): apple blueberry cherry date + +使用索引遍历 vec4: 1 2 150 3 4 5 +使用范围-based for 遍历 vec5: apple blueberry cherry date +使用迭代器遍历 vec3: 10 10 10 10 10 + +插入和删除元素示例: +vec2 (插入50并删除第二个元素): 0 50 0 0 +vec1 (pop_back): 100 + +使用反向迭代器遍历 vec4: 5 4 3 150 2 1 +使用常量迭代器遍历 vec5: apple blueberry cherry date + +向量大小和容量示例: +vec4 的大小: 6 +vec4 的容量: 6 +vec4 预留容量后的容量: 20 +vec4 resize(10, 999) 后: 1 2 150 3 4 5 999 999 999 999 + +向量排序和搜索示例: +vec6 排序后: 1 2 5 5 6 9 +binary_search 5: 找到 +binary_search 3: 未找到 +find 6 的位置索引: 4 + +使用算法与向量结合示例: +vec6 的总和: 28 +vec6 中5的数量: 2 +vec6 的元素乘以2: 2 4 10 10 12 18 + +二维向量示例: +1 0 0 0 +0 0 5 0 +0 0 0 9 + +向量清空和检查示例: +vec6 清空后大小: 0 +vec6 是否为空: 是空的 + +向量复制和赋值示例: +vec9 (拷贝自 vec2): 0 50 0 0 +vec10 (赋值自 vec4): 1 2 150 3 4 5 999 999 999 999 + +向量比较示例: +vec9 == vec10: 不相等 +vec2 != vec3: 相等 + +向量的嵌套与操作示例: +子向量 0: C++ Java +子向量 1: Python JavaScript + +使用 back_inserter 追加 vec12 到 vec11: 1 2 3 4 5 6 +反转后的 vec11: 6 5 4 3 2 1 + +异常处理示例: +尝试访问 vec2.at(100) 产生异常: vector::_M_range_check: __n (which is 100) >= this->size() (which is 4) + +向量内存管理示例: +vec4 的容量: 20 +vec4 使用 shrink_to_fit() 后的容量: 10 +``` + +### 总结 + +通过上述代码示例和详细注释,全面展示了C++ `std::vector` 库的各种功能和使用方法。掌握这些基本操作对于进行高效的动态数组处理和编程开发至关重要。希望本示例能够帮助您更好地理解和应用C++中的向量库。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/C/C 代码概述:检查特定条件的素数.md b/public/mengyanote/编程语言/C/C 代码概述:检查特定条件的素数.md new file mode 100644 index 0000000..6b7e116 --- /dev/null +++ b/public/mengyanote/编程语言/C/C 代码概述:检查特定条件的素数.md @@ -0,0 +1,81 @@ +# C 代码概述:检查特定条件的素数 + +## 功能描述 +该程序对给定的整数范围内的每个整数进行检查,计算一个特定的函数,并判断该函数的结果是否为素数。 + +## 主要组成部分 + +### 1. `is_prime` 函数 +- **输入**: 一个整数 `n` +- **输出**: 如果 `n` 是素数,返回 `1`,否则返回 `0`。 +- **逻辑**: + - 如果 `n` 小于或等于 1,返回 `0`。 + - 通过循环检查从 `2` 到 `√n` 的所有整数,判断 `n` 是否可被整除。 + +### 2. `main` 函数 +- **输入**: 从标准输入读取两个整数 `x` 和 `y`,直到输入为 `0 0`。 +- **逻辑**: + - 使用 `x` 和 `y` 定义的范围内进行迭代。 + - 计算 `f = i * i + i + 41`。 + - 调用 `is_prime` 函数检查 `f` 是否为素数: + - 如果发现任意 `f` 不是素数,输出 `"Sorry"` 并停止进一步检查。 + - 如果所有 `f` 都是素数,最终输出 `"OK"`。 + +## 使用示例 +- **输入**: + ``` + 1 5 + 0 0 + ``` +- **输出**: + ``` + Sorry + ``` + +## 注意事项 +- 如果输入为 `0 0`,程序会终止。 +- 当范围内某个 `f` 不是素数时,输出 `"Sorry"`,并不再继续检查后续数字。 + + + + + +```c +#include + +int is_prime(int n) { + if (n <= 1) return 0; + for (int i = 2; i * i <= n; i++) { + if (n % i == 0) return 0; + } + return 1; +} + +int main() { + int x, y; + + + while (scanf("%d %d", &x, &y) != EOF) { + if (x == 0 && y == 0) break; + + int all_prime = 1; + + for (int i = x; i <= y; i++) { + int f = i * i + i + 41; + if (!is_prime(f)) { + all_prime = 0; + printf("Sorry\n"); + break; + } + } + + if (all_prime) { + printf("OK\n"); + } + } + + return 0; +} + +``` + diff --git a/public/mengyanote/编程语言/C/C语言不设置临时变量交换x和y的值(方法).md b/public/mengyanote/编程语言/C/C语言不设置临时变量交换x和y的值(方法).md new file mode 100644 index 0000000..395da24 --- /dev/null +++ b/public/mengyanote/编程语言/C/C语言不设置临时变量交换x和y的值(方法).md @@ -0,0 +1,30 @@ +# C语言不设置临时变量交换x和y的值(方法) + +```c +#include +//异或 +int main() { + int x = 10, y = 20; + x = x ^ y; + y = x ^ y; + x = x ^ y; + printf("x的值为:%d,y的值为:%d\n", x, y); + return 0; +} + +``` + +```c +#include + +int main() { + int x = 10, y = 20; + x = x + y; + y = x - y; + x = x - y; + printf("x的值为:%d,y的值为:%d\n", x, y); + return 0; +} + +``` + diff --git a/public/mengyanote/编程语言/CSharp/mono和dotnet的区别.md b/public/mengyanote/编程语言/CSharp/mono和dotnet的区别.md new file mode 100644 index 0000000..b6ef0d0 --- /dev/null +++ b/public/mengyanote/编程语言/CSharp/mono和dotnet的区别.md @@ -0,0 +1,42 @@ +Mono 和 .NET(尤其是 .NET Core/5+)均为跨平台的 .NET 生态实现,但在背景、定位和特性上存在显著差异: + +1. 背景与归属 + +- .NET(官方) + +- 由微软主导开发,最初是 Windows 专属框架(.NET Framework)。 +- 2016 年推出开源跨平台的 .NET Core,后整合为 .NET 5+,成为统一的跨平台版本。 +- 官方支持 Windows、macOS、Linux 等主流系统,强调高性能和现代化开发。 +- Mono + +- 由第三方团队(Xamarin,后被微软收购)于 2000 年代初开发,是最早的跨平台 .NET 实现。 +- 目标是将 .NET 框架移植到非 Windows 系统(如 Linux、macOS、Android、iOS 等)。 +- 开源但实现进度滞后于官方版本,依赖社区维护。 + +2. 核心差异 + +特性 .NET(Core/5+) Mono +类库 官方提供 CoreFX(精简且持续更新) 部分兼容 .NET 类库,但存在功能缺失或延迟 +运行时 CoreCLR(优化性能,支持 JIT/AOT) Mono VM(需适配多平台,维护成本高) +兼容性 高度兼容 .NET Framework 应用 对旧版 .NET 支持较好,但新特性支持不足 +性能 针对现代工作负载优化,速度更快 性能稍弱,尤其在复杂场景(如 Web 服务) +生态支持 官方支持力度大,社区活跃,第三方库丰富 社区较小,依赖特定领域(如 Unity 早期) + +3. 典型应用场景 + +- .NET(Core/5+) + +- 现代 Web 应用、云服务、微服务、桌面应用(通过 MAUI)。 +- 适合追求高性能和长期稳定性的项目。 +- Mono + +- 遗留 .NET 应用跨平台迁移(如 Linux 服务器)。 +- 游戏开发(Unity 早期依赖 Mono,但现已转向 .NET)。 +- 对实时编译限制严格的场景(如 iOS 的 AOT 模式)。 + +4. 总结 + +- 选择 .NET:若需官方支持、高性能和最新技术(如云原生、微服务),优先选 .NET 5+。 +- 选择 Mono:若需兼容旧版 .NET 应用或特定平台(如早期 Unity 项目),可考虑 Mono。 + +两者最终目标一致(跨平台运行 .NET 应用),但 .NET 作为官方方案更具前瞻性,而 Mono 更偏向历史兼容性。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/Flutter/Flutter安卓构建注意事项.md b/public/mengyanote/编程语言/Flutter/Flutter安卓构建注意事项.md index 9a24784..9e0dabb 100644 --- a/public/mengyanote/编程语言/Flutter/Flutter安卓构建注意事项.md +++ b/public/mengyanote/编程语言/Flutter/Flutter安卓构建注意事项.md @@ -1,8 +1,7 @@ - ```powershell -#先使用这个构建 +#国内优先使用这个地址构建 $env:FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn"; $env:PUB_HOSTED_URL="https://pub.flutter-io.cn"; flutter build apk --release #再使用这个运行 diff --git a/public/mengyanote/编程语言/Flutter/Flutter常用命令.md b/public/mengyanote/编程语言/Flutter/Flutter常用命令.md index d435489..dbd0599 100644 --- a/public/mengyanote/编程语言/Flutter/Flutter常用命令.md +++ b/public/mengyanote/编程语言/Flutter/Flutter常用命令.md @@ -1,5 +1,3 @@ -好的 👍 -我帮你把 **Flutter 常用命令**整理一下,方便开发时快速查阅。可以分几类: --- diff --git a/public/mengyanote/编程语言/Flutter/Flutter构建平台产物位置.md b/public/mengyanote/编程语言/Flutter/Flutter构建平台产物位置.md index ccd633e..fadd662 100644 --- a/public/mengyanote/编程语言/Flutter/Flutter构建平台产物位置.md +++ b/public/mengyanote/编程语言/Flutter/Flutter构建平台产物位置.md @@ -1,67 +1,73 @@ -在使用 Flutter 构建应用时,不同平台的输出文件会存放在项目目录的特定位置,具体路径会因构建命令和平台而有所不同。以下是各平台构建产物的默认存放位置及相关说明: ### 一、通用说明 Flutter 项目的构建产物默认存放在项目根目录的 build 文件夹下,该文件夹会根据目标平台自动创建子目录,存放对应平台的编译文件、安装包等。 -### 二、各平台构建产物位置 +### 二、各个平台构建产物位置 #### 1. Android 平台 -- **构建命令**:flutter build apk(默认 release 模式)、flutter build appbundle(AAB 格式) - -- **产物位置**: - -- APK 文件:项目根目录/build/app/outputs/flutter-apk/ +**构建命令**: +flutter build apk(默认 release 模式)、flutter build appbundle(AAB 格式) +**产物位置**: +APK 文件: +项目根目录/build/app/outputs/flutter-apk/ 文件名通常为 app-release.apk(release 模式)或 app-debug.apk(debug 模式)。 -- AAB 文件(Android App Bundle):项目根目录/build/app/outputs/bundle/release/app-release.aab +AAB 文件(Android App Bundle): +项目根目录/build/app/outputs/bundle/release/app-release.aab #### 2. iOS 平台 -- **构建命令**:flutter build ios(release 模式)、flutter build ios --debug(debug 模式) +**构建命令**: +flutter build ios(release 模式)、flutter build ios --debug(debug 模式) -- **产物位置**: - -- 编译后的应用文件(.app 格式):项目根目录/build/ios/iphoneos/Runner.app(真机运行)或 build/ios/iphonesimulator/Runner.app(模拟器)。 - -- IPA 安装包(需通过 Xcode 导出): +**产物位置**: +编译后的应用文件(.app 格式): +项目根目录/build/ios/iphoneos/Runner.app(真机运行)或 build/ios/iphonesimulator/Runner.app(模拟器)。 +IPA 安装包(需通过 Xcode 导出): 若使用 flutter build ipa 命令,产物会存放在 项目根目录/build/ios/ipa/,文件名为 Runner.ipa。 #### 3. 桌面平台(Windows/macOS/Linux) 需先通过 flutter config --enable-[windows/macos/linux]-desktop 开启对应平台支持。 -- **Windows**: +***Windows**:* -- 构建命令:flutter build windows +**构建命令:** +flutter build windows -- 产物位置:项目根目录/build/windows/runner/Release/(release 模式),包含可执行文件 Runner.exe 及相关依赖库。 +**产物位置:** +项目根目录/build/windows/runner/Release/(release 模式),包含可执行文件 Runner.exe 及相关依赖库。 -- **macOS**: +***macOS:*** -- 构建命令:flutter build macos +**构建命令:** +flutter build macos -- 产物位置:项目根目录/build/macos/Build/Products/Release/Runner.app(release 模式),这是一个 macOS 应用包。 +**产物位置:** +项目根目录/build/macos/Build/Products/Release/Runner.app(release 模式),这是一个 macOS 应用包。 -- **Linux**: +***Linux**:* -- 构建命令:flutter build linux +**构建命令:** +flutter build linux -- 产物位置:项目根目录/build/linux/x64/release/bundle/(64 位系统),包含可执行文件 runner 及依赖文件。 +**产物位置:** +项目根目录/build/linux/x64/release/bundle/(64 位系统),包含可执行文件 runner 及依赖文件。 #### 4. Web 平台 -- **构建命令**:flutter build web(默认 release 模式) +**构建命令**: +flutter build web(默认 release 模式) -- **产物位置**:项目根目录/build/web/,包含 HTML、CSS、JavaScript 等静态文件,可直接部署到 Web 服务器(如 Nginx、Apache 等)。 +**产物位置**: +项目根目录/build/web/,包含 HTML、CSS、JavaScript 等静态文件,可直接部署到 Web 服务器(如 Nginx、Apache 等)。 ### 三、注意事项 - **debug 与 release 模式**:debug 模式的产物通常用于开发调试,体积较大且包含调试信息;release 模式产物经过优化,适合发布,默认存放在对应平台的 release 子目录中。 - **自定义输出路径**:部分命令支持通过参数指定输出路径,例如 flutter build apk --output=./my_app.apk 可将 APK 输出到根目录并命名为 my_app.apk。 - -通过以上路径,你可以找到 Flutter 为各平台构建的应用文件,便于测试或发布到应用商店。 \ No newline at end of file diff --git a/public/mengyanote/编程语言/Java/Java基础-导入java文件.md b/public/mengyanote/编程语言/Java/Java基础-导入java文件.md index f7923bf..6bd0030 100644 --- a/public/mengyanote/编程语言/Java/Java基础-导入java文件.md +++ b/public/mengyanote/编程语言/Java/Java基础-导入java文件.md @@ -1,7 +1,5 @@ ---- - -## 🔹 情况 1:同一个包里的多个 `.java` 文件 +## 🔹 情况 1:同一个包里的多个.java文件 如果两个类在同一个包(或者没写 `package`,都在默认包), 只要把它们放在同一个目录下,直接编译就能互相使用。 @@ -15,7 +13,7 @@ HelloWorld.java Utils.java ``` -`HelloWorld.java`: +**HelloWorld.java** ```java public class HelloWorld { @@ -25,7 +23,7 @@ public class HelloWorld { } ``` -`Utils.java`: +**Utils.java** ```java public class Utils { @@ -35,14 +33,14 @@ public class Utils { } ``` -编译运行: +**编译运行:** ```bash javac HelloWorld.java Utils.java java HelloWorld ``` -输出: +**输出:** ``` Hello from Utils! @@ -52,9 +50,9 @@ Hello from Utils! ## 🔹 情况 2:不同包的类 -如果你要用别的包里的类,需要用 `import`。 +如果你要用别的包里的类,需要用 import -目录结构: +**目录结构:** ``` src/ @@ -64,7 +62,7 @@ src/ └─ Utils.java ``` -`util/Utils.java`: +**util/Utils.java** ```java package util; @@ -76,7 +74,7 @@ public class Utils { } ``` -`app/HelloWorld.java`: +**app/HelloWorld.java** ```java package app; @@ -90,13 +88,13 @@ public class HelloWorld { } ``` -编译: +**编译:** ```bash javac src/util/Utils.java src/app/HelloWorld.java -d out ``` -运行: +**运行:** ```bash java -cp out app.HelloWorld diff --git a/public/mengyanote/编程语言/Python/Kivy/kivy编译安卓APK.md b/public/mengyanote/编程语言/Python/Kivy/kivy编译安卓APK.md index 48419ea..4366092 100644 --- a/public/mengyanote/编程语言/Python/Kivy/kivy编译安卓APK.md +++ b/public/mengyanote/编程语言/Python/Kivy/kivy编译安卓APK.md @@ -70,9 +70,6 @@ if __name__ == "__main__": ``` -```ini - -``` diff --git a/public/mengyanote/编程语言/Python/Python国内pip加速镜像.md b/public/mengyanote/编程语言/Python/Python国内pip加速镜像.md index a0ce83f..e9794cb 100644 --- a/public/mengyanote/编程语言/Python/Python国内pip加速镜像.md +++ b/public/mengyanote/编程语言/Python/Python国内pip加速镜像.md @@ -6,22 +6,15 @@ 以下是一些稳定且速度优异的国内 PyPI 镜像源: - **清华大学** - `https://pypi.tuna.tsinghua.edu.cn/simple` ([CSDN博客](https://blog.csdn.net/weixin_39334709/article/details/105265951?utm_source=chatgpt.com "pip install 加速(修改为国内源) 原创")) - + `https://pypi.tuna.tsinghua.edu.cn/simple` - **阿里云** - `https://mirrors.aliyun.com/pypi/simple/` ([CSDN博客](https://blog.csdn.net/zwq_zwq_zwq111/article/details/139562615?utm_source=chatgpt.com "python-pip配置镜像源加速下载Python包安装:快速配置pip源")) - + `https://mirrors.aliyun.com/pypi/simple/` - **中国科技大学(USTC)** - `https://pypi.mirrors.ustc.edu.cn/simple/` ([CSDN博客](https://blog.csdn.net/zwq_zwq_zwq111/article/details/139562615?utm_source=chatgpt.com "python-pip配置镜像源加速下载Python包安装:快速配置pip源")) - + `https://pypi.mirrors.ustc.edu.cn/simple/` - **网易** - `https://mirrors.163.com/pypi/simple/` ([CSDN博客](https://blog.csdn.net/qq_44924694/article/details/134017564?utm_source=chatgpt.com "Python安装库加速之pip国内镜像源原创")) - + `https://mirrors.163.com/pypi/simple/` - **豆瓣** - `http://pypi.douban.com/simple/`(推荐使用 HTTPS 若可用)([CSDN博客](https://blog.csdn.net/zwq_zwq_zwq111/article/details/139562615?utm_source=chatgpt.com "python-pip配置镜像源加速下载Python包安装:快速配置pip源")) - -- **华为云、腾讯云**等也是可选镜像,但常用推荐如上即可 ([CSDN博客](https://blog.csdn.net/qq_44924694/article/details/134017564?utm_source=chatgpt.com "Python安装库加速之pip国内镜像源原创")) - + `http://pypi.douban.com/simple/`(推荐使用 HTTPS 若可用) --- @@ -39,7 +32,6 @@ pip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install 包名 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com ``` -([博客园](https://www.cnblogs.com/minuhy/p/18424608?utm_source=chatgpt.com "【Python】pip安装加速:使用国内镜像源")) --- @@ -63,11 +55,11 @@ index-url = https://pypi.tuna.tsinghua.edu.cn/simple trusted-host = pypi.tuna.tsinghua.edu.cn ``` -- `timeout`:设置最长等待时间,例如 **120 秒**,避免连接中断 ([CSDN博客](https://blog.csdn.net/weixin_39334709/article/details/105265951?utm_source=chatgpt.com "pip install 加速(修改为国内源) 原创")) +- `timeout`:设置最长等待时间,例如 **120 秒**,避免连接中断 - `index-url`:指定清华镜像为默认源 -- `trusted-host`:将镜像主机设为可信,避免 HTTPS 以外的警告 ([CSDN博客](https://blog.csdn.net/weixin_39334709/article/details/105265951?utm_source=chatgpt.com "pip install 加速(修改为国内源) 原创")) +- `trusted-host`:将镜像主机设为可信,避免 HTTPS 以外的警告 记住,pip 配置的优先级如下(高到低): @@ -76,7 +68,7 @@ trusted-host = pypi.tuna.tsinghua.edu.cn 2. 当前用户目录中的配置 -3. 全局配置(系统范围)([CSDN博客](https://blog.csdn.net/weixin_39334709/article/details/105265951?utm_source=chatgpt.com "pip install 加速(修改为国内源) 原创")) +3. 全局配置(系统范围) --- @@ -89,7 +81,7 @@ trusted-host = pypi.tuna.tsinghua.edu.cn pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ ``` -随后你可以用 `pip config list` 来验证是否设置成功 ([CSDN博客](https://blog.csdn.net/zwq_zwq_zwq111/article/details/139562615?utm_source=chatgpt.com "python-pip配置镜像源加速下载Python包安装:快速配置pip源"))。 +随后你可以用 `pip config list` 来验证是否设置成功 若想恢复到默认的官方 PyPI 源,可使用: @@ -97,7 +89,6 @@ pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ pip config unset global.index-url ``` -([CSDN博客](https://blog.csdn.net/zwq_zwq_zwq111/article/details/139562615?utm_source=chatgpt.com "python-pip配置镜像源加速下载Python包安装:快速配置pip源")) --- diff --git a/public/mengyanote/计算机科普/clash机场三种代理模式科普.md b/public/mengyanote/计算机科普/clash机场三种代理模式科普.md index 198e6c8..a38dffc 100644 --- a/public/mengyanote/计算机科普/clash机场三种代理模式科普.md +++ b/public/mengyanote/计算机科普/clash机场三种代理模式科普.md @@ -4,74 +4,43 @@ ### 1️⃣ `rule`(规则模式) - **中文理解**:按规则走 - - **工作方式**: - - 根据配置文件里的 **规则列表(rules)** 来判断请求走哪条线路。 - - 每条规则通常指定域名、IP、地理位置或者关键词对应的代理: - - 例如 `DOMAIN-SUFFIX,google.com,Proxy` → 访问 google.com 时走代理 - - `DOMAIN-SUFFIX,example.com,DIRECT` → 访问 example.com 时直连 - **优点**: - - 灵活,可针对不同网站走不同线路。 - - 节省带宽和延迟。 - -- **缺点**: - +- **缺点** - 规则多时,解析略慢一些。 - - --- ### 2️⃣ `global`(全局代理模式) - **中文理解**:所有流量都走代理 - - **工作方式**: - - 不看规则,所有网络请求都被发送到指定的 **代理服务器**。 - - **优点**: - - 配置简单,不需要维护规则。 - - 对某些被墙网站或应用更友好。 - - **缺点**: - - 所有流量都经过代理,可能降低速度。 - - 国内网站也会走代理,浪费带宽。 - - --- ### 3️⃣ `direct`(全局直连模式) - **中文理解**:所有流量直连,不走代理 - - **工作方式**: - - 忽略所有规则,直接访问目标网站。 - - **优点**: - - 速度快,延迟低。 - - 避免代理服务器的限制。 - - **缺点**: - - 无法访问被墙网站。 - - 所有请求都走直连,规则无效。 - - --- ### 🔹 总结对比 diff --git a/public/mengyanote/计算机科普/sim卡作用及原理.md b/public/mengyanote/计算机科普/sim卡作用及原理.md index 3bc3d51..8cfb0b9 100644 --- a/public/mengyanote/计算机科普/sim卡作用及原理.md +++ b/public/mengyanote/计算机科普/sim卡作用及原理.md @@ -1,4 +1,4 @@ -# 什么是 SIM 卡(从专业角度解释) +# 什么是 SIM 卡 **SIM** 是 _Subscriber Identity Module_ 的缩写(中文常译为“用户身份模块”)。严格来说,现代移动设备里常见的有两类相关的东西:**物理 SIM / 晶片卡(UICC)** 和 **嵌入式 SIM(eSIM / eUICC)**。无论形式如何,其核心作用是:**为移动用户提供唯一身份、储存认证凭证与少量用户数据,并参与网络认证与安全通信**。 @@ -76,8 +76,3 @@ ## 小结(一句话) SIM(或更一般的 UICC / eUICC)是一个小型但受保护的智能卡 / 安全芯片,**存储用户身份与加密凭证,通过挑战—应答和密钥派生机制对用户进行网络认证并保护移动通信的安全**,同时支持少量用户数据与运营商增值服务(如 SIM Toolkit、OTA、eSIM 配置等)。 - -如果你想,我可以进一步: - -- 画一张简单的认证流程图(步骤图); -- 或者针对 **eSIM 远程配置**、**SIM 文件系统结构(MF/DF/EF)**、或**具体的 AKA 算法(Milenage)** 做更深的技术说明。要哪一种直接告诉我。 \ No newline at end of file diff --git a/public/mengyanote/计算机科普/多模态大模型识别图片,视频,音频原理.md b/public/mengyanote/计算机科普/多模态大模型识别图片,视频,音频原理.md new file mode 100644 index 0000000..7d3e1d6 --- /dev/null +++ b/public/mengyanote/计算机科普/多模态大模型识别图片,视频,音频原理.md @@ -0,0 +1,140 @@ + +## 核心思想 + +- **目标**:把非文本模态(图片、视频、音频等二进制数据)转换成模型能理解的“通用语言”(数值向量/特征向量)。 + +- **统一空间**:在统一的语义向量空间中实现多模态信息的对齐、理解和生成。 + + +--- + +## 核心步骤 + +1. **预处理与编码(Encoding)** + + - 使用专门的编码器(图像、视频、音频编码器),将原始数据转为特征向量。 + +2. **对齐与融合(Alignment & Fusion)** + + - 通过投影层将不同模态特征映射到同一向量空间,并进行融合。 + +3. **理解与推理(Understanding & Reasoning)** + + - LLM基于融合特征进行语义理解与逻辑推理。 + +4. **解码与生成(Decoding & Generation)** + + - 将LLM的内部表示解码为文本输出,完成对话或任务。 + + +--- + +## 工作流程示意图 + +```mermaid +flowchart TD +A[输入
非文本模态] --> B[专用编码器
(如ViT, CLIP-ViT)] +B --> C[特征向量
“通用语言”] +C --> D[与LLM交互
(前缀/软提示)] + +E[输入
文本指令] --> F[文本编码器
(如CLIP-Text, BPE)] +F --> G[文本向量] + +D & G --> H[大语言模型核心
(Transformer)] +H --> I[理解与推理] +I --> J[文本解码器] +J --> K[输出
文本响应] +``` + +--- + +## 模态细分说明 + +### 1. 图像(Image) + +- **编码器**:CNN(ResNet,早期)或 ViT(主流)。 + +- **流程**: + + 1. 图像分块 → ViT编码 → 图像特征向量。 + + 2. 投影层对齐到文本空间。 + + 3. 特征作为“视觉提示”与文本一起输入LLM。 + + 4. LLM生成描述或问答结果。 + + +--- + +### 2. 视频(Video) + +- **特点**:图像序列 + 时间维度 + 可选音频。 + +- **编码器**: + + - 图像帧 → ViT。 + + - 时序关系 → 3D-CNN / 时序Transformer。 + + - 音频 → 独立音频编码器。 + +- **流程**: + + 1. 视频帧采样。 + + 2. 逐帧编码 + 时序建模。 + + 3. 融合视觉+音频特征,对齐到文本空间。 + + 4. LLM理解动作与剧情,输出结果。 + + +--- + +### 3. 音频/音乐(Audio) + +- **语音识别路径**: + + - 使用ASR模型(如Whisper)转录为文本 → 输入LLM。 + +- **非语音音频路径**: + + - 音频波形 → 频谱图(Spectrogram)。 + + - 频谱图 → ViT 等视觉编码器 → 特征向量。 + + - 投影对齐后,与文本一同输入LLM。 + + +--- + +## 关键技术 + +1. **CLIP模型**: + + - 对比学习,建立图像-文本统一语义空间。 + +2. **投影层(Projection Layer)**: + + - 将模态特征翻译到LLM空间。 + +3. **软提示(Soft Prompt)**: + + - 非文本特征向量作为额外提示,辅助LLM理解与生成。 + + +--- + +## 类比理解 + +- **编码器**:不同模态的“翻译官”。 + +- **投影层**:统一标准的“校对官”。 + +- **LLM**:只懂“世界语”的“博学大脑”。 + +- **解码器**:把“世界语”翻译回自然语言。 + + +--- diff --git a/public/mengyanote/计算机科普/多模态大模型识别图片,视频,音频原理.md b/public/mengyanote/计算机科普/多模态大模型识别图片,视频,音频原理.md deleted file mode 100644 index 0bad093..0000000 --- a/public/mengyanote/计算机科普/多模态大模型识别图片,视频,音频原理.md +++ /dev/null @@ -1,102 +0,0 @@ -目前的多模态大语言模型(MLLM,如GPT-4V, Gemini, LLaVA等)识别图片、视频、音乐等二进制文件的过程,可以概括为一个 “翻译-理解-对话” 的流程。 - -其核心思想是:将非文本的二进制数据(图片、视频、音频)转换成一种模型能够理解的“通用语言”(即数值向量/特征向量),然后在这个统一的向量空间里进行理解和生成。 - -下面我们分步骤详细解释这个过程: - -核心步骤概述 - -1. 预处理与编码(Encoding): 使用专门的编码器(Encoder)将二进制文件转换为数字特征向量。 -2. 对齐与融合(Alignment & Fusion): 将这些特征向量与文本的向量空间进行对齐,并融合成一个统一的表示。 -3. 理解与推理(Understanding & Reasoning): 大语言模型(LLM)核心基于融合后的特征进行理解和推理。 -4. 解码与生成(Decoding & Generation): LLM核心生成文本响应,完成对话或任务。 - -为了让您更直观地理解这个复杂流程,我绘制了以下示意图,它展示了多模态处理的核心“翻译-理解”管道: - -```mermaid -flowchart TD -A[输入
非文本模态] --> B[专用编码器
(如ViT, CLIP-ViT)] -B --> C[特征向量
(数据的“通用语言”)] -C --> D[与大语言模型交互
(作为前缀/软提示)] - -E[输入
文本指令] --> F[文本编码器
(如CLIP-Text, BPE)] -F --> G[文本令牌向量] - -D & G --> H[大语言模型核心
(如Transformer)] - -H --> I[理解与推理
在统一语义空间完成] - -I --> J[文本解码器] -J --> K[输出
文本响应] -``` - ---- - -分模态详细说明 - -尽管流程相似,但不同模态的“编码器”各有特点。 - -1. 图像(Image)识别 - -这是最成熟的多模态应用。 - -· 编码器(Encoder): - · 卷积神经网络(CNN):早期模型使用,如ResNet,能有效提取图像的局部特征(如边缘、纹理)。 - · 视觉Transformer(ViT):当前主流方法。将图像切割成一个个图像块(Patches),然后像处理文本词汇一样处理这些图像块,通过自注意力机制捕捉全局关系。CLIP模型的图像编码器(通常是ViT)是许多MLLM的基石。 -· 具体流程: - 1. 分块与编码:将输入图像分割成固定大小的图块,通过视觉编码器(如ViT)转换成一系列图像特征向量。每个向量代表了图像的一部分信息。 - 2. 投影对齐:将这些图像特征向量通过一个投影层(Projection Layer) 映射到文本向量所在的高维空间。这样,”猫的图片特征“和文本“猫”这个词在向量空间中的位置就会很接近。 - 3. 送入LLM核心:将这些对齐后的图像向量与文本指令的向量拼接在一起,作为一个整体的“提示(Prompt)”输入给大语言模型(LLM)。 - 4. 理解生成:LLM像处理文本序列一样,同时“看”着这些图像特征和文本指令,理解其间的关联,并生成对应的文本回复(例如描述图像、回答问题等)。 - -5. 视频(Video)识别 - -视频可以看作是带时间序列的图像(帧)和音频的组合。 - -· 编码器(Encoder): - · 视觉部分:使用图像编码器(如ViT)对视频关键帧进行采样编码。 - · 时序部分:为了理解动作和剧情变化,需要引入能捕捉时间信息的模型,如: - · 3D-CNN:直接在时空维度上处理视频帧。 - · 时序Transformer:在编码后的帧特征之上,增加一层注意力机制来建模帧与帧之间的关系。 - · 音频部分:有独立的音频编码器(见下文)。 -· 具体流程: - 1. 帧采样:从视频中均匀或策略性地抽取若干帧(如每秒1帧或关键帧)。 - 2. 提取视觉特征:用图像编码器为每一帧提取特征向量。 - 3. 建模时序关系:使用时序模型(如时序Transformer)处理这些帧特征序列,得到一个既能表达每帧内容又能表达动作变化的视频整体特征。 - 4. (可选)融合音频特征:同时处理音频轨道,将音频特征与视频视觉特征融合。 - 5. 对齐与生成:之后的步骤与图像处理一致:将融合后的特征投影到文本空间,与问题文本拼接,送入LLM生成回答。 - -6. 音乐/音频(Audio)识别 - -音频处理主要有两个方向:语音识别和音频事件识别。 - -· 编码器(Encoder): - · 语音识别(ASR):通常先使用Whisper等专用语音识别模型,直接将语音转写成文本,然后将文本送入LLM。这是一种间接但非常高效的方式。 - · 通用音频识别:对于音乐、音效、环境声等,需要直接处理音频信号: - · 首先将时域上的音频波形(Waveform)通过傅里叶变换等转换成频谱图(Spectrogram),这是一种图像的视觉表示。 - · 然后使用类似图像编码器(如ViT) 来处理频谱图,将其编码为特征向量。 -· 具体流程: - 1. 路径选择:如果是语音,优先用ASR模型转文本;如果是非语音音频,则转为频谱图。 - 2. 特征提取: - · 语音路径:输出直接是文本Tokens。 - · 音频路径:输出是频谱图特征向量。 - 3. 投影与融合:音频路径的特征向量被投影到文本空间,与问题文本拼接。 - 4. 理解与生成:LLM接收处理后的信息。例如,你问“这是什么音乐?”,LLM结合音频特征和其知识库,可能回答“这是贝多芬的《致爱丽丝》”。 - ---- - -关键技术总结 - -1. CLIP模型(OpenAI):革命性的基石。它通过在海量“图像-文本”对上对比学习,学会了将图像和文本映射到同一个向量空间,使得图像和文本的含义可以相互衡量。这为后续所有MLLM的视觉-语言对齐提供了基础。 -2. 投影层(Projection Layer):一个关键的“翻译官”。它是一个小型神经网络,负责将编码器提取的视觉(或音频)特征向量,完美地“翻译”并对齐到LLM所理解的文本向量空间。 -3. 软提示(Soft Prompt):图像特征向量在被送入LLM时,可以被看作是一种“视觉提示”或“软提示”,它们和文本提示(Hard Prompt)共同引导LLM生成内容。 - -简单的比喻 - -你可以把整个过程想象成: - -· 编码器就像一群“翻译官”:图像翻译官、视频翻译官、音乐翻译官。他们各自精通一种语言,负责把图片、视频、音乐“翻译”成一种统一的“世界语”(特征向量)。 -· 投影层就像一位“校对官”,确保各位翻译官输出的“世界语”口音和语法都标准统一,确保大家都能听懂。 -· 大语言模型(LLM) 就像一位“博学的大脑”,它只懂这种“世界语”。它接收来自翻译官和校对官的信息,结合自己的海量知识,然后用“世界语”进行思考和回答。 -· 最后的输出层再把“大脑”的“世界语”思考结果翻译回用户能理解的自然语言。 - diff --git a/public/mengyanote/计算机科普/CVM术语科普.md b/public/mengyanote/计算机科普/术语科普-CVM.md similarity index 100% rename from public/mengyanote/计算机科普/CVM术语科普.md rename to public/mengyanote/计算机科普/术语科普-CVM.md diff --git a/public/mengyanote/计算机科普/IT行业的A端B端C端术语解释.md b/public/mengyanote/计算机科普/术语科普-IT行业的A端B端C端.md similarity index 100% rename from public/mengyanote/计算机科普/IT行业的A端B端C端术语解释.md rename to public/mengyanote/计算机科普/术语科普-IT行业的A端B端C端.md diff --git a/public/mengyanote/计算机科普/MCU术语科普.md b/public/mengyanote/计算机科普/术语科普-MCU.md similarity index 100% rename from public/mengyanote/计算机科普/MCU术语科普.md rename to public/mengyanote/计算机科普/术语科普-MCU.md diff --git a/public/mengyanote/计算机科普/pwn术语科普.md b/public/mengyanote/计算机科普/术语科普-pwn.md similarity index 100% rename from public/mengyanote/计算机科普/pwn术语科普.md rename to public/mengyanote/计算机科普/术语科普-pwn.md diff --git a/public/mengyanote/计算机科普/科普-Nagle 算法.md b/public/mengyanote/计算机科普/科普-Nagle 算法.md index d818684..9c84267 100644 --- a/public/mengyanote/计算机科普/科普-Nagle 算法.md +++ b/public/mengyanote/计算机科普/科普-Nagle 算法.md @@ -1,4 +1,5 @@ -***Nagle算法是TCP协议中用于优化网络传输效率的一种流量控制算法,其核心目的是减少网络中“小数据包”的数量,从而降低网络拥塞和协议开销。*** +> [!NOTE] +> ***Nagle算法是TCP协议中用于优化网络传输效率的一种流量控制算法,其核心目的是减少网络中“小数据包”的数量,从而降低网络拥塞和协议开销。*** ### **核心问题:小数据包的弊端** @@ -32,4 +33,7 @@ Nagle算法可能与TCP的“延迟确认(Delayed ACK)”机制产生叠加 在需要低延迟的场景(如游戏、实时通信),可通过设置TCP选项`TCP_NODELAY`(大多数编程语言/系统都支持)禁用Nagle算法,强制TCP立即发送数据,牺牲部分带宽效率换取实时性。 -总结:Nagle算法是TCP为平衡效率与开销设计的优化机制,通过合并小数据包减少网络负担,但需根据应用场景权衡实时性需求决定是否启用。 \ No newline at end of file +### **总结:** +Nagle算法是TCP为平衡效率与开销设计的优化机制,通过合并小数据包减少网络负担,但需根据应用场景权衡实时性需求决定是否启用。 + +[^1]: diff --git a/public/mengyanote/面试八股/Nacos功能与应用场景详解.md b/public/mengyanote/面试八股/Nacos功能与应用场景详解.md new file mode 100644 index 0000000..1be51ce --- /dev/null +++ b/public/mengyanote/面试八股/Nacos功能与应用场景详解.md @@ -0,0 +1,61 @@ +Nacos 是阿里巴巴开源的 **动态服务发现、配置管理与服务治理平台**,旨在简化微服务架构的构建、交付和管理。 + +--- + +## 🚀 核心功能 + +| 功能 | 主要作用 | +|------|----------| +| 🎯 **服务注册与发现** | 服务提供者注册自身信息,服务消费者动态发现和调用其他服务。 | +| ⚙️ **动态配置管理** | 集中管理所有环境的配置,支持实时推送变更,无需重启应用。 | +| 🔍 **服务健康监测** | 定期检查服务实例健康状况,自动隔离不健康实例,保障系统稳定性。 | +| 🚦 **动态DNS与流量管理** | 支持权重路由,助力灰度发布、蓝绿部署等高级流量管理策略。 | + +--- + +## 🎯 服务发现与健康检查 + +- **服务注册**:实例启动时向 Nacos 注册自身元数据(服务名、IP、端口等)。 +- **服务发现**:消费者通过服务名查询健康实例,实现通信而无需关心具体地址。 +- **健康检查**:支持客户端上报与服务端主动探测,自动剔除不健康实例,保障可靠性。 + +--- + +## ⚙️ 动态配置管理 + +- **集中化管理**:统一存储数据库连接、开关、限流阈值等配置。 +- **动态刷新**:配置变更实时推送,应用可在运行中直接生效(热更新)。 +- **版本控制与回滚**:支持历史版本,一键回滚,降低变更风险。 + +--- + +## 🚦 动态DNS与服务治理 + +- **动态DNS服务**:支持权重路由、流量控制和简易内网 DNS 解析。 +- **服务与元数据管理**:统一管理服务描述、依赖关系、健康状态、流量及安全策略。 + +--- + +## 💡 主要应用场景 + +- **数据库配置集中化管理**:提升安全性与合规性。 +- **限流与降级开关**:结合 Sentinel 等组件实现运行时动态调整。 +- **多环境与多数据中心**:基于 Namespace 与 Group 实现隔离与灵活部署。 + +--- + +## 📊 与其他组件对比 + +- ✅ **功能更全面**:Nacos = 服务发现 + 配置管理;Eureka 仅支持服务发现。 +- ✅ **健康检查机制更强**:优于 Eureka 心跳检测。 +- ✅ **社区与生态活跃**:Eureka 已停止维护,而 Nacos 持续迭代。 +- ✅ **多数据中心支持优越**:原生支持多数据中心部署。 + +--- + +## 📚 总结 + +Nacos 集 **服务发现、配置管理、服务治理** 于一体, +极大简化了微服务架构复杂性,提升了 **开发效率**、**可维护性** 和 **系统弹性**。 + +--- \ No newline at end of file diff --git a/public/mengyanote/首页.md b/public/mengyanote/首页.md new file mode 100644 index 0000000..dec0546 --- /dev/null +++ b/public/mengyanote/首页.md @@ -0,0 +1,10 @@ + +## 引言 +你好,陌生人!这是我的学习笔记,用来展示我的一些学习路径 +欢迎和我一起讨论和交流学习! + +## 联系方式 +QQ:3205788256 +邮箱:3205788256@qq.com +个人主页:shumengya.top +作品集:work.shumengya.top \ No newline at end of file diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/scripts/generateData.js b/scripts/generateData.js index 7f938d7..904ffb6 100644 --- a/scripts/generateData.js +++ b/scripts/generateData.js @@ -8,6 +8,8 @@ const __dirname = path.dirname(__filename); // 路径配置 const NOTES_SOURCE_PATH = path.join(__dirname, '../public/mengyanote'); const OUTPUT_PATH = path.join(__dirname, '../src/data'); +const PUBLIC_OUTPUT_PATH = path.join(__dirname, '../public/data'); +const IGNORE_FILE_PATH = path.join(NOTES_SOURCE_PATH, 'ignore.json'); // 文件节点类型 const NODE_TYPES = { @@ -15,15 +17,31 @@ const NODE_TYPES = { FILE: 'file' }; +// 读取忽略配置 +function loadIgnoreConfig() { + try { + if (fs.existsSync(IGNORE_FILE_PATH)) { + const ignoreContent = fs.readFileSync(IGNORE_FILE_PATH, 'utf-8'); + const ignoreConfig = JSON.parse(ignoreContent); + console.log('✓ 已加载忽略配置:', ignoreConfig.ignore); + return ignoreConfig.ignore || []; + } + } catch (error) { + console.warn('⚠️ 读取ignore.json失败,使用默认配置:', error.message); + } + return []; +} + // 检查是否为Markdown文件 function isMarkdownFile(filename) { return filename.toLowerCase().endsWith('.md'); } // 检查是否应该忽略的文件/文件夹 -function shouldIgnore(name) { - const ignoredItems = ['.obsidian', '.trash', '.git', 'node_modules']; - return ignoredItems.includes(name) || name.startsWith('.'); +function shouldIgnore(name, customIgnoreList = []) { + const defaultIgnoredItems = ['.obsidian', '.trash', '.git', 'node_modules']; + const allIgnoredItems = [...defaultIgnoredItems, ...customIgnoreList]; + return allIgnoredItems.includes(name) || name.startsWith('.'); } // 创建文件树节点 @@ -39,13 +57,13 @@ function createNode(name, type, path, children = []) { } // 递归读取目录结构 -function readDirectoryTree(dirPath, basePath = NOTES_SOURCE_PATH) { +function readDirectoryTree(dirPath, basePath = NOTES_SOURCE_PATH, ignoreList = []) { try { const items = fs.readdirSync(dirPath, { withFileTypes: true }); const children = []; for (const item of items) { - if (shouldIgnore(item.name)) { + if (shouldIgnore(item.name, ignoreList)) { continue; } @@ -53,7 +71,7 @@ function readDirectoryTree(dirPath, basePath = NOTES_SOURCE_PATH) { const relativePath = path.relative(basePath, itemPath).replace(/\\/g, '/'); if (item.isDirectory()) { - const subChildren = readDirectoryTree(itemPath, basePath); + const subChildren = readDirectoryTree(itemPath, basePath, ignoreList); if (subChildren.length > 0) { children.push(createNode(item.name, NODE_TYPES.FOLDER, relativePath, subChildren)); } @@ -78,12 +96,12 @@ function readDirectoryTree(dirPath, basePath = NOTES_SOURCE_PATH) { } // 读取所有Markdown文件内容 -function readAllMarkdownFiles(dirPath, basePath = NOTES_SOURCE_PATH, fileContents = {}) { +function readAllMarkdownFiles(dirPath, basePath = NOTES_SOURCE_PATH, fileContents = {}, ignoreList = []) { try { const items = fs.readdirSync(dirPath, { withFileTypes: true }); for (const item of items) { - if (shouldIgnore(item.name)) { + if (shouldIgnore(item.name, ignoreList)) { continue; } @@ -91,7 +109,7 @@ function readAllMarkdownFiles(dirPath, basePath = NOTES_SOURCE_PATH, fileContent const relativePath = path.relative(basePath, itemPath).replace(/\\/g, '/'); if (item.isDirectory()) { - readAllMarkdownFiles(itemPath, basePath, fileContents); + readAllMarkdownFiles(itemPath, basePath, fileContents, ignoreList); } else if (isMarkdownFile(item.name)) { try { const content = fs.readFileSync(itemPath, 'utf-8'); @@ -124,22 +142,19 @@ function generateData() { if (!fs.existsSync(OUTPUT_PATH)) { fs.mkdirSync(OUTPUT_PATH, { recursive: true }); } + if (!fs.existsSync(PUBLIC_OUTPUT_PATH)) { + fs.mkdirSync(PUBLIC_OUTPUT_PATH, { recursive: true }); + } + + // 加载忽略配置 + console.log('📋 加载忽略配置...'); + const ignoreList = loadIgnoreConfig(); console.log('📁 读取目录结构...'); - const directoryTree = readDirectoryTree(NOTES_SOURCE_PATH); + const directoryTree = readDirectoryTree(NOTES_SOURCE_PATH, NOTES_SOURCE_PATH, ignoreList); console.log('📄 读取Markdown文件内容...'); - const fileContents = readAllMarkdownFiles(NOTES_SOURCE_PATH); - - // 生成目录树文件 - const treeOutputPath = path.join(OUTPUT_PATH, 'directoryTree.json'); - fs.writeFileSync(treeOutputPath, JSON.stringify(directoryTree, null, 2), 'utf-8'); - console.log(`✓ 目录树已生成: ${treeOutputPath}`); - - // 生成文件内容文件 - const contentOutputPath = path.join(OUTPUT_PATH, 'fileContents.json'); - fs.writeFileSync(contentOutputPath, JSON.stringify(fileContents, null, 2), 'utf-8'); - console.log(`✓ 文件内容已生成: ${contentOutputPath}`); + const fileContents = readAllMarkdownFiles(NOTES_SOURCE_PATH, NOTES_SOURCE_PATH, {}, ignoreList); // 生成统计信息 const stats = { @@ -149,10 +164,32 @@ function generateData() { sourceDirectory: NOTES_SOURCE_PATH }; + // 生成到 src/data 目录 + const treeOutputPath = path.join(OUTPUT_PATH, 'directoryTree.json'); + const contentOutputPath = path.join(OUTPUT_PATH, 'fileContents.json'); const statsOutputPath = path.join(OUTPUT_PATH, 'stats.json'); + + fs.writeFileSync(treeOutputPath, JSON.stringify(directoryTree, null, 2), 'utf-8'); + fs.writeFileSync(contentOutputPath, JSON.stringify(fileContents, null, 2), 'utf-8'); fs.writeFileSync(statsOutputPath, JSON.stringify(stats, null, 2), 'utf-8'); + + console.log(`✓ 目录树已生成: ${treeOutputPath}`); + console.log(`✓ 文件内容已生成: ${contentOutputPath}`); console.log(`✓ 统计信息已生成: ${statsOutputPath}`); + // 生成到 public/data 目录 + const publicTreeOutputPath = path.join(PUBLIC_OUTPUT_PATH, 'directoryTree.json'); + const publicContentOutputPath = path.join(PUBLIC_OUTPUT_PATH, 'fileContents.json'); + const publicStatsOutputPath = path.join(PUBLIC_OUTPUT_PATH, 'stats.json'); + + fs.writeFileSync(publicTreeOutputPath, JSON.stringify(directoryTree, null, 2), 'utf-8'); + fs.writeFileSync(publicContentOutputPath, JSON.stringify(fileContents, null, 2), 'utf-8'); + fs.writeFileSync(publicStatsOutputPath, JSON.stringify(stats, null, 2), 'utf-8'); + + console.log(`✓ 目录树已生成到public: ${publicTreeOutputPath}`); + console.log(`✓ 文件内容已生成到public: ${publicContentOutputPath}`); + console.log(`✓ 统计信息已生成到public: ${publicStatsOutputPath}`); + console.log('🎉 数据生成完成!'); console.log(`📊 统计信息:`); console.log(` - 文件数量: ${stats.totalFiles}`); diff --git a/src/App.css b/src/App.css index ff64e18..01aef5b 100644 --- a/src/App.css +++ b/src/App.css @@ -1,14 +1,15 @@ -:root { +:root { --color-bg: #f5f7fb; --color-surface: #ffffff; --color-surface-alt: #f1f4fa; --color-border: #d8deed; --color-text: #1f2a44; --color-muted: #6f7b92; - --color-accent: #3a7afe; - --color-accent-soft: rgba(58, 122, 254, 0.1); + --color-accent: #7da7f2; + --color-accent-soft: rgba(125, 167, 242, 0.12); --color-danger: #d6455d; --sidebar-width: clamp(250px, 20vw, 320px); + --sidebar-width-mobile: clamp(250px, 35vw, 300px); --shadow-soft: 0 20px 45px rgba(86, 105, 141, 0.15); --radius-lg: 22px; --font-family-base: 'Inter', 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif; @@ -23,76 +24,99 @@ body { margin: 0; padding: 0; min-height: 100vh; - background: linear-gradient(135deg, #f6f9ff 0%, #edf2fb 45%, #fbfdff 100%); + background: linear-gradient(135deg, #dfe9f3 0%, #f2f0ff 25%, #fde6f4 50%, #e3f6ff 75%, #f4fff8 100%); color: var(--color-text); font-family: var(--font-family-base); + overflow-x: hidden; + width: 100%; + max-width: 100vw; + /* 全局隐藏滚动条 */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ +} + +/* 全局隐藏 WebKit 浏览器的滚动条 */ +html::-webkit-scrollbar, +body::-webkit-scrollbar { + display: none; } #root { min-height: 100vh; display: flex; - padding: clamp(1rem, 4vw, 2.5rem); + padding: 0; + width: 100%; + max-width: 100vw; + overflow-x: hidden; } .app { flex: 1; display: flex; - min-height: calc(100vh - clamp(2rem, 6vw, 5rem)); - border-radius: var(--radius-lg); - background: var(--color-surface); - border: 1px solid var(--color-border); - box-shadow: var(--shadow-soft); + min-height: 100vh; + border-radius: 0; + background: rgba(255, 255, 255, 0.04); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border: 1px solid rgba(255, 255, 255, 0.14); + box-shadow: 0 10px 34px rgba(45, 60, 115, 0.22); overflow: hidden; position: relative; + width: 100%; + max-width: 100vw; } body ::selection { - background-color: rgba(58, 122, 254, 0.18); + background-color: rgba(125, 167, 242, 0.18); color: var(--color-text); } +/* 全局隐藏所有滚动条 */ ::-webkit-scrollbar { - width: 10px; + display: none; } -::-webkit-scrollbar-track { - background: rgba(216, 222, 237, 0.4); - border-radius: 999px; -} - -::-webkit-scrollbar-thumb { - background: rgba(111, 123, 146, 0.35); - border-radius: 999px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgba(111, 123, 146, 0.55); +* { + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ } button:focus, a:focus { - outline: 2px solid rgba(58, 122, 254, 0.45); + outline: 2px solid rgba(125, 167, 242, 0.4); outline-offset: 2px; } -@media (max-width: 1024px) { - #root { - padding: clamp(0.75rem, 4vw, 1.75rem); - } - - .app { - min-height: calc(100vh - clamp(1.5rem, 7vw, 3.5rem)); - border-radius: 18px; - } -} - +/* 手机屏 */ @media (max-width: 768px) { + /* 手机屏全局字体放大1.5倍 */ + html { + font-size: 150%; + } + + :root { + --sidebar-width-mobile: 280px; + } + + html, body { + overflow-x: hidden; + width: 100%; + max-width: 100vw; + } + #root { - padding: clamp(0.5rem, 5vw, 1.2rem); + padding: 0; + width: 100%; + max-width: 100vw; + overflow-x: hidden; } .app { min-height: 100vh; - border-radius: 16px; + border-radius: 0; + width: 100%; + max-width: 100vw; + overflow-x: hidden; + flex-direction: row; } } diff --git a/src/components/MarkdownRenderer.css b/src/components/MarkdownRenderer.css index 60f7b87..f83c6b9 100644 --- a/src/components/MarkdownRenderer.css +++ b/src/components/MarkdownRenderer.css @@ -1,9 +1,15 @@ -.content-area { +.content-area { flex: 1; display: flex; flex-direction: column; - background: var(--color-surface); + background: rgba(255, 255, 255, 0.06); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); color: var(--color-text); + width: 100%; + max-width: 100%; + height: 100vh; + overflow: hidden; } .content-area.with-sidebar { @@ -15,8 +21,11 @@ top: 0; z-index: 10; padding: 1.75rem clamp(2rem, 5vw, 3rem) 1.25rem; - background: var(--color-surface); - border-bottom: 1px solid var(--color-border); + background: rgba(255, 255, 255, 0.12); + backdrop-filter: blur(16px) saturate(180%); + -webkit-backdrop-filter: blur(16px) saturate(180%); + border-bottom: 1px solid rgba(255, 255, 255, 0.22); + box-shadow: 0 3px 14px rgba(45, 60, 115, 0.15); } .breadcrumbs { @@ -41,7 +50,10 @@ .breadcrumb-text { padding: 0.2rem 0.55rem; border-radius: 999px; - background: rgba(58, 122, 254, 0.08); + background: rgba(255, 255, 255, 0.18); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + box-shadow: 0 2px 6px rgba(45, 60, 115, 0.12); } .content-title { @@ -49,14 +61,18 @@ font-size: clamp(2rem, 3.5vw, 2.6rem); font-weight: 600; color: var(--color-text); + text-align: center; } .content-body { flex: 1; overflow-y: auto; + overflow-x: hidden; display: flex; justify-content: center; padding: clamp(2rem, 6vw, 3.5rem); + height: 0; + min-height: 0; } .markdown-pane { @@ -85,26 +101,34 @@ } .markdown-content h1 { - font-size: clamp(2.1rem, 3vw, 2.8rem); + font-size: clamp(1.8rem, 2.5vw, 2.4rem); border-bottom: 2px solid rgba(31, 42, 68, 0.08); padding-bottom: 0.6rem; } .markdown-content h2 { - font-size: clamp(1.7rem, 2.5vw, 2.2rem); + font-size: clamp(1.5rem, 2vw, 1.9rem); border-bottom: 1px solid rgba(31, 42, 68, 0.08); padding-bottom: 0.45rem; } .markdown-content h3 { - font-size: clamp(1.4rem, 2vw, 1.7rem); + font-size: clamp(1.25rem, 1.7vw, 1.5rem); } .markdown-content h4 { - font-size: 1.15rem; + font-size: 1.1rem; letter-spacing: 0.01em; } +.markdown-content h5 { + font-size: 1.05rem; +} + +.markdown-content h6 { + font-size: 1rem; +} + .heading-anchor { position: absolute; left: -1.5rem; @@ -154,61 +178,137 @@ align-items: center; padding: 0.15rem 0.4rem; border-radius: 6px; - background: rgba(58, 122, 254, 0.08); - border: 1px solid rgba(58, 122, 254, 0.16); + background: rgba(255, 255, 255, 0.2); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + border: 1px solid rgba(255, 255, 255, 0.26); color: var(--color-text); font-size: 0.95em; + box-shadow: 0 2px 6px rgba(45, 60, 115, 0.12); } -.code-block-wrapper { - background: #f6f8ff; - border: 1px solid rgba(58, 122, 254, 0.15); - border-radius: 14px; - overflow: hidden; +/* 桌面端代码块样式 */ +@media (min-width: 769px) { + .code-block-wrapper { + width: clamp(85%, 90%, calc(100vw - 4rem)); + max-width: min(1200px, calc(100vw - 4rem)); + margin: 1.5rem auto; + background: rgba(246, 248, 255, 0.78); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.26); + border-radius: 16px; + overflow: hidden; + box-sizing: border-box; + box-shadow: 0 8px 25px rgba(45, 60, 115, 0.18); + position: relative; + } } .code-block-header { display: flex; align-items: center; - justify-content: space-between; - padding: 0.75rem 1rem; - background: rgba(58, 122, 254, 0.08); + justify-content: center; + padding: 0.75rem 1rem 0.75rem 5rem; + background: rgba(125, 167, 242, 0.12); color: var(--color-muted); font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; + position: relative; +} + +.code-block-header::before { + content: ''; + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + display: flex; + gap: 8px; +} + +.code-block-header::after { + content: ''; + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + width: 12px; + height: 12px; + border-radius: 50%; + background: #ff5f57; + box-shadow: + 20px 0 0 #ffbd2e, + 40px 0 0 #28ca42, + 0 0 0 1px rgba(0, 0, 0, 0.1), + 20px 0 0 1px rgba(0, 0, 0, 0.1), + 40px 0 0 1px rgba(0, 0, 0, 0.1); +} + +.code-block-header .code-copy-button { + position: absolute; + right: 1rem; + top: 50%; + transform: translateY(-50%); } .code-copy-button { - border: 1px solid rgba(58, 122, 254, 0.25); - background: #fff; + border: 1px solid rgba(255, 255, 255, 0.34); + background: rgba(255, 255, 255, 0.25); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); color: var(--color-muted); border-radius: 8px; padding: 0.35rem 0.7rem; + box-shadow: 0 3px 10px rgba(45, 60, 115, 0.16); cursor: pointer; transition: all 0.2s ease; } .code-copy-button:hover { color: var(--color-accent); - border-color: rgba(58, 122, 254, 0.5); + border-color: rgba(125, 167, 242, 0.5); } .code-copy-button.copied { color: var(--color-accent); - border-color: rgba(58, 122, 254, 0.7); + border-color: rgba(125, 167, 242, 0.65); } pre { margin: 0; padding: 1.1rem 1.35rem; + width: 100%; overflow-x: auto; + overflow-y: auto; font-size: 0.95rem; + box-sizing: border-box; + max-width: 100%; + white-space: pre; + line-height: 1.6; + /* 隐藏滚动条 */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ } +/* 隐藏 WebKit 浏览器的滚动条 */ +pre::-webkit-scrollbar { + display: none; +} + + + + + pre code { background: transparent !important; color: #1f2a44; + display: block; + width: 100%; + overflow-x: auto; + white-space: pre; + line-height: inherit; } .markdown-image { @@ -218,8 +318,10 @@ pre code { .markdown-image img { border-radius: 14px; - border: 1px solid rgba(31, 42, 68, 0.1); - box-shadow: 0 18px 38px rgba(31, 42, 68, 0.12); + border: 1px solid rgba(255, 255, 255, 0.22); + box-shadow: 0 16px 30px rgba(45, 60, 115, 0.18); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); } .markdown-image figcaption { @@ -231,10 +333,13 @@ pre code { .markdown-content blockquote { margin: 1.6rem 0; padding: 1rem 1.25rem; - border-left: 4px solid rgba(58, 122, 254, 0.45); - background: rgba(58, 122, 254, 0.1); + border-left: 4px solid rgba(125, 167, 242, 0.5); + background: rgba(255, 255, 255, 0.18); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); border-radius: 0 14px 14px 0; color: var(--color-text); + box-shadow: 0 4px 12px rgba(45, 60, 115, 0.14); } .markdown-content hr { @@ -246,8 +351,11 @@ pre code { .table-wrapper { overflow-x: auto; border-radius: 14px; - border: 1px solid rgba(31, 42, 68, 0.12); - background: #ffffff; + border: 1px solid rgba(255, 255, 255, 0.26); + background: rgba(255, 255, 255, 0.12); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: 0 6px 18px rgba(45, 60, 115, 0.16); } .table-wrapper table { @@ -318,9 +426,11 @@ pre code { max-width: 520px; padding: 2.4rem; border-radius: 18px; - background: #ffffff; - border: 1px solid var(--color-border); - box-shadow: 0 24px 48px rgba(86, 105, 141, 0.18); + background: rgba(255, 255, 255, 0.12); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + border: 1px solid rgba(255, 255, 255, 0.24); + box-shadow: 0 20px 36px rgba(45, 60, 115, 0.2); } .welcome-content h1 { @@ -345,44 +455,220 @@ pre code { justify-content: center; gap: 0.6rem; padding: 0.85rem; - border: 1px solid var(--color-border); + border: 1px solid rgba(255, 255, 255, 0.24); border-radius: 12px; - background: var(--color-surface); - color: var(--color-muted); + background: rgba(255, 255, 255, 0.16); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + color: rgba(31, 42, 68, 0.75); + box-shadow: 0 4px 10px rgba(45, 60, 115, 0.16); + transition: all 0.3s ease; +} + +.feature-item:hover { + transform: translateY(-2px); + box-shadow: 0 7px 16px rgba(45, 60, 115, 0.22); + background: rgba(255, 255, 255, 0.22); } .feature-icon { font-size: 1.1rem; } +/* 手机屏 */ @media (max-width: 768px) { - .content-header { - padding: 1.2rem 1.5rem 0.9rem; + .content-area { + width: 100%; + max-width: 100%; + overflow-x: hidden; } - .content-body { - padding: 1.5rem; + .content-header { + padding: clamp(0.5rem, 1.5vw, 0.75rem); + border-radius: 6px; + width: 100%; + max-width: 100%; + overflow-x: hidden; } .markdown-pane { width: 100%; + max-width: 100%; + overflow-x: hidden; } .heading-anchor { display: none; } -} -@media (max-width: 480px) { - .content-header { - padding: 1rem 1.1rem 0.75rem; + .content-title { + font-size: clamp(1.125rem, 3.5vw, 1.375rem); + line-height: 1.2; + margin-bottom: 0.375rem; + word-wrap: break-word; + overflow-wrap: break-word; } .content-body { - padding: 1rem; + padding: clamp(0.5rem, 1.5vw, 0.75rem) 0; + width: 100%; + max-width: 100%; + overflow-x: hidden; + } + + .markdown-content { + font-size: clamp(0.8rem, 2.2vw, 0.9rem); + line-height: 1.5; + width: 100%; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content h1 { + font-size: clamp(1.375rem, 4.5vw, 1.75rem); + line-height: 1.1; + margin: 1.25rem 0 0.875rem 0; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content h2 { + font-size: clamp(1.125rem, 3.5vw, 1.5rem); + line-height: 1.2; + margin: 1rem 0 0.625rem 0; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content h3 { + font-size: clamp(1rem, 3vw, 1.25rem); + line-height: 1.2; + margin: 0.875rem 0 0.5rem 0; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content h4 { + font-size: clamp(0.95rem, 2.8vw, 1.125rem); + line-height: 1.3; + margin: 0.75rem 0 0.375rem 0; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content h5 { + font-size: clamp(0.9rem, 2.5vw, 1rem); + line-height: 1.3; + margin: 0.625rem 0 0.375rem 0; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content h6 { + font-size: clamp(0.85rem, 2.2vw, 0.95rem); + line-height: 1.3; + margin: 0.5rem 0 0.25rem 0; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content p { + margin: 0.625rem 0; + line-height: 1.5; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content li { + margin: 0.25rem 0; + line-height: 1.4; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .markdown-content blockquote { + margin: 0.875rem 0; + padding: 0.625rem 0.875rem; + font-size: clamp(0.8rem, 2.2vw, 0.9rem); + line-height: 1.5; + word-wrap: break-word; + overflow-wrap: break-word; + } + + .code-block-wrapper { + width: calc(100vw - 2rem); + max-width: calc(100vw - 2rem); + margin: 0.875rem 0 0.875rem 0; + background: rgba(246, 248, 255, 0.78); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.26); + border-radius: 6px; + overflow: hidden; + box-sizing: border-box; + box-shadow: 0 8px 25px rgba(45, 60, 115, 0.18); + position: relative; + } + + .code-block-header { + padding: 0.375rem 0.5rem; + font-size: 0.7rem; + } + + .code-block-controls button { + padding: 0.2rem 0.4rem; + font-size: 0.65rem; + } + + .copy-button { + width: 24px; + height: 24px; + font-size: 10px; + top: 0.375rem; + right: 0.375rem; + } + + .markdown-content pre { + overflow-x: auto; + overflow-y: auto; + white-space: pre; + line-height: 1.4; + padding: 0.6rem 0.8rem; + font-size: 0.75rem; + /* 隐藏滚动条 */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + } + + /* 隐藏移动端 WebKit 浏览器的滚动条 */ + .markdown-content pre::-webkit-scrollbar { + display: none; + } + + .markdown-content img { + margin: 0.875rem auto; + border-radius: 6px; + max-width: calc(100vw - 1rem); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + } + + .markdown-content table { + font-size: 0.8rem; + width: 100%; + max-width: calc(100vw - 1rem); + overflow-x: auto; + display: block; + } + + .markdown-content th, + .markdown-content td { + padding: 0.375rem 0.5rem; + min-width: 80px; } .feature-item { flex-direction: column; } } + diff --git a/src/components/MarkdownRenderer.jsx b/src/components/MarkdownRenderer.jsx index 8ad23d6..d99330a 100644 --- a/src/components/MarkdownRenderer.jsx +++ b/src/components/MarkdownRenderer.jsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; @@ -12,6 +12,34 @@ import './MarkdownRenderer.css'; import 'katex/dist/katex.min.css'; import 'highlight.js/styles/github.css'; +// 自定义插件:禁用内联代码解析 +function remarkDisableInlineCode() { + return (tree) => { + // 移除所有内联代码节点,将其转换为普通文本 + function visit(node, parent, index) { + if (node.type === 'inlineCode') { + // 将内联代码节点替换为文本节点 + const textNode = { + type: 'text', + value: node.value + }; + if (parent && typeof index === 'number') { + parent.children[index] = textNode; + } + return; + } + + if (node.children) { + for (let i = 0; i < node.children.length; i++) { + visit(node.children[i], node, i); + } + } + } + + visit(tree); + }; +} + function Breadcrumbs({ filePath }) { const breadcrumbs = generateBreadcrumbs(filePath); if (breadcrumbs.length === 0) return null; @@ -32,14 +60,28 @@ function CodeBlock({ inline, className, children, ...props }) { const [copied, setCopied] = useState(false); if (inline) { - return ( - - {children} - - ); + // 不渲染为代码,直接返回普通文本 + return {children}; } - const codeText = React.Children.toArray(children).join('').replace(/\n$/, ''); + // 改进的文本提取逻辑,处理React元素和纯文本 + const extractText = (node) => { + if (typeof node === 'string') { + return node; + } + if (typeof node === 'number') { + return String(node); + } + if (React.isValidElement(node)) { + return extractText(node.props.children); + } + if (Array.isArray(node)) { + return node.map(extractText).join(''); + } + return ''; + }; + + const codeText = extractText(children).replace(/\n$/, ''); const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : 'text'; const buttonClass = 'code-copy-button' + (copied ? ' copied' : ''); @@ -152,7 +194,14 @@ export default function MarkdownRenderer() { const components = useMemo( () => ({ - code: CodeBlock, + code: ({ inline, className, children, ...props }) => { + if (inline) { + // 内联代码直接返回普通文本,不做任何特殊处理 + return {children}; + } + // 代码块使用原来的CodeBlock组件 + return {children}; + }, a: CustomLink, table: CustomTable, ...headingComponents, @@ -205,7 +254,6 @@ export default function MarkdownRenderer() { return (
-

{fileTitle}

@@ -219,7 +267,7 @@ export default function MarkdownRenderer() { ) : (
diff --git a/src/components/Sidebar.css b/src/components/Sidebar.css index 02a611b..c429779 100644 --- a/src/components/Sidebar.css +++ b/src/components/Sidebar.css @@ -1,11 +1,18 @@ -.sidebar { +.sidebar { + position: relative; + z-index: 110; width: var(--sidebar-width); - background: var(--color-surface-alt); - border-right: 1px solid var(--color-border); + height: 100vh; + background: rgba(255, 255, 255, 0.08); + backdrop-filter: blur(16px) saturate(180%); + -webkit-backdrop-filter: blur(16px) saturate(180%); + border-right: 1px solid rgba(255, 255, 255, 0.18); display: flex; flex-direction: column; padding: 1.5rem 1.25rem 1.75rem; color: var(--color-text); + box-shadow: 0 6px 24px rgba(45, 60, 115, 0.18); + overflow: hidden; } .sidebar.closed { @@ -19,9 +26,8 @@ .sidebar-header { display: flex; align-items: center; - justify-content: space-between; gap: 0.75rem; - margin-bottom: 1.75rem; + margin-bottom: 1.5rem; } .sidebar-header h2 { @@ -33,32 +39,48 @@ } .toggle-button { - background: var(--color-surface); + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 42px; + height: 42px; + padding: 0 0.7rem; + background: rgba(255, 255, 255, 0.16); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); color: var(--color-muted); - border: 1px solid var(--color-border); + border: 1px solid rgba(255, 255, 255, 0.24); border-radius: 12px; - padding: 0.4rem 0.8rem; font-size: 0.95rem; + line-height: 1; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 12px 24px rgba(86, 105, 141, 0.12); + box-shadow: 0 6px 14px rgba(45, 60, 115, 0.18); } .toggle-button:hover { color: var(--color-accent); - border-color: rgba(58, 122, 254, 0.6); + border-color: rgba(125, 167, 242, 0.55); +} + +.toggle-button.open { + color: var(--color-accent); + border-color: rgba(125, 167, 242, 0.65); } .sidebar-content { flex: 1; overflow-y: auto; + overflow-x: hidden; padding-right: 0.5rem; + height: 0; + min-height: 0; } .directory-tree { display: flex; flex-direction: column; - gap: 0.35rem; + gap: 0rem; } .tree-node { @@ -69,22 +91,29 @@ display: flex; align-items: center; gap: 0.55rem; - padding: 0.5rem 0.65rem; + padding: 0.3rem 0.65rem; border-radius: 12px; - color: var(--color-muted); + color: rgba(31, 42, 68, 0.7); cursor: pointer; - transition: background 0.2s ease, color 0.2s ease; + transition: all 0.2s ease; } .tree-node-content:hover { - background: var(--color-accent-soft); + background: rgba(255, 255, 255, 0.2); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); color: var(--color-accent); + box-shadow: 0 3px 10px rgba(45, 60, 115, 0.16); } .tree-node-content.selected { - background: rgba(58, 122, 254, 0.16); + background: rgba(255, 255, 255, 0.26); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); color: var(--color-accent); font-weight: 600; + border: 1px solid rgba(255, 255, 255, 0.34); + box-shadow: 0 4px 14px rgba(125, 167, 242, 0.25); } .tree-node-icon { @@ -98,7 +127,11 @@ } .tree-node-children { - margin-top: 0.25rem; + margin-top: 0; +} + +.tree-node-name { + font-weight: 600; } .loading, @@ -129,66 +162,64 @@ } .sidebar-backdrop { - position: fixed; - inset: 0; - background: rgba(16, 23, 35, 0.35); - backdrop-filter: blur(4px); - opacity: 0; - pointer-events: none; - transition: opacity 0.25s ease; - z-index: 50; -} - -.sidebar-backdrop.active { - opacity: 1; - pointer-events: auto; + display: none; } .sidebar-toggle { position: fixed; - top: 1.25rem; - left: 1.25rem; - z-index: 120; + top: 1rem; + right: 1rem; + z-index: 130; + width: 44px; + height: 44px; + padding: 0; + border-radius: 14px; + box-shadow: 0 14px 30px rgba(86, 105, 141, 0.18); } -.sidebar-toggle .toggle-button { - padding: 0.45rem 0.9rem; -} - -.toggle-button.open { - color: var(--color-accent); - border-color: rgba(58, 122, 254, 0.55); -} - -@media (max-width: 1024px) { +/* 手机屏 */ +@media (max-width: 768px) { .sidebar { - position: absolute; - top: clamp(1rem, 5vw, 2rem); - left: clamp(1rem, 5vw, 2rem); - height: calc(100% - clamp(2rem, 10vw, 4rem)); - border-radius: 20px; - box-shadow: var(--shadow-soft); - transform: translateX(calc(-100% - 2.5rem)); - transition: transform 0.3s ease, opacity 0.3s ease; - opacity: 0; - pointer-events: none; + width: var(--sidebar-width-mobile, 280px); + padding: 0.75rem; + max-width: calc(100vw - 1rem); + overflow-x: hidden; + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1); } - .sidebar.open { - transform: translateX(0); - opacity: 1; - pointer-events: auto; + .sidebar.closed { + transform: translateX(-100%); + } + + .toggle-button { + top: 0.75rem; + left: 0.75rem; + z-index: 1001; + width: 40px; + height: 40px; + font-size: 18px; + } + + .sidebar-content { + overflow-x: hidden; + width: 100%; + } + + .directory-tree { + overflow-x: hidden; + width: 100%; + } + + .sidebar-header h2 { + font-size: 1.1rem; + margin: 0.5rem 0; } } -@media (min-width: 1025px) { - .sidebar-backdrop, - .sidebar-toggle { - display: none; - } - +/* 电脑屏 */ +@media (min-width: 769px) { .sidebar { - position: relative; + position: static; transform: none; opacity: 1; pointer-events: auto; diff --git a/src/components/Sidebar.jsx b/src/components/Sidebar.jsx index 6c8f1a9..0893313 100644 --- a/src/components/Sidebar.jsx +++ b/src/components/Sidebar.jsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect } from 'react'; import { useApp } from '../context/AppContext'; import { NODE_TYPES } from '../utils/fileUtils'; import './Sidebar.css'; @@ -43,7 +43,11 @@ function TreeNode({ node, level = 0 }) { {node.type === NODE_TYPES.FILE && ( 📄 )} - {node.name} + + {node.type === NODE_TYPES.FILE && node.name.endsWith('.md') + ? node.name.slice(0, -3) + : node.name} +
{node.type === NODE_TYPES.FOLDER && node.isExpanded && hasChildren && ( @@ -60,38 +64,16 @@ function TreeNode({ node, level = 0 }) { export default function Sidebar() { const { directoryTree, isLoading, error, sidebarOpen, toggleSidebar } = useApp(); - const toggleLabel = sidebarOpen ? '收起目录' : '展开目录'; + const toggleLabel = sidebarOpen ? '隐藏目录' : '展开目录'; + const toggleSymbol = sidebarOpen ? '◀' : '☰'; const sidebarClass = sidebarOpen ? 'sidebar open' : 'sidebar closed'; const toggleButtonClass = sidebarOpen ? 'toggle-button open' : 'toggle-button'; - const backdropClass = sidebarOpen ? 'sidebar-backdrop active' : 'sidebar-backdrop'; - - useEffect(() => { - if (typeof window === 'undefined') { - return undefined; - } - - const handleScrollLock = () => { - const shouldLock = sidebarOpen && window.innerWidth <= 1024; - document.body.classList.toggle('no-scroll', shouldLock); - }; - - handleScrollLock(); - window.addEventListener('resize', handleScrollLock); - - return () => { - window.removeEventListener('resize', handleScrollLock); - document.body.classList.remove('no-scroll'); - }; - }, [sidebarOpen]); return ( <> -