<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://right202209.github.io/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://right202209.github.io/blog/" rel="alternate" type="text/html" hreflang="zh" /><updated>2026-03-23T13:51:24+00:00</updated><id>https://right202209.github.io/blog/feed.xml</id><title type="html">Right</title><subtitle>以证据为起点，以方法为路径。</subtitle><entry><title type="html">Zsh 与 Oh My Zsh 安装配置指南</title><link href="https://right202209.github.io/blog/oh-my-zsh/" rel="alternate" type="text/html" title="Zsh 与 Oh My Zsh 安装配置指南" /><published>2026-02-20T00:00:00+00:00</published><updated>2026-02-20T00:00:00+00:00</updated><id>https://right202209.github.io/blog/oh-my-zsh</id><content type="html" xml:base="https://right202209.github.io/blog/oh-my-zsh/"><![CDATA[<blockquote>
  <table>
    <tbody>
      <tr>
        <td>参考来源：[zsh 安装与配置</td>
        <td>Leehow的小站](https://www.haoyep.com/posts/zsh-config-oh-my-zsh/)</td>
      </tr>
    </tbody>
  </table>

  <p>OS -&gt; Ubuntu</p>
</blockquote>

<h2 id="1-环境准备">1. 环境准备</h2>

<p>更新软件源并安装必要依赖：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt upgrade <span class="nt">-y</span>
<span class="nb">sudo </span>apt <span class="nb">install </span>zsh git curl <span class="nt">-y</span>
</code></pre></div></div>

<p>设置 Zsh 为默认 Shell（<strong>无需 sudo</strong>，注销或重启生效）：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chsh <span class="nt">-s</span> /bin/zsh
</code></pre></div></div>

<h2 id="2-安装-oh-my-zsh">2. 安装 Oh My Zsh</h2>

<p>安装过程中如提示覆盖 <code class="language-plaintext highlighter-rouge">.zshrc</code>，请选择同意。</p>
<h3 id="官方源">官方源</h3>

<table>
  <thead>
    <tr>
      <th style="text-align: left">工具</th>
      <th style="text-align: left">安装命令</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>curl</strong></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">sh -c "$(curl -fsSL https://install.ohmyz.sh/)"</code></td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>wget</strong></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">sh -c "$(wget -O- https://install.ohmyz.sh/)"</code></td>
    </tr>
  </tbody>
</table>

<h2 id="3-配置迁移-bash--zsh">3. 配置迁移 Bash → Zsh</h2>

<p>若之前在 <code class="language-plaintext highlighter-rouge">bash</code> 中有自定义环境变量或别名，需手动迁移：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1. 查看旧配置</span>
<span class="nb">cat</span> ~/.bashrc
<span class="c"># 2. 编辑新配置</span>
nano ~/.zshrc
<span class="c"># 3. 加载配置</span>
<span class="nb">source</span> ~/.zshrc
</code></pre></div></div>

<h2 id="4-主题配置">4. 主题配置</h2>

<p>以 <code class="language-plaintext highlighter-rouge">haoomz</code> 主题为例 (也可使用内置主题如 <code class="language-plaintext highlighter-rouge">ys</code>, <code class="language-plaintext highlighter-rouge">robbyrussell</code>)。</p>

<p><strong>下载第三方主题：</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>wget <span class="nt">-O</span> <span class="nv">$ZSH_CUSTOM</span>/themes/haoomz.zsh-theme https://cdn.haoyep.com/gh/leegical/Blog_img/zsh/haoomz.zsh-theme
</code></pre></div></div>

<p><strong>启用主题：</strong>
编辑 <code class="language-plaintext highlighter-rouge">~/.zshrc</code>，修改 <code class="language-plaintext highlighter-rouge">ZSH_THEME</code> 字段：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ZSH_THEME</span><span class="o">=</span><span class="s2">"haoomz"</span>
<span class="c"># ZSH_THEME="robbyrussell" # 备选内置主题</span>
</code></pre></div></div>

<h2 id="5-插件配置">5. 插件配置</h2>

<p>插件分为<strong>内置插件</strong>（可直接启用）和<strong>第三方插件</strong>（需下载）。</p>

<h3 id="第三方插件下载">第三方插件下载</h3>

<ol>
  <li>
    <p><strong>zsh-autosuggestions</strong>（自动补全建议）</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/zsh-users/zsh-autosuggestions <span class="k">${</span><span class="nv">ZSH_CUSTOM</span><span class="k">:-</span><span class="p">~/.oh-my-zsh/custom</span><span class="k">}</span>/plugins/zsh-autosuggestions
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>zsh-syntax-highlighting</strong>（语法高亮校验）</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/zsh-users/zsh-syntax-highlighting.git <span class="k">${</span><span class="nv">ZSH_CUSTOM</span><span class="k">:-</span><span class="p">~/.oh-my-zsh/custom</span><span class="k">}</span>/plugins/zsh-syntax-highlighting
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="推荐内置插件">推荐内置插件</h3>
<ul>
  <li><strong>git</strong>: 显示 Git 仓库状态（默认开启）。</li>
  <li><strong>z</strong>: 快速跳转常用目录（智能记忆）。</li>
  <li><strong>extract</strong>: 万能解压命令，使用 <code class="language-plaintext highlighter-rouge">x filename</code> 即可。</li>
  <li><strong>web-search</strong>: 命令行搜索，如 <code class="language-plaintext highlighter-rouge">google 搜索内容</code>。</li>
</ul>

<h3 id="启用插件">启用插件</h3>
<p>编辑 <code class="language-plaintext highlighter-rouge">~/.zshrc</code>，找到 <code class="language-plaintext highlighter-rouge">plugins=(...)</code> 并修改：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">plugins</span><span class="o">=(</span>
  git
  zsh-autosuggestions
  zsh-syntax-highlighting
  z
  extract
  web-search
<span class="o">)</span>
</code></pre></div></div>

<p>保存后执行 <code class="language-plaintext highlighter-rouge">source ~/.zshrc</code> 重新加载。</p>

<h2 id="6-高级配置">6. 高级配置</h2>

<h3 id="root-用户配置">Root 用户配置</h3>
<p><code class="language-plaintext highlighter-rouge">root</code> 用户的 Shell 配置与普通用户独立。建议：</p>
<ol>
  <li>切换到 root (<code class="language-plaintext highlighter-rouge">sudo su</code>) 并重新安装 Oh My Zsh。</li>
  <li>使用不同的主题以区分身份。</li>
  <li>插件配置可与普通用户保持一致。</li>
</ol>

<h3 id="快捷代理设置">快捷代理设置</h3>
<p>在 <code class="language-plaintext highlighter-rouge">~/.zshrc</code> 中添加函数，实现一条命令开关代理（根据实际端口修改）：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 开启代理</span>
proxy <span class="o">()</span> <span class="o">{</span>
  <span class="nb">export </span><span class="nv">HTTP_PROXY</span><span class="o">=</span><span class="s2">"http://127.0.0.1:7890"</span>
  <span class="nb">export </span><span class="nv">HTTPS_PROXY</span><span class="o">=</span><span class="s2">"https://127.0.0.1:7890"</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="7-维护命令">7. 维护命令</h2>

<ul>
  <li>
    <p><strong>手动更新 Oh My Zsh</strong>：</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>upgrade_oh_my_zsh
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>卸载 Oh My Zsh</strong>：</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>uninstall_oh_my_zsh
</code></pre></div>    </div>
  </li>
</ul>]]></content><author><name></name></author><category term="document" /><summary type="html"><![CDATA[参考来源：[zsh 安装与配置 Leehow的小站](https://www.haoyep.com/posts/zsh-config-oh-my-zsh/) OS -&gt; Ubuntu 1. 环境准备 更新软件源并安装必要依赖： sudo apt update &amp;&amp; sudo apt upgrade -y sudo apt install zsh git curl -y 设置 Zsh 为默认 Shell（无需 sudo，注销或重启生效）： chsh -s /bin/zsh 2. 安装 Oh My Zsh 安装过程中如提示覆盖 .zshrc，请选择同意。 官方源 工具 安装命令 curl sh -c "$(curl -fsSL https://install.ohmyz.sh/)" wget sh -c "$(wget -O- https://install.ohmyz.sh/)" 3. 配置迁移 Bash → Zsh 若之前在 bash 中有自定义环境变量或别名，需手动迁移： # 1. 查看旧配置 cat ~/.bashrc # 2. 编辑新配置 nano ~/.zshrc # 3. 加载配置 source ~/.zshrc 4. 主题配置 以 haoomz 主题为例 (也可使用内置主题如 ys, robbyrussell)。 下载第三方主题： sudo wget -O $ZSH_CUSTOM/themes/haoomz.zsh-theme https://cdn.haoyep.com/gh/leegical/Blog_img/zsh/haoomz.zsh-theme 启用主题： 编辑 ~/.zshrc，修改 ZSH_THEME 字段： ZSH_THEME="haoomz" # ZSH_THEME="robbyrussell" # 备选内置主题 5. 插件配置 插件分为内置插件（可直接启用）和第三方插件（需下载）。 第三方插件下载 zsh-autosuggestions（自动补全建议） git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions zsh-syntax-highlighting（语法高亮校验） git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting 推荐内置插件 git: 显示 Git 仓库状态（默认开启）。 z: 快速跳转常用目录（智能记忆）。 extract: 万能解压命令，使用 x filename 即可。 web-search: 命令行搜索，如 google 搜索内容。 启用插件 编辑 ~/.zshrc，找到 plugins=(...) 并修改： plugins=( git zsh-autosuggestions zsh-syntax-highlighting z extract web-search ) 保存后执行 source ~/.zshrc 重新加载。 6. 高级配置 Root 用户配置 root 用户的 Shell 配置与普通用户独立。建议： 切换到 root (sudo su) 并重新安装 Oh My Zsh。 使用不同的主题以区分身份。 插件配置可与普通用户保持一致。 快捷代理设置 在 ~/.zshrc 中添加函数，实现一条命令开关代理（根据实际端口修改）： # 开启代理 proxy () { export HTTP_PROXY="http://127.0.0.1:7890" export HTTPS_PROXY="https://127.0.0.1:7890" } 7. 维护命令 手动更新 Oh My Zsh： upgrade_oh_my_zsh 卸载 Oh My Zsh： uninstall_oh_my_zsh]]></summary></entry><entry><title type="html">博客现代化改造</title><link href="https://right202209.github.io/blog/post-7/" rel="alternate" type="text/html" title="博客现代化改造" /><published>2026-02-09T00:00:00+00:00</published><updated>2026-02-09T00:00:00+00:00</updated><id>https://right202209.github.io/blog/post-7</id><content type="html" xml:base="https://right202209.github.io/blog/post-7/"><![CDATA[<p>博客现代化改造：Issue 驱动与扁平化布局</p>

<p>站点整体风格改为更紧凑的阅读节奏：少留白、少卡片、弱装饰。工作流上继续强化自动化，保证“随时能写、写完就发”。</p>

<hr />

<h2 id="1-issue-驱动的发布流程">1. Issue 驱动的发布流程</h2>

<p>把写作入口放在 GitHub：</p>
<ul>
  <li><strong>Issue 即草稿</strong>：标题/正文即文章内容，标签用于分类。</li>
  <li><strong>Actions 自动转稿</strong>：发布或关闭触发流水线，生成 <code class="language-plaintext highlighter-rouge">_posts</code> 文件并提交。</li>
  <li><strong>元信息统一</strong>：时间、标签、作者等由脚本注入，减少手工维护。</li>
</ul>

<p>好处很直接：手机端可写、评论天然可用、内容版本可追溯。</p>

<hr />

<h2 id="2-页面结构更扁平">2. 页面结构更扁平</h2>

<p>围绕“内容优先”重排布局：</p>
<ul>
  <li><strong>首页</strong>：主栏列表 + 侧栏概览，信息密度更高。</li>
  <li><strong>文章页</strong>：正文为主，TOC 贴边但不抢占空间。</li>
  <li><strong>导航</strong>：保留 Home / Archive / Tags / About 四个入口。</li>
</ul>

<p>整体强调线条分隔，避免卡片化层叠。</p>

<hr />

<h2 id="3-列表更好找">3. 列表更好找</h2>

<p>归档与标签页加入轻量筛选：</p>
<ul>
  <li>直接输入标题/日期/标签片段即可定位</li>
  <li>仍保留完整列表，筛选只是“快速跳转”</li>
</ul>

<hr />

<h2 id="4-视觉基调统一">4. 视觉基调统一</h2>

<p>延续 CRT 叠加与 rose‑pine 色系，但降低噪点与发光强度，让内容更清爽、更易读。</p>

<hr />

<h2 id="结语">结语</h2>

<p>这次改动的核心只有两点：<strong>写作更快</strong>、<strong>阅读更干净</strong>。后续会继续在不打扰内容的前提下做小步迭代。</p>

<p><strong>下一步计划：</strong></p>
<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />优化图片自动压缩与 WebP 流程</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />引入更细致的全站搜索</li>
</ul>

<p>感谢阅读。</p>]]></content><author><name></name></author><category term="document" /><summary type="html"><![CDATA[博客现代化改造：Issue 驱动与扁平化布局 站点整体风格改为更紧凑的阅读节奏：少留白、少卡片、弱装饰。工作流上继续强化自动化，保证“随时能写、写完就发”。 1. Issue 驱动的发布流程 把写作入口放在 GitHub： Issue 即草稿：标题/正文即文章内容，标签用于分类。 Actions 自动转稿：发布或关闭触发流水线，生成 _posts 文件并提交。 元信息统一：时间、标签、作者等由脚本注入，减少手工维护。 好处很直接：手机端可写、评论天然可用、内容版本可追溯。 2. 页面结构更扁平 围绕“内容优先”重排布局： 首页：主栏列表 + 侧栏概览，信息密度更高。 文章页：正文为主，TOC 贴边但不抢占空间。 导航：保留 Home / Archive / Tags / About 四个入口。 整体强调线条分隔，避免卡片化层叠。 3. 列表更好找 归档与标签页加入轻量筛选： 直接输入标题/日期/标签片段即可定位 仍保留完整列表，筛选只是“快速跳转” 4. 视觉基调统一 延续 CRT 叠加与 rose‑pine 色系，但降低噪点与发光强度，让内容更清爽、更易读。 结语 这次改动的核心只有两点：写作更快、阅读更干净。后续会继续在不打扰内容的前提下做小步迭代。 下一步计划： 优化图片自动压缩与 WebP 流程 引入更细致的全站搜索 感谢阅读。]]></summary></entry><entry><title type="html">Git</title><link href="https://right202209.github.io/blog/git/" rel="alternate" type="text/html" title="Git" /><published>2024-11-09T00:00:00+00:00</published><updated>2024-11-09T00:00:00+00:00</updated><id>https://right202209.github.io/blog/git</id><content type="html" xml:base="https://right202209.github.io/blog/git/"><![CDATA[<p>这是一份我自己的 Git 笔记版教程：内容完整，但语气更像备忘。</p>

<hr />

<h2 id="1-安装-git">1. 安装 Git</h2>

<h3 id="11-windows">1.1 Windows</h3>
<ol>
  <li>下载：<a href="https://gitforwindows.org/">Git for Windows</a>。</li>
  <li>安装选默认即可。</li>
  <li>验证安装：
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git <span class="nt">--version</span>
</code></pre></div>    </div>
    <p>有版本号就说明成功。</p>
  </li>
</ol>

<h3 id="12-macos">1.2 macOS</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>git
git <span class="nt">--version</span>
</code></pre></div></div>

<h3 id="13-linux以-ubuntu-为例">1.3 Linux（以 Ubuntu 为例）</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt-get update
<span class="nb">sudo </span>apt-get <span class="nb">install </span>git
git <span class="nt">--version</span>
</code></pre></div></div>

<hr />

<h2 id="2-基础配置">2. 基础配置</h2>

<p>我只记两行：</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config <span class="nt">--global</span> user.name <span class="s2">"你的名字"</span>
git config <span class="nt">--global</span> user.email <span class="s2">"你的邮箱"</span>
</code></pre></div></div>

<p>看当前配置：</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config <span class="nt">--list</span>
</code></pre></div></div>

<hr />

<h2 id="3-基本概念速记">3. 基本概念（速记）</h2>

<ul>
  <li><strong>仓库</strong>：项目目录 + 历史记录</li>
  <li><strong>暂存区</strong>：待提交的缓冲区</li>
  <li><strong>提交</strong>：一次快照</li>
  <li><strong>分支</strong>：并行线路（通常 <code class="language-plaintext highlighter-rouge">main</code>/<code class="language-plaintext highlighter-rouge">master</code>）</li>
</ul>

<hr />

<h2 id="4-常用命令">4. 常用命令</h2>

<h3 id="41-初始化仓库">4.1 初始化仓库</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git init
</code></pre></div></div>

<h3 id="42-克隆仓库">4.2 克隆仓库</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone &lt;仓库地址&gt;
</code></pre></div></div>
<p>自定义目录名：</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone &lt;仓库名称&gt; &lt;本地名称&gt;
</code></pre></div></div>

<h3 id="43-查看仓库状态">4.3 查看仓库状态</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git status
</code></pre></div></div>

<h3 id="44-添加到暂存区">4.4 添加到暂存区</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add &lt;文件名&gt;       <span class="c"># 添加指定文件</span>
git add <span class="nb">.</span>              <span class="c"># 添加所有修改的文件</span>
</code></pre></div></div>

<h3 id="45-提交更改">4.5 提交更改</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit <span class="nt">-m</span> <span class="s2">"提交信息"</span>
</code></pre></div></div>

<h3 id="46-查看日志">4.6 查看日志</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git log
</code></pre></div></div>

<h3 id="47-远程仓库操作">4.7 远程仓库操作</h3>
<ul>
  <li>添加远程：
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git remote add origin &lt;仓库地址&gt;
</code></pre></div>    </div>
  </li>
  <li>推送：
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git push origin &lt;分支名&gt;
</code></pre></div>    </div>
  </li>
  <li>拉取：
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git pull origin &lt;分支名&gt;
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="48-分支操作">4.8 分支操作</h3>
<ul>
  <li>新建：
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch &lt;分支名&gt;
</code></pre></div>    </div>
  </li>
  <li>切换：
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout &lt;分支名&gt;
</code></pre></div>    </div>
  </li>
  <li>合并：
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git merge &lt;分支名&gt;
</code></pre></div>    </div>
  </li>
</ul>

<hr />

<h2 id="5-基本工作流程">5. 基本工作流程</h2>

<ol>
  <li>初始化或克隆</li>
  <li>修改文件</li>
  <li><code class="language-plaintext highlighter-rouge">git add &lt;文件名&gt;</code></li>
  <li><code class="language-plaintext highlighter-rouge">git commit -m "提交信息"</code></li>
  <li>需要同步就 <code class="language-plaintext highlighter-rouge">git push origin &lt;分支名&gt;</code></li>
</ol>

<hr />

<h2 id="6-其他常用命令">6. 其他常用命令</h2>

<h3 id="61-查看差异">6.1 查看差异</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git diff
git diff <span class="nt">--cached</span>
</code></pre></div></div>

<h3 id="62-回退操作">6.2 回退操作</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 回退到上一个提交（保留改动）</span>
 git reset <span class="nt">--soft</span> HEAD^

<span class="c"># 回退并丢弃改动（确认不需要）</span>
 git reset <span class="nt">--hard</span> HEAD^
</code></pre></div></div>

<h3 id="63-删除文件">6.3 删除文件</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git <span class="nb">rm</span> &lt;文件名&gt;
git commit <span class="nt">-m</span> <span class="s2">"删除文件"</span>
</code></pre></div></div>

<hr />

<h2 id="7-连接-github-等代码托管平台">7. 连接 GitHub 等代码托管平台</h2>

<h3 id="71-创建-github-账号">7.1 创建 GitHub 账号</h3>
<p>先注册：<a href="https://github.com/">GitHub 官网</a>。</p>

<h3 id="72-生成并配置-ssh-密钥">7.2 生成并配置 SSH 密钥</h3>

<h4 id="721-生成-ssh-密钥">7.2.1 生成 SSH 密钥</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen <span class="nt">-t</span> rsa <span class="nt">-b</span> 4096 <span class="nt">-C</span> <span class="s2">"your_email@example.com"</span>
</code></pre></div></div>
<p>按提示存储到 <code class="language-plaintext highlighter-rouge">~/.ssh/</code>（默认即可），可设置密码或留空。</p>

<p>生成文件：</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">id_ed25519</code>: 私钥</li>
  <li><code class="language-plaintext highlighter-rouge">id_ed25519.pub</code>: 公钥</li>
</ul>

<h4 id="722-添加到-ssh-代理">7.2.2 添加到 SSH 代理</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>ssh-agent <span class="nt">-s</span><span class="si">)</span><span class="s2">"</span>
ssh-add ~/.ssh/id_rsa
</code></pre></div></div>

<h4 id="723-添加到-github">7.2.3 添加到 GitHub</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> ~/.ssh/id_rsa.pub
</code></pre></div></div>
<p>复制内容 → <strong>Settings</strong> → <strong>SSH and GPG keys</strong> → <strong>New SSH key</strong>。</p>

<h4 id="724-测试连接">7.2.4 测试连接</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh <span class="nt">-T</span> git@github.com
</code></pre></div></div>
<p>看到 “Hi username! …” 就说明成功。</p>

<h3 id="73-绑定远程仓库">7.3 绑定远程仓库</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git remote add origin git@github.com:username/repository.git
git remote <span class="nt">-v</span>
</code></pre></div></div>

<h3 id="74-推送到-github">7.4 推送到 GitHub</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git push <span class="nt">-u</span> origin main
</code></pre></div></div>
<p>默认分支是 <code class="language-plaintext highlighter-rouge">master</code> 就改成 <code class="language-plaintext highlighter-rouge">master</code>。</p>

<p>后续同步：</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"更新信息"</span>
git push origin main
</code></pre></div></div>

<h3 id="75-克隆仓库到本地">7.5 克隆仓库到本地</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone git@github.com:username/repository.git
</code></pre></div></div>

<h3 id="76-设置全局-github-信息可选">7.6 设置全局 GitHub 信息（可选）</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config <span class="nt">--global</span> user.name <span class="s2">"你的GitHub用户名"</span>
git config <span class="nt">--global</span> user.email <span class="s2">"你的GitHub邮箱"</span>
</code></pre></div></div>

<h3 id="77-windows-额外配置">7.7 Windows 额外配置</h3>
<p>如果用 Git Bash 或 PowerShell，注意 <code class="language-plaintext highlighter-rouge">HOME</code> 环境变量和 <code class="language-plaintext highlighter-rouge">~/.ssh</code> 路径正确，避免找不到密钥。</p>]]></content><author><name></name></author><category term="notes" /><category term="toold" /><summary type="html"><![CDATA[这是一份我自己的 Git 笔记版教程：内容完整，但语气更像备忘。 1. 安装 Git 1.1 Windows 下载：Git for Windows。 安装选默认即可。 验证安装： git --version 有版本号就说明成功。 1.2 macOS brew install git git --version 1.3 Linux（以 Ubuntu 为例） sudo apt-get update sudo apt-get install git git --version 2. 基础配置 我只记两行： git config --global user.name "你的名字" git config --global user.email "你的邮箱" 看当前配置： git config --list 3. 基本概念（速记） 仓库：项目目录 + 历史记录 暂存区：待提交的缓冲区 提交：一次快照 分支：并行线路（通常 main/master） 4. 常用命令 4.1 初始化仓库 git init 4.2 克隆仓库 git clone &lt;仓库地址&gt; 自定义目录名： git clone &lt;仓库名称&gt; &lt;本地名称&gt; 4.3 查看仓库状态 git status 4.4 添加到暂存区 git add &lt;文件名&gt; # 添加指定文件 git add . # 添加所有修改的文件 4.5 提交更改 git commit -m "提交信息" 4.6 查看日志 git log 4.7 远程仓库操作 添加远程： git remote add origin &lt;仓库地址&gt; 推送： git push origin &lt;分支名&gt; 拉取： git pull origin &lt;分支名&gt; 4.8 分支操作 新建： git branch &lt;分支名&gt; 切换： git checkout &lt;分支名&gt; 合并： git merge &lt;分支名&gt; 5. 基本工作流程 初始化或克隆 修改文件 git add &lt;文件名&gt; git commit -m "提交信息" 需要同步就 git push origin &lt;分支名&gt; 6. 其他常用命令 6.1 查看差异 git diff git diff --cached 6.2 回退操作 # 回退到上一个提交（保留改动） git reset --soft HEAD^ # 回退并丢弃改动（确认不需要） git reset --hard HEAD^ 6.3 删除文件 git rm &lt;文件名&gt; git commit -m "删除文件" 7. 连接 GitHub 等代码托管平台 7.1 创建 GitHub 账号 先注册：GitHub 官网。 7.2 生成并配置 SSH 密钥 7.2.1 生成 SSH 密钥 ssh-keygen -t rsa -b 4096 -C "your_email@example.com" 按提示存储到 ~/.ssh/（默认即可），可设置密码或留空。 生成文件： id_ed25519: 私钥 id_ed25519.pub: 公钥 7.2.2 添加到 SSH 代理 eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_rsa 7.2.3 添加到 GitHub cat ~/.ssh/id_rsa.pub 复制内容 → Settings → SSH and GPG keys → New SSH key。 7.2.4 测试连接 ssh -T git@github.com 看到 “Hi username! …” 就说明成功。 7.3 绑定远程仓库 git remote add origin git@github.com:username/repository.git git remote -v 7.4 推送到 GitHub git push -u origin main 默认分支是 master 就改成 master。 后续同步： git add . git commit -m "更新信息" git push origin main 7.5 克隆仓库到本地 git clone git@github.com:username/repository.git 7.6 设置全局 GitHub 信息（可选） git config --global user.name "你的GitHub用户名" git config --global user.email "你的GitHub邮箱" 7.7 Windows 额外配置 如果用 Git Bash 或 PowerShell，注意 HOME 环境变量和 ~/.ssh 路径正确，避免找不到密钥。]]></summary></entry><entry><title type="html">Minio</title><link href="https://right202209.github.io/blog/Minio/" rel="alternate" type="text/html" title="Minio" /><published>2024-08-24T00:00:00+00:00</published><updated>2024-08-24T00:00:00+00:00</updated><id>https://right202209.github.io/blog/Minio</id><content type="html" xml:base="https://right202209.github.io/blog/Minio/"><![CDATA[<p>一份Git的基础使用教程，包括MinIO的安装、使用、常用命令。</p>

<p>Github <a href="https://github.com/minio/minio">github.com/minio/minio</a></p>

<p>官网 <a href="https://www.minio.org.cn">MinIO</a></p>

<h2 id="部署与安装"><strong>部署与安装</strong></h2>

<h3 id="docker安装"><strong>Docker安装</strong></h3>

<p>运行以下命令以使用临时数据卷将 MinIO 的最新稳定映像作为容器运行：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker pull minio/minio  
docker run <span class="nt">-d</span> <span class="nt">-p</span> 9000:9000 <span class="nt">--name</span><span class="o">=</span>minio <span class="nt">--restart</span><span class="o">=</span>always <span class="nt">-e</span> <span class="s2">"MINIO_ROOT_USER=minioadmin"</span> <span class="nt">-e</span> <span class="s2">"MINIO_ROOT_PASSWORD=minioadmin"</span> <span class="nt">-v</span> /home/data:/data <span class="nt">-v</span> /home/config:/root/.minio  minio/minio server /data <span class="nt">--console-address</span> <span class="s2">":9000"</span> <span class="nt">--address</span> <span class="s2">":9090"</span>
 
 <span class="nt">-d</span> 后台运行容器
 <span class="nt">--name</span> 为容器名称
 <span class="nt">--restart</span> docker重启或者开启时自动启动镜像
 <span class="nt">-p</span> 端口映射，宿主机端口:容器端口 访问9010，映射到9000端口
 <span class="nt">-e</span> 设置Minio的ACCESS_KEY和SECRET_KEY
 <span class="nt">-v</span> 挂载  宿主机目录:容器内目录。
</code></pre></div></div>

<p>MinIO 部署开始使用凭据 <code class="language-plaintext highlighter-rouge">minioadmin:minioadmin</code>。可以使用 MinIO 控制台测试部署，嵌入式内置于 MinIO 服务器的对象浏览器。将主机上运行的 Web 浏览器指向 http://127.0.0.1:9000 并使用根凭据。可以使用浏览器来创建桶、上传对象以及浏览 MinIO 服务器的内容。</p>

<h3 id="linux安装"><strong>Linux安装</strong></h3>

<p>使用以下命令在运行 64 位 Intel/AMD 架构的 Linux 主机上运行独立的 MinIO 服务器。将<code class="language-plaintext highlighter-rouge">/data</code> 替换为您希望 MinIO 存储数据的驱动器或目录的路径。</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget http://dl.minio.org.cn/server/minio/release/linux-amd64/minio
<span class="nb">chmod</span> +x minio
./minio server /data
</code></pre></div></div>

<p>将<code class="language-plaintext highlighter-rouge">/data</code> 替换为您希望 MinIO 存储数据的驱动器或目录的路径。</p>
<h3 id="windows"><strong>Windows</strong></h3>

<p><a href="https://dl.minio.io/server/minio/release/windows-amd64/minio.exe">服务端下载</a>
<a href="https://dl.minio.io/client/mc/release/windows-amd64/mc.exe">客户端下载</a></p>

<p>使用以下命令在 Windows 主机上运行独立的 MinIO 服务器。将 <code class="language-plaintext highlighter-rouge">C:\</code> 替换为希望 MinIO 存储数据的驱动器或目录路径。将终端或 PowerShell 目录切换到 <code class="language-plaintext highlighter-rouge">minio.exe</code> 所在位置，或将该目录加入系统 <code class="language-plaintext highlighter-rouge">$PATH</code>：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minio.exe server C:\
</code></pre></div></div>
<p>MinIO 部署开始使用默认的 root 凭据 <code class="language-plaintext highlighter-rouge">minioadmin:minioadmin</code>。可以使用 MinIO 控制台测试部署，这是一个内置在 MinIO 服务器中的基于 Web 的嵌入式对象浏览器。将主机上运行的 Web 浏览器指向 http://127.0.0.1:9000 并使用 root 凭据登录。使用浏览器来创建桶、上传对象以及浏览 MinIO 服务器的内容。</p>
<h2 id="使用"><strong>使用</strong></h2>
<h4 id="使用命令行工具">使用命令行工具</h4>
<p>MinIO 提供了命令行工具 mc，可以方便地管理 MinIO 服务器。可以使用 mc 命令来创建、删除、上传、下载文件等操作。
列出存储桶</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">ls</span> &lt;<span class="nb">alias</span><span class="o">&gt;</span>
</code></pre></div></div>
<p>这会列出指定 MinIO 服务器上的所有存储桶。
创建存储桶</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc mb &lt;alias&gt;/&lt;bucket_name&gt;
</code></pre></div></div>
<p>这会在指定 MinIO 服务器上创建一个新的存储桶。
上传文件</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc <span class="nb">cp</span> &lt;file_path&gt; &lt;<span class="nb">alias</span><span class="o">&gt;</span>/&lt;bucket_name&gt;
</code></pre></div></div>
<p>这会将本地文件上传到指定的 MinIO 存储桶中。
下载文件</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc <span class="nb">cp</span> &lt;<span class="nb">alias</span><span class="o">&gt;</span>/&lt;bucket_name&gt;/&lt;file_name&gt; &lt;local_file_path&gt;
</code></pre></div></div>
<p>这会将 MinIO 存储桶中的文件下载到本地。
复制对象</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc <span class="nb">cp</span> &lt;<span class="nb">source</span><span class="o">&gt;</span> &lt;target&gt;
</code></pre></div></div>
<p>这会复制对象从一个位置到另一个位置，可以是存储桶内的对象或不同存储桶间的对象。
移动对象</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc <span class="nb">mv</span> &lt;<span class="nb">source</span><span class="o">&gt;</span> &lt;target&gt;
</code></pre></div></div>
<p>这会移动对象从一个位置到另一个位置，与复制不同的是，移动后源位置的对象将被删除。
删除对象</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc <span class="nb">rm</span> &lt;<span class="nb">alias</span><span class="o">&gt;</span>/&lt;bucket_name&gt;/&lt;object_name&gt;
</code></pre></div></div>
<p>这会删除指定的对象。
删除存储桶</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc rb &lt;<span class="nb">alias</span><span class="o">&gt;</span>/&lt;bucket_name&gt;
</code></pre></div></div>
<p>这会删除指定的存储桶及其中的所有对象。</p>]]></content><author><name></name></author><category term="notes" /><category term="tools" /><summary type="html"><![CDATA[一份Git的基础使用教程，包括MinIO的安装、使用、常用命令。 Github github.com/minio/minio 官网 MinIO 部署与安装 Docker安装 运行以下命令以使用临时数据卷将 MinIO 的最新稳定映像作为容器运行： docker pull minio/minio docker run -d -p 9000:9000 --name=minio --restart=always -e "MINIO_ROOT_USER=minioadmin" -e "MINIO_ROOT_PASSWORD=minioadmin" -v /home/data:/data -v /home/config:/root/.minio minio/minio server /data --console-address ":9000" --address ":9090" -d 后台运行容器 --name 为容器名称 --restart docker重启或者开启时自动启动镜像 -p 端口映射，宿主机端口:容器端口 访问9010，映射到9000端口 -e 设置Minio的ACCESS_KEY和SECRET_KEY -v 挂载 宿主机目录:容器内目录。 MinIO 部署开始使用凭据 minioadmin:minioadmin。可以使用 MinIO 控制台测试部署，嵌入式内置于 MinIO 服务器的对象浏览器。将主机上运行的 Web 浏览器指向 http://127.0.0.1:9000 并使用根凭据。可以使用浏览器来创建桶、上传对象以及浏览 MinIO 服务器的内容。 Linux安装 使用以下命令在运行 64 位 Intel/AMD 架构的 Linux 主机上运行独立的 MinIO 服务器。将/data 替换为您希望 MinIO 存储数据的驱动器或目录的路径。 wget http://dl.minio.org.cn/server/minio/release/linux-amd64/minio chmod +x minio ./minio server /data 将/data 替换为您希望 MinIO 存储数据的驱动器或目录的路径。 Windows 服务端下载 客户端下载 使用以下命令在 Windows 主机上运行独立的 MinIO 服务器。将 C:\ 替换为希望 MinIO 存储数据的驱动器或目录路径。将终端或 PowerShell 目录切换到 minio.exe 所在位置，或将该目录加入系统 $PATH： minio.exe server C:\ MinIO 部署开始使用默认的 root 凭据 minioadmin:minioadmin。可以使用 MinIO 控制台测试部署，这是一个内置在 MinIO 服务器中的基于 Web 的嵌入式对象浏览器。将主机上运行的 Web 浏览器指向 http://127.0.0.1:9000 并使用 root 凭据登录。使用浏览器来创建桶、上传对象以及浏览 MinIO 服务器的内容。 使用 使用命令行工具 MinIO 提供了命令行工具 mc，可以方便地管理 MinIO 服务器。可以使用 mc 命令来创建、删除、上传、下载文件等操作。 列出存储桶 ls &lt;alias&gt; 这会列出指定 MinIO 服务器上的所有存储桶。 创建存储桶 mc mb &lt;alias&gt;/&lt;bucket_name&gt; 这会在指定 MinIO 服务器上创建一个新的存储桶。 上传文件 mc cp &lt;file_path&gt; &lt;alias&gt;/&lt;bucket_name&gt; 这会将本地文件上传到指定的 MinIO 存储桶中。 下载文件 mc cp &lt;alias&gt;/&lt;bucket_name&gt;/&lt;file_name&gt; &lt;local_file_path&gt; 这会将 MinIO 存储桶中的文件下载到本地。 复制对象 mc cp &lt;source&gt; &lt;target&gt; 这会复制对象从一个位置到另一个位置，可以是存储桶内的对象或不同存储桶间的对象。 移动对象 mc mv &lt;source&gt; &lt;target&gt; 这会移动对象从一个位置到另一个位置，与复制不同的是，移动后源位置的对象将被删除。 删除对象 mc rm &lt;alias&gt;/&lt;bucket_name&gt;/&lt;object_name&gt; 这会删除指定的对象。 删除存储桶 mc rb &lt;alias&gt;/&lt;bucket_name&gt; 这会删除指定的存储桶及其中的所有对象。]]></summary></entry><entry><title type="html">数据库</title><link href="https://right202209.github.io/blog/databases/" rel="alternate" type="text/html" title="数据库" /><published>2024-02-08T00:00:00+00:00</published><updated>2024-02-08T00:00:00+00:00</updated><id>https://right202209.github.io/blog/databases</id><content type="html" xml:base="https://right202209.github.io/blog/databases/"><![CDATA[<p>数据库原理主要内容</p>

<h2 id="1-数据库是什么">1. 数据库是什么？</h2>

<p>数据库是一个组织数据的集合，可供快速访问、管理和更新。它是应用程序的基础，用于存储和检索数据。</p>

<p>数据库是一个组织数据的集合，可供快速访问、管理和更新的系统。它是一个电子化的数据存储系统，旨在有效地存储和检索大量的数据。数据库系统能够存储各种类型的数据，包括文字、数字、图像、音频和视频等，以及它们之间的关系。通过使用数据库，用户可以轻松地进行数据的添加、删除、修改和查询，以满足各种应用程序和业务需求。（以下以MySQL为栗子）</p>

<h2 id="2-数据库的基本原则">2. 数据库的基本原则</h2>

<ul>
  <li>
    <p><strong>数据唯一性：</strong> 每条数据都应该有一个唯一的标识符，例如主键。</p>

    <ol>
      <li>
        <p><strong>主键约束（Primary Key Constraint）：</strong> 在关系型数据库中，可以通过定义一个主键来确保数据的唯一性。主键是一列或一组列，其值在整个表中必须唯一。通过将主键约束应用于表中的一个或多个列，可以防止重复的数据记录。</p>

        <p>​		创建一个包含主键约束的表</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 创建一个学生表（Student），包含学生的学号、姓名和年龄信息，其中学号为主键</span>
     
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">Student</span> <span class="p">(</span>
    <span class="n">student_id</span> <span class="nb">INT</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span> <span class="c1">-- 学号作为主键</span>
    <span class="n">name</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span>
    <span class="n">age</span> <span class="nb">INT</span>
<span class="p">);</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p><strong>唯一约束（Unique Constraint）：</strong> 除了主键之外，还可以使用唯一约束来保证数据的唯一性。唯一约束要求某一列或一组列中的值在表中是唯一的，但不要求其成为主键。</p>

        <p>sqlCopy code</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 创建一个用户表（User），包含用户名和电子邮件地址，要求用户名和电子邮件地址都是唯一的 </span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="k">User</span> <span class="p">(</span>    <span class="n">user_id</span> <span class="nb">INT</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="n">AUTO_INCREMENT</span><span class="p">,</span>    <span class="n">username</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">50</span><span class="p">)</span> <span class="k">UNIQUE</span><span class="p">,</span> <span class="c1">-- 用户名必须唯一    </span>
<span class="n">email</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span> <span class="k">UNIQUE</span> <span class="c1">-- 电子邮件地址必须唯一 );</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p><strong>索引（Index）：</strong> 在数据库中创建索引可以提高数据的检索效率，同时也可以帮助确保数据的唯一性。通过在列上创建唯一索引，可以强制该列中的值保持唯一。</p>

        <p>​		创建一个索引：</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 在一个名为 students 的表中，对 name 列创建一个索引</span>
<span class="k">CREATE</span> <span class="k">INDEX</span> <span class="n">idx_name</span> <span class="k">ON</span> <span class="n">students</span> <span class="p">(</span><span class="n">name</span><span class="p">);</span>
</code></pre></div>        </div>

        <p>在上面的示例中，<code class="language-plaintext highlighter-rouge">idx_name</code> 是索引的名称，<code class="language-plaintext highlighter-rouge">students</code> 是表的名称，<code class="language-plaintext highlighter-rouge">name</code> 是要创建索引的列名。</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>数据完整性：</strong> 数据应该保持准确和完整，不应该存在不一致或缺失的数据。</p>

    <ol>
      <li><strong>实体完整性（Entity Integrity）：</strong> 实体完整性确保每个表中的行都具有唯一的标识符，通常是一个主键。这意味着每个表中的每行都必须具有一个主键值，并且主键值不能是空值或重复的。通过实体完整性约束，防止了表中的行缺失主键值或存在重复的行。</li>
      <li><strong>域完整性（Domain Integrity）：</strong> 域完整性确保数据库中的数据符合预定义的规范和范围。它包括数据类型的限制、取值范围的约束、格式要求等。例如，一个字段的数据类型为整数，那么它就不能存储非整数类型的值；又如，一个字段的取值范围限定在特定范围内。</li>
      <li><strong>引用完整性（Referential Integrity）：</strong> 引用完整性确保数据库中的引用关系保持一致和有效。在关系数据库中，引用完整性通常通过外键约束实现。外键约束指定了一个表中的列（外键），它引用了另一个表中的主键。引用完整性要求在外键引用的表中，对应的主键值必须存在，或者必须为 NULL（如果允许空值）。这样可以确保引用关系的有效性，防止出现无效引用或孤立的数据。</li>
      <li><strong>用户定义的完整性规则（User-defined Integrity Rules）：</strong> 在某些情况下，数据库管理员可能会定义特定的完整性规则，以确保数据满足特定的业务规则或约束条件。这些规则可以通过触发器（Triggers）、存储过程（Stored Procedures）等方式来实现。</li>
    </ol>
  </li>
  <li>
    <p><strong>数据一致性：</strong> 数据库中的数据应该保持一致性，即不同的数据之间的关联关系应该得到维护。</p>

    <ol>
      <li><strong>实体间的一致性：</strong> 数据库中的不同实体之间的关系应该得到维护。例如，在关系型数据库中，表之间的关联关系应该保持一致，确保相关数据的完整性和正确性。</li>
      <li><strong>事务一致性：</strong> 事务是数据库操作的一个基本单位，它应该保证数据库从一个一致状态转移到另一个一致状态。数据库管理系统通过实现事务的原子性、一致性、隔离性和持久性（ACID属性）来确保事务的一致性。</li>
      <li><strong>索引和约束的一致性：</strong> 数据库中的索引和约束应该与数据的实际状态保持一致。例如，如果一个表中的数据发生了变化，相关的索引和约束应该及时更新，以反映最新的数据状态。</li>
      <li><strong>数据更新的一致性：</strong> 当数据库中的数据发生变化时，应该保证相关的数据更新是一致的和正确的。这包括在数据插入、更新或删除操作中，保证数据的完整性、准确性和有效性。</li>
      <li><strong>复制和分布式数据的一致性：</strong> 在分布式数据库系统中，数据的复制和分布可能导致数据副本之间的不一致性。因此，数据库管理系统必须实现复制和分布式算法，以确保数据的一致性和同步性。</li>
    </ol>
  </li>
  <li>
    <p><strong>数据可恢复性：</strong> 数据库应该具备恢复数据的能力，以应对故障或错误。</p>

    <ol>
      <li><strong>备份和恢复策略：</strong> 数据库管理系统应该实施定期备份数据库的策略，以确保数据的安全性和可恢复性。备份数据应该存储在安全的位置，并且能够快速恢复数据库到之前的状态。</li>
      <li><strong>日志记录：</strong> 数据库系统应该记录所有的数据库操作和事务，以便在需要时进行恢复。事务日志记录了数据库中发生的所有变化，可以用来恢复数据库到一个一致的状态。</li>
      <li><strong>事务管理：</strong> 数据库管理系统应该支持事务的原子性、一致性、隔离性和持久性（ACID属性）。当事务执行失败或中断时，数据库系统应该能够回滚事务并保持数据库的一致性。</li>
      <li><strong>灾难恢复：</strong> 数据库管理系统应该具备灾难恢复的能力，以应对硬件故障、自然灾害或人为破坏等情况。灾难恢复计划应该包括备份数据的存储位置、紧急恢复过程和灾难恢复团队的角色和责任。</li>
      <li><strong>故障转移和高可用性：</strong> 数据库系统可以通过故障转移和高可用性技术来提高数据的可恢复性。这包括使用备用服务器、集群和自动故障检测和恢复机制等。</li>
    </ol>
  </li>
</ul>

<ol>
  <li>数据唯一性：每条数据都应该有一个唯一的标识符，通常是一个主键。这确保了每条数据在数据库中的唯一性，避免了重复数据的存在。</li>
  <li>数据完整性：数据应该保持准确和完整，不应该存在不一致或缺失的数据。这可以通过定义数据类型、约束和规范来实现，确保数据在插入、更新和删除过程中保持完整性。</li>
  <li>数据一致性：数据库中的数据应该保持一致性，即不同的数据之间的关联关系应该得到维护。例如，在关系型数据库中，外键约束可以用来维护表之间的关系，确保数据的一致性。</li>
  <li>数据可恢复性：数据库应该具备恢复数据的能力，以应对故障、错误或意外事件。这包括定期备份数据库、实施事务处理和日志记录，以确保在发生故障时能够恢复数据到一致的状态。</li>
  <li>数据安全性：数据库应该保护数据的安全性，防止未经授权的访问、修改或删除数据。这包括实施访问控制、加密数据、审计和监控数据库活动等措施，以保护数据免受恶意攻击和意外泄露的风险。</li>
</ol>

<h2 id="3-数据库模型">3. 数据库模型</h2>

<p>数据库模型定义了数据在数据库中的组织方式。常见的数据库模型包括：</p>

<ol>
  <li>
    <p><strong>层次模型（Hierarchical Model）：</strong> 层次模型使用树形结构来组织数据，其中每个节点可以有一个或多个子节点，但只能有一个父节点。这种模型适合描述具有明确定义的父子关系的数据，例如组织结构和文件系统。</p>

    <ol>
      <li>
        <p><strong>父子关系：</strong> 在层次模型中，每个数据元素都与其他元素之间建立了明确的父子关系。父节点是子节点的直接上级，而子节点是父节点的直接下级。</p>
      </li>
      <li>
        <p><strong>根节点：</strong> 根节点是层次结构的顶层节点，它不具有父节点。</p>
      </li>
      <li>
        <p><strong>分支节点：</strong> 分支节点是除了根节点之外的其他节点，它们既可以有父节点也可以有子节点。</p>
      </li>
      <li>
        <p><strong>叶子节点：</strong> 叶子节点是没有子节点的节点，它们位于层次结构的末端。</p>
      </li>
      <li>
        <p><strong>路径：</strong> 路径是从根节点到任意节点的一系列相连的节点。</p>

        <p>​		使用递归关系来构建层次模型：</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 创建一个名为 Employee 的表，用于存储员工信息，并实现层次模型</span>
      
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">Employee</span> <span class="p">(</span>
    <span class="n">emp_id</span> <span class="nb">INT</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span>
    <span class="n">emp_name</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">100</span><span class="p">),</span>
    <span class="n">manager_id</span> <span class="nb">INT</span><span class="p">,</span> <span class="c1">-- 管理者的员工ID</span>
    <span class="k">FOREIGN</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">manager_id</span><span class="p">)</span> <span class="k">REFERENCES</span> <span class="n">Employee</span><span class="p">(</span><span class="n">emp_id</span><span class="p">)</span> <span class="c1">-- 管理者ID是对应员工表的员工ID</span>
<span class="p">);</span>
</code></pre></div>        </div>

        <p>在上面的示例中，<code class="language-plaintext highlighter-rouge">Employee</code> 表包含了员工的信息，其中包括员工ID (<code class="language-plaintext highlighter-rouge">emp_id</code>)、员工姓名 (<code class="language-plaintext highlighter-rouge">emp_name</code>) 和其直接上级的员工ID (<code class="language-plaintext highlighter-rouge">manager_id</code>)。<code class="language-plaintext highlighter-rouge">manager_id</code> 列是对应员工表的外键，它参考了自身的主键 <code class="language-plaintext highlighter-rouge">emp_id</code>，这样就可以构建员工与直接上级之间的层次关系。</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>网状模型（Network Model）：</strong> 网状模型是一种图形结构，其中数据元素可以具有多个父节点和多个子节点。这种模型允许更复杂的数据关系，但也更加复杂和难以理解，通常用于一些特定的应用场景。</p>

    <ol>
      <li>
        <p><strong>记录类型（Record Types）：</strong> 网状模型使用记录类型来描述数据的结构。每个记录类型都定义了一组属性，并且可以包含一个或多个记录实例。</p>
      </li>
      <li>
        <p><strong>集合类型（Set Types）：</strong> 集合类型用于描述记录类型之间的关系。一个集合类型可以包含多个记录类型，并且可以定义记录类型之间的连接和关系。</p>
      </li>
      <li>
        <p><strong>拓扑结构：</strong> 网状模型中的数据组织形式具有拓扑结构，其中节点之间的关系不仅限于父子关系，还可以是任意的连接关系。</p>
      </li>
      <li>
        <p><strong>指针（Pointers）：</strong> 在网状模型中，使用指针来表示记录之间的关系。一个记录可以包含一个或多个指向其他记录的指针，从而形成网络结构。</p>
      </li>
      <li>
        <p><strong>数据访问路径：</strong> 在网状模型中，可以沿着指针定义的路径访问数据。与层次模型不同，网状模型允许多个路径访问同一个记录，提供了更大的灵活性和查询能力。</p>

        <p>下面是一个简单的示例，演示如何使用指针来构建一个简单的网状模型：</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 创建一个名为 Relationship 的表，用于存储实体之间的关系</span>
      
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">Relationship</span> <span class="p">(</span>
    <span class="n">entity_id1</span> <span class="nb">INT</span><span class="p">,</span>
    <span class="n">entity_id2</span> <span class="nb">INT</span><span class="p">,</span>
    <span class="n">relationship_type</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span>
    <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">entity_id1</span><span class="p">,</span> <span class="n">entity_id2</span><span class="p">),</span> <span class="c1">-- 将 entity_id1 和 entity_id2 作为复合主键</span>
    <span class="k">FOREIGN</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">entity_id1</span><span class="p">)</span> <span class="k">REFERENCES</span> <span class="n">Entity</span><span class="p">(</span><span class="n">entity_id</span><span class="p">),</span> <span class="c1">-- entity_id1 是对应实体表的实体ID</span>
    <span class="k">FOREIGN</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">entity_id2</span><span class="p">)</span> <span class="k">REFERENCES</span> <span class="n">Entity</span><span class="p">(</span><span class="n">entity_id</span><span class="p">)</span> <span class="c1">-- entity_id2 是对应实体表的实体ID</span>
<span class="p">);</span>
</code></pre></div>        </div>

        <p>在上面的示例中，<code class="language-plaintext highlighter-rouge">Relationship</code> 表包含了实体之间的关系，其中包括了 <code class="language-plaintext highlighter-rouge">entity_id1</code> 和 <code class="language-plaintext highlighter-rouge">entity_id2</code> 两个实体的ID，以及它们之间的关系类型 <code class="language-plaintext highlighter-rouge">relationship_type</code>。</p>

        <p><code class="language-plaintext highlighter-rouge">entity_id1</code> 和 <code class="language-plaintext highlighter-rouge">entity_id2</code> 列分别是对应实体表 <code class="language-plaintext highlighter-rouge">Entity</code> 的外键，它们参考了实体表中的实体ID。通过这种方式，可以在关系表中建立实体之间的多对多关系。</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>关系模型（Relational Model）：</strong> 关系模型是目前最广泛使用的数据库模型之一，它使用表格（或称为关系）来组织数据。每个表包含多个行（记录）和列（字段），其中每个字段具有唯一的名称和数据类型。关系模型通过主键和外键来定义表之间的关系，具有良好的结构化特性和简单的查询语言，例如结构化查询语言（SQL）。</p>

    <ol>
      <li><strong>表格（Table）：</strong> 关系模型中的数据被组织成表格的形式，每个表格也被称为关系（Relation）。每个表格由行（Records）和列（Fields）组成，每一行代表一个记录，每一列代表一个属性。</li>
      <li><strong>主键（Primary Key）：</strong> 每个表格都有一个或多个列组成的主键，主键的值在表格中是唯一的，并且不为空。主键用于唯一标识表格中的每条记录。</li>
      <li><strong>外键（Foreign Key）：</strong> 外键是一个表格中的列，它引用了另一个表格中的主键。外键用于建立表格之间的关系。</li>
      <li><strong>关系操作（Relational Operations）：</strong> 关系模型定义了一系列的操作，用于处理表格中的数据，包括选择（Select）、投影（Project）、连接（Join）、并集（Union）、差集（Difference）等。</li>
      <li><strong>数据完整性（Data Integrity）：</strong> 关系模型通过约束（Constraints）来保持数据的完整性，包括实体完整性、域完整性和引用完整性。</li>
      <li><strong>结构化查询语言（SQL）：</strong> 结构化查询语言是关系数据库管理系统中用于管理和查询数据的标准语言。它支持各种操作，包括数据查询、插入、更新和删除等。</li>
    </ol>

    <p>关系模型的优点包括：</p>

    <ul>
      <li>
        <p>结构化：关系模型提供了一种结构化的方式来组织和存储数据，使得数据更容易理解和管理。</p>
      </li>
      <li>
        <p>灵活性：关系模型的设计可以适应各种不同类型和规模的数据集，具有很高的灵活性。</p>
      </li>
      <li>
        <p>数据独立性：关系模型通过将数据和数据操作分离，实现了数据独立性，使得应用程序可以独立于数据存储的物理结构进行开发和维护。</p>

        <blockquote>
          <p>创建一个关系模型的表格：</p>
        </blockquote>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 创建一个名为 Students 的表格，用于存储学生信息
     
CREATE TABLE Students (
    student_id INT PRIMARY KEY,
    name VARCHAR(100),
    age INT,
    gender VARCHAR(10)
);
</code></pre></div>        </div>

        <blockquote>
          <p>在上面的示例中，<code class="language-plaintext highlighter-rouge">Students</code> 表格定义了学生的信息，包括学生ID (<code class="language-plaintext highlighter-rouge">student_id</code>)、姓名 (<code class="language-plaintext highlighter-rouge">name</code>)、年龄 (<code class="language-plaintext highlighter-rouge">age</code>) 和性别 (<code class="language-plaintext highlighter-rouge">gender</code>)。</p>
        </blockquote>

        <blockquote>
          <p>student_id<code class="language-plaintext highlighter-rouge"> 列被定义为主键 (</code>PRIMARY KEY`)，确保每个学生ID的唯一性。</p>
        </blockquote>

        <blockquote>
          <p>其列包括了学生的姓名、年龄和性别等属性。</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>面向对象模型（Object-Oriented Model）：</strong> 面向对象模型将数据组织为对象，每个对象具有属性和方法。这种模型适合于描述现实世界中的复杂对象和关系，例如物体、人员、事件等。</p>

    <ol>
      <li>
        <p><strong>对象（Object）：</strong> 在面向对象模型中，数据被组织成对象的形式。对象包含了数据（属性）和行为（方法）的集合，能够完整地描述现实世界中的实体。</p>
      </li>
      <li>
        <p><strong>类（Class）：</strong> 类是对象的模板，它定义了对象的属性和方法。类可以用来创建多个具有相似属性和行为的对象。</p>
      </li>
      <li>
        <p><strong>继承（Inheritance）：</strong> 继承是面向对象模型中的一个重要特性，它允许一个类从另一个类继承属性和方法。这样可以促进代码的重用和扩展，提高了系统的可维护性和可扩展性。</p>
      </li>
      <li>
        <p><strong>多态（Polymorphism）：</strong> 多态允许不同的对象对相同的消息做出不同的响应。这意味着可以通过统一的接口来处理不同类型的对象，从而提高了系统的灵活性和可扩展性。</p>
      </li>
      <li>
        <p><strong>封装（Encapsulation）：</strong> 封装是一种将数据和操作封装在一起的机制，使得对象的内部状态对外部是不可见的。这样可以防止数据的不合法访问和修改，提高了系统的安全性和健壮性。</p>

        <p>在关系型数据库中使用面向对象模型：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 创建一个名为 Person 的表格，用于存储人员信息
      
CREATE TABLE Person (
    person_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    date_of_birth DATE
);
      
-- 创建一个名为 Address 的表格，用于存储地址信息
      
CREATE TABLE Address (
    address_id INT PRIMARY KEY,
    street VARCHAR(100),
    city VARCHAR(50),
    state VARCHAR(50),
    zip_code VARCHAR(10)
);
      
-- 创建一个名为 PersonAddress 的表格，用于建立 Person 和 Address 之间的关联关系
      
CREATE TABLE PersonAddress (
    person_id INT,
    address_id INT,
    PRIMARY KEY (person_id, address_id),
    FOREIGN KEY (person_id) REFERENCES Person(person_id),
    FOREIGN KEY (address_id) REFERENCES Address(address_id)
);
</code></pre></div>        </div>

        <p>在上面的示例中，我们创建了三个表格：</p>

        <ol>
          <li><code class="language-plaintext highlighter-rouge">Person</code> 表格用于存储人员信息，包括 <code class="language-plaintext highlighter-rouge">person_id</code>、<code class="language-plaintext highlighter-rouge">first_name</code>、<code class="language-plaintext highlighter-rouge">last_name</code> 和 <code class="language-plaintext highlighter-rouge">date_of_birth</code> 等属性。</li>
          <li><code class="language-plaintext highlighter-rouge">Address</code> 表格用于存储地址信息，包括 <code class="language-plaintext highlighter-rouge">address_id</code>、<code class="language-plaintext highlighter-rouge">street</code>、<code class="language-plaintext highlighter-rouge">city</code>、<code class="language-plaintext highlighter-rouge">state</code> 和 <code class="language-plaintext highlighter-rouge">zip_code</code> 等属性。</li>
          <li><code class="language-plaintext highlighter-rouge">PersonAddress</code> 表格用于建立 <code class="language-plaintext highlighter-rouge">Person</code> 和 <code class="language-plaintext highlighter-rouge">Address</code> 之间的关联关系，它包含了 <code class="language-plaintext highlighter-rouge">person_id</code> 和 <code class="language-plaintext highlighter-rouge">address_id</code> 两个外键，分别参考了 <code class="language-plaintext highlighter-rouge">Person</code> 和 <code class="language-plaintext highlighter-rouge">Address</code> 表格中的主键。</li>
        </ol>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>文档模型（Document Model）：</strong> 文档模型将数据组织为文档（通常是JSON或XML格式），每个文档可以包含不同类型和结构的数据。这种模型适用于需要灵活处理和存储各种类型数据的场景，例如内容管理系统和大数据应用。</p>

    <ol>
      <li>
        <p><strong>文档（Document）：</strong> 文档是文档模型中的基本单位，它可以是一个JSON对象、XML文档或类似的数据结构。文档可以包含任意数量和类型的字段，具有很高的灵活性。</p>
      </li>
      <li>
        <p><strong>集合（Collection）：</strong> 文档通常被组织在集合中，类似于关系数据库中的表格。一个集合可以包含多个文档，每个文档可以具有不同的结构。</p>
      </li>
      <li>
        <p><strong>嵌套文档（Nested Documents）：</strong> 文档模型允许文档内部包含其他文档，形成嵌套的层次结构。这样可以更好地表示复杂的数据关系和嵌套结构。</p>
      </li>
      <li>
        <p><strong>灵活性：</strong> 文档模型具有很高的灵活性，可以存储各种类型和格式的数据，适用于处理半结构化和非结构化数据。</p>
      </li>
      <li>
        <p><strong>查询语言：</strong> 文档数据库通常提供了灵活和强大的查询语言，用于查询和操作文档数据。这些查询语言通常支持各种条件查询、投影、聚合和排序等操作。</p>

        <blockquote>
          <p>在 MongoDB 中使用文档模型存储数据：</p>
        </blockquote>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>javascriptCopy code// 在 MongoDB 中插入一个文档
      
db.students.insertOne({
    "student_id": 1001,
    "name": "John Doe",
    "age": 25,
    "courses": ["Math", "Science"],
    "address": {
        "street": "123 Main St",
        "city": "Anytown",
        "state": "CA",
        "zip": "12345"
    }
});
</code></pre></div>        </div>

        <p>在上面的示例中，我们向 MongoDB 中的 <code class="language-plaintext highlighter-rouge">students</code> 集合插入了一个文档。这个文档包含了学生的信息，包括学生ID (<code class="language-plaintext highlighter-rouge">student_id</code>)、姓名 (<code class="language-plaintext highlighter-rouge">name</code>)、年龄 (<code class="language-plaintext highlighter-rouge">age</code>)、所修课程 (<code class="language-plaintext highlighter-rouge">courses</code>) 和地址信息 (<code class="language-plaintext highlighter-rouge">address</code>)。<code class="language-plaintext highlighter-rouge">address</code> 字段是一个嵌套的文档，包含了街道、城市、州和邮编等信息。</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>列存储模型（Columnar Store Model）：</strong> 列存储模型将数据按列存储，而不是按行存储。这种模型适用于需要快速分析和聚合大量数据的场景，例如数据仓库和数据分析应用。</p>

    <ol>
      <li><strong>列存储：</strong> 在列存储模型中，数据按列组织存储在内存或磁盘中。这意味着一个表的每一列都被存储在一起，而不是将整个行存储在一起。这种存储方式使得查询可以只检索需要的列，从而提高了查询效率和性能。</li>
      <li><strong>压缩技术：</strong> 列存储模型通常使用压缩技术来减少存储空间和提高查询性能。由于列中的数据通常具有较高的数据重复性，因此可以使用压缩算法来减少存储空间并加快数据读取速度。</li>
      <li><strong>向量化处理：</strong> 列存储模型可以利用向量化处理技术来进行高效的数据操作。向量化处理允许一次性处理多个数据元素，从而提高了数据处理的速度和效率。</li>
      <li><strong>分区和分布式处理：</strong> 列存储模型通常支持数据分区和分布式处理，可以将数据分成多个分区并分布在不同的节点上进行存储和处理。这样可以提高系统的扩展性和容错性。</li>
      <li><strong>适用场景：</strong> 列存储模型适用于需要快速分析和聚合大量数据的场景，例如数据仓库、在线分析处理（OLAP）和数据分析应用程序。</li>
    </ol>

    <p>列存储模型的优点包括：</p>

    <ul>
      <li>
        <p>查询性能：由于列存储模型只检索需要的列，因此可以大大提高查询性能和响应速度。</p>
      </li>
      <li>
        <p>压缩效率：列存储模型可以通过压缩技术减少存储空间的使用，节省存储成本。</p>
      </li>
      <li>
        <p>分区和分布式处理：列存储模型支持数据分区和分布式处理，可以处理大规模数据并实现水平扩展。</p>

        <blockquote>
          <p>在 Apache HBase 中使用列存储模型存储数据：</p>
        </blockquote>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>javaCopy codeimport org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
     
public class HBaseExample {
     
    public static void main(String[] args) throws IOException {
        // 配置 HBase 连接
        org.apache.hadoop.conf.Configuration config = HBaseConfiguration.create();
        config.set("hbase.zookeeper.quorum", "localhost"); // 设置 ZooKeeper 地址
     
        // 建立 HBase 连接
        Connection connection = ConnectionFactory.createConnection(config);
     
        // 获取表格
        Table table = connection.getTable(TableName.valueOf("my_table"));
     
        // 创建一个 Put 对象，并指定行键
        Put put = new Put(Bytes.toBytes("row1"));
     
        // 添加列族和列
        put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("col1"), Bytes.toBytes("value1"));
        put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("col2"), Bytes.toBytes("value2"));
     
        // 插入数据
        table.put(put);
     
        // 关闭连接
        connection.close();
    }
}
</code></pre></div>        </div>

        <p>在上面的示例中，我们使用 Apache HBase 客户端 API 连接到 HBase，并向名为 <code class="language-plaintext highlighter-rouge">my_table</code> 的表格中插入了一行数据。</p>

        <p>这里我们采用了列存储模型的方式来存储数据。数据在 HBase 中是按列族（Column Family）存储的，每个列族包含一组相关的列。在插入数据时，我们使用 <code class="language-plaintext highlighter-rouge">addColumn</code> 方法来添加列族和列。在列存储模型中，列族通常在表格设计时静态地定义，而列则动态地添加。</p>
      </li>
    </ul>
  </li>
</ol>

<h2 id="4-sqlstructured-query-language">4. SQL（Structured Query Language）</h2>

<h3 id="sql-简介">SQL 简介</h3>

<p>SQL 是用于管理和查询数据库的标准语言。以下是一个简单的 SQL 查询示例：</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">students</span> <span class="k">WHERE</span> <span class="n">age</span> <span class="o">&gt;</span> <span class="mi">18</span><span class="p">;</span>
</code></pre></div></div>

<p>SQL（Structured Query Language）是一种专门用于管理关系型数据库系统的标准化查询语言。它允许用户执行各种操作，包括查询数据、插入新数据、更新现有数据、删除数据等。SQL是关系数据库管理系统（RDBMS）的核心语言，几乎所有主流的关系数据库管理系统都支持SQL。</p>

<p>以下是SQL的一些基本概念和常见操作：</p>

<ol>
  <li>
    <p><strong>DDL（数据定义语言）：</strong> DDL用于定义数据库的结构和模式。常见的DDL命令包括：</p>

    <ul>
      <li>
        <p><code class="language-plaintext highlighter-rouge">CREATE TABLE</code>：创建新表格。</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">ALTER TABLE</code>：修改现有表格的结构。</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">DROP TABLE</code>：删除表格。</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">CREATE INDEX</code>：创建索引。</p>

        <ol>
          <li>创建表格（CREATE TABLE）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeCREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    LastName VARCHAR(50),
    FirstName VARCHAR(50),
    BirthDate DATE,
    DepartmentID INT,
    FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID)
);
</code></pre></div>        </div>

        <ol>
          <li>修改表格（ALTER TABLE）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeALTER TABLE Employees
ADD Email VARCHAR(100);
</code></pre></div>        </div>

        <ol>
          <li>删除表格（DROP TABLE）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
DROP TABLE Employees;
</code></pre></div>        </div>

        <ol>
          <li>创建索引（CREATE INDEX）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
CREATE INDEX idx_lastname ON Employees(LastName);
</code></pre></div>        </div>

        <ol>
          <li>删除索引（DROP INDEX）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
DROP INDEX idx_lastname ON Employees;
</code></pre></div>        </div>

        <p>DDL</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>DML（数据操作语言）：</strong> DML用于管理数据库中的数据。常见的DML命令包括：</p>

    <ul>
      <li>
        <p><code class="language-plaintext highlighter-rouge">SELECT</code>：从数据库中检索数据。</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">INSERT INTO</code>：向表格中插入新数据。</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">UPDATE</code>：更新表格中的现有数据。</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">DELETE FROM</code>：从表格中删除数据。</p>

        <ol>
          <li>插入数据（INSERT INTO）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeINSERT INTO Employees (EmployeeID, LastName, FirstName, BirthDate, DepartmentID)
VALUES (1, 'Smith', 'John', '1990-05-25', 101);
</code></pre></div>        </div>

        <ol>
          <li>查询数据（SELECT）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeSELECT EmployeeID, LastName, FirstName
FROM Employees
WHERE DepartmentID = 101;
</code></pre></div>        </div>

        <ol>
          <li>更新数据（UPDATE）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeUPDATE Employees
SET DepartmentID = 102
WHERE LastName = 'Smith';
</code></pre></div>        </div>

        <ol>
          <li>删除数据（DELETE FROM）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeDELETE FROM Employees
WHERE EmployeeID = 1;
</code></pre></div>        </div>

        <p>DML</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>DCL（数据控制语言）：</strong> DCL用于控制数据库的访问权限和安全性。常见的DCL命令包括：</p>

    <ul>
      <li>
        <p><code class="language-plaintext highlighter-rouge">GRANT</code>：授予用户特定权限。</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">REVOKE</code>：收回用户的权限。</p>

        <p>以下是一些常见的DCL代码示例：</p>

        <ol>
          <li>授予权限（GRANT）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
GRANT SELECT, INSERT ON Employees TO user1;
</code></pre></div>        </div>

        <ol>
          <li>撤销权限（REVOKE）：</li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
REVOKE INSERT ON Employees FROM user1;
</code></pre></div>        </div>

        <p>DCL</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>数据查询：</strong> SQL的主要功能之一是查询数据库中的数据。通过使用<code class="language-plaintext highlighter-rouge">SELECT</code>语句，可以检索特定条件下的数据，进行筛选、排序和聚合等操作。</p>

    <ol>
      <li>
        <p><strong>选择数据表格：</strong> 首先，确定从哪些数据表格中检索数据。在关系数据库中，通常会有多个表格存储不同类型的数据。</p>
      </li>
      <li>
        <p><strong>编写查询语句：</strong> 使用查询语言（如SQL），编写查询语句以指定所需的数据。查询语句通常由 <code class="language-plaintext highlighter-rouge">SELECT</code> 语句组成，可以包含多个选项，如 <code class="language-plaintext highlighter-rouge">FROM</code>、<code class="language-plaintext highlighter-rouge">WHERE</code>、<code class="language-plaintext highlighter-rouge">ORDER BY</code>、<code class="language-plaintext highlighter-rouge">GROUP BY</code> 等，用于指定要检索的数据以及对数据的排序、筛选和分组等操作。</p>
      </li>
      <li>
        <p><strong>选择数据列：</strong> 在 <code class="language-plaintext highlighter-rouge">SELECT</code> 语句中，指定要检索的数据列。可以使用 <code class="language-plaintext highlighter-rouge">*</code> 通配符检索所有列，也可以列出要检索的特定列名。</p>
      </li>
      <li>
        <p><strong>设置检索条件：</strong> 使用 <code class="language-plaintext highlighter-rouge">WHERE</code> 子句指定数据检索的条件，以筛选符合特定条件的数据。条件可以是简单的比较操作，也可以是复杂的逻辑表达式。</p>
      </li>
      <li>
        <p><strong>排序数据：</strong> 使用 <code class="language-plaintext highlighter-rouge">ORDER BY</code> 子句对检索到的数据进行排序，可以按照一个或多个列进行升序或降序排列。</p>
      </li>
      <li>
        <p><strong>聚合数据：</strong> 使用聚合函数（如 <code class="language-plaintext highlighter-rouge">SUM</code>、<code class="language-plaintext highlighter-rouge">COUNT</code>、<code class="language-plaintext highlighter-rouge">AVG</code>、<code class="language-plaintext highlighter-rouge">MAX</code>、<code class="language-plaintext highlighter-rouge">MIN</code> 等）对数据进行统计和汇总。</p>
      </li>
      <li>
        <p><strong>分组数据：</strong> 使用 <code class="language-plaintext highlighter-rouge">GROUP BY</code> 子句对数据进行分组，通常与聚合函数一起使用，用于对分组后的数据进行统计和分析。</p>
      </li>
      <li>
        <p><strong>执行查询：</strong> 将编写好的查询语句提交给数据库管理系统执行，获取查询结果。</p>
      </li>
      <li>
        <p><strong>解释查询结果：</strong> 分析和解释查询结果，确保数据符合预期并满足查询要求。</p>

        <p>以下是一个简单的数据查询示例：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 从名为 Employees 的表中检索所有员工的姓氏和名字
SELECT LastName, FirstName
FROM Employees;
</code></pre></div>        </div>

        <p>这个查询语句从 Employees 表中选择了姓氏（LastName）和名字（FirstName）列的数据。</p>

        <p>另外，SELECT语句还可以进行更复杂的查询，如下所示：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 从名为 Orders 的表中检索订单数量大于100的顾客ID
SELECT CustomerID, COUNT(OrderID) AS OrderCount
FROM Orders
GROUP BY CustomerID
HAVING COUNT(OrderID) &gt; 100;
</code></pre></div>        </div>

        <p>这个查询语句从 Orders 表中选择了顾客ID（CustomerID），并对顾客ID进行分组，然后使用HAVING子句过滤出订单数量大于100的顾客ID。COUNT函数用于统计每个顾客ID的订单数量。</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>数据过滤和排序：</strong> SQL允许对检索到的数据进行过滤和排序，以便根据特定的条件选择所需的数据，并按照指定的顺序进行排列。</p>

    <ol>
      <li><strong>数据过滤：</strong> 数据过滤是根据特定的条件从数据库中选择符合条件的数据记录。常见的过滤操作使用 <code class="language-plaintext highlighter-rouge">WHERE</code> 子句来指定条件，只有满足条件的数据记录才会被检索出来。例如：</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
SELECT * FROM employees WHERE department = 'Sales';
</code></pre></div>    </div>

    <p>上面的查询语句将从名为 “employees” 的表中选择所有部门为 “Sales” 的员工记录。</p>

    <ol>
      <li><strong>数据排序：</strong> 数据排序是对查询结果按照指定的列或表达式进行排序，以便更容易地理解和分析数据。常见的排序操作使用 <code class="language-plaintext highlighter-rouge">ORDER BY</code> 子句来指定排序的列和排序顺序（升序或降序）。例如：</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
SELECT * FROM products ORDER BY price DESC;
</code></pre></div>    </div>

    <p>上面的查询语句将从名为 “products” 的表中选择所有产品记录，并按照价格从高到低的顺序对其进行排序。</p>

    <ol>
      <li><strong>组合过滤和排序：</strong> 可以将数据过滤和排序操作组合在一起，以获取满足特定条件并按照指定顺序排列的数据记录。例如：</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
SELECT * FROM customers WHERE city = 'New York' ORDER BY last_name;
</code></pre></div>    </div>

    <p>上面的查询语句将从名为 “customers” 的表中选择居住在纽约的客户记录，并按照客户姓氏的字母顺序对其进行排序。</p>

    <p>在 SELECT 查询中使用 WHERE 子句和 ORDER BY 子句：</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 从名为 Employees 的表中检索年龄大于等于 30 岁的员工，并按照姓氏进行升序排序
SELECT LastName, FirstName, Age
FROM Employees
WHERE Age &gt;= 30
ORDER BY LastName ASC;
</code></pre></div>    </div>

    <p>在上面的示例中，我们使用 WHERE 子句过滤了年龄大于等于 30 岁的员工，并使用 ORDER BY 子句按照姓氏（LastName）进行升序排序。ASC 关键字表示升序排序（默认情况下，ORDER BY 子句会按照升序排序）</p>
  </li>
  <li>
    <p><strong>数据聚合：</strong> SQL支持对数据进行聚合操作，如求和、计数、平均值、最大值和最小值等，以便进行统计和分析。</p>

    <ol>
      <li><strong>聚合函数：</strong> 数据聚合通常使用聚合函数来执行计算。常见的聚合函数包括：
        <ul>
          <li><code class="language-plaintext highlighter-rouge">COUNT()</code>：计算数据行的数量。</li>
          <li><code class="language-plaintext highlighter-rouge">SUM()</code>：计算数据列的总和。</li>
          <li><code class="language-plaintext highlighter-rouge">AVG()</code>：计算数据列的平均值。</li>
          <li><code class="language-plaintext highlighter-rouge">MAX()</code>：计算数据列的最大值。</li>
          <li><code class="language-plaintext highlighter-rouge">MIN()</code>：计算数据列的最小值。</li>
        </ul>
      </li>
      <li><strong>使用 GROUP BY 子句进行分组：</strong> 在执行聚合操作时，通常需要使用 <code class="language-plaintext highlighter-rouge">GROUP BY</code> 子句对数据进行分组。<code class="language-plaintext highlighter-rouge">GROUP BY</code> 子句将查询结果按照指定的列进行分组，然后对每个分组执行聚合函数计算。</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeSELECT department, COUNT(*) AS num_employees
FROM employees
GROUP BY department;
</code></pre></div>    </div>

    <p>上面的查询语句将从名为 “employees” 的表中按照部门对员工进行分组，并计算每个部门的员工数量。</p>

    <ol>
      <li><strong>使用 HAVING 子句进行条件筛选：</strong> 与 <code class="language-plaintext highlighter-rouge">WHERE</code> 子句类似，<code class="language-plaintext highlighter-rouge">HAVING</code> 子句用于对分组后的数据进行条件筛选。它通常用于筛选聚合结果中满足特定条件的数据组。</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeSELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) &gt; 50000;
</code></pre></div>    </div>

    <p>上面的查询语句将从名为 “employees” 的表中按部门分组，并计算每个部门的平均工资。然后，它将仅显示平均工资超过 50000 的部门。</p>

    <blockquote>
      <p>使用聚合函数进行数据聚合：</p>
    </blockquote>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 统计名为 Orders 的表中订单的总数
SELECT COUNT(*) AS TotalOrders
FROM Orders;
</code></pre></div>    </div>

    <blockquote>
      <p>上面的示例中，我们使用 COUNT(*) 函数统计了 Orders 表中的订单总数，并将结果存储在 TotalOrders 列中。</p>
    </blockquote>

    <blockquote>
      <p>另一个示例是计算销售总额的总和：</p>
    </blockquote>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 计算名为 Sales 的表中销售总额
SELECT SUM(SalesAmount) AS TotalSales
FROM Sales;
</code></pre></div>    </div>

    <blockquote>
      <p>在这个示例中，我们使用 SUM(SalesAmount) 函数计算了 Sales 表中所有销售金额的总和，并将结果存储在 TotalSales 列中。</p>
    </blockquote>
  </li>
  <li>
    <p><strong>连接操作：</strong> SQL允许在多个表格之间建立连接，以便检索相关联的数据。常见的连接操作包括内连接、外连接和交叉连接。</p>

    <p>在 SQL 中，连接操作通常使用 <code class="language-plaintext highlighter-rouge">JOIN</code> 关键字实现，有多种类型的连接可以使用，包括：</p>

    <ol>
      <li><strong>内连接（Inner Join）：</strong> 内连接返回两个表格中符合连接条件的行，即两个表格中的行必须具有相同的连接列值。</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeSELECT orders.order_id, customers.customer_name
FROM orders
INNER JOIN customers ON orders.customer_id = customers.customer_id;
</code></pre></div>    </div>

    <ol>
      <li><strong>左连接（Left Join）：</strong> 左连接返回左侧表格的所有行，以及与右侧表格中匹配的行。如果右侧表格中没有匹配的行，则返回 <code class="language-plaintext highlighter-rouge">NULL</code> 值。</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sql codeSELECT customers.customer_name, orders.order_id
FROM customers
LEFT JOIN orders ON customers.customer_id = orders.customer_id;
</code></pre></div>    </div>

    <ol>
      <li><strong>右连接（Right Join）：</strong> 右连接返回右侧表格的所有行，以及与左侧表格中匹配的行。如果左侧表格中没有匹配的行，则返回 <code class="language-plaintext highlighter-rouge">NULL</code> 值。</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeSELECT orders.order_id, customers.customer_name
FROM orders
RIGHT JOIN customers ON orders.customer_id = customers.customer_id;
</code></pre></div>    </div>

    <ol>
      <li><strong>全连接（Full Join）：</strong> 全连接返回左侧表格和右侧表格的所有行，如果某一侧表格中没有匹配的行，则返回 <code class="language-plaintext highlighter-rouge">NULL</code> 值。</li>
    </ol>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy codeSELECT customers.customer_name, orders.order_id
FROM customers
FULL JOIN orders ON customers.customer_id = orders.customer_id;
</code></pre></div>    </div>
  </li>
</ol>

<p>SQL作为一种标准化的查询语言，具有通用性和广泛应用性。无论是简单的数据检索还是复杂的数据处理和分析，SQL都可以满足各种数据库操作的需求。通过熟练掌握SQL语言，用户可以有效地管理和操作关系型数据库系统，从而更好地实现数据存储、管理和分析的目标。</p>

<ol>
  <li>数据库索引</li>
</ol>

<p>数据库索引是一种提高检索效率的数据结构。创建索引可以加速数据表的查找操作。</p>

<ol>
  <li>
    <p><strong>索引结构：</strong> 索引通常是一个数据结构，它存储了表格中某一列或多列的值以及对应的行号。这样，当查询时，数据库系统可以使用索引快速定位到所需的数据行。</p>

    <ol>
      <li>
        <p><strong>B-树索引（B-tree Index）：</strong> B-树索引是最常见和最广泛使用的索引结构之一。它是一种平衡树结构，具有良好的平衡性和高效的查询性能。B-树索引适用于范围查询和精确查询，并且在大多数关系型数据库管理系统中被广泛应用。</p>

        <blockquote>
          <p>在SQL数据库中，创建B-树索引通常是通过CREATE INDEX语句来实现的。以下是一个示例代码：</p>
        </blockquote>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 Employees 的表格中创建一个B-树索引，用于加速 LastName 列的检索
CREATE INDEX idx_lastname ON Employees(LastName);
</code></pre></div>        </div>

        <blockquote>
          <p>上述代码在 Employees 表格的 LastName 列上创建了一个名为 idx_lastname 的B-树索引。</p>
        </blockquote>

        <blockquote>
          <p>使用B-树索引可以加速数据的检索，特别是在涉及到大量数据的情况下。例如，如果我们要查询姓氏为 “Smith” 的员工信息，有了B-树索引，数据库引擎可以更快地定位到姓氏为 “Smith” 的员工记录，而不需要扫描整个表格。</p>
        </blockquote>

        <h5 id="特点">特点：</h5>

        <ol>
          <li><strong>平衡性：</strong> B-树是一种平衡树，确保在任何时候，从根节点到叶子节点的最长路径和最短路径之间的高度差不超过1。这种平衡性保证了树的深度相对较小，使得查询效率较高。</li>
          <li><strong>节点存储多个键值：</strong> B-树的节点可以存储多个键值，而不仅仅是两个。这有助于减少树的深度，提高查询效率。节点中的键值以升序排列。</li>
          <li><strong>支持范围查询：</strong> B-树支持范围查询，因为在一个节点中存在多个连续的键值，可以更容易地定位到范围内的数据。</li>
          <li><strong>适用于磁盘存储：</strong> B-树的设计考虑到了磁盘I/O的特性，使其适用于在磁盘上存储的场景。每个节点的大小通常被设计为磁盘页的大小，以最大限度地减少I/O操作。</li>
        </ol>

        <h5 id="工作原理">工作原理：</h5>

        <ol>
          <li><strong>树结构：</strong> B-树是一种多叉树，每个节点可以有多个子节点。树的根节点到叶子节点的路径长度是相等的。</li>
          <li><strong>插入操作：</strong> 当需要插入一个新的键值时，B-树首先在树中找到合适的位置，然后进行插入。如果插入导致节点的键值数量超过了限制，就会进行节点的分裂操作，将中间值提升到父节点，并将左右两侧的键值分别作为新的子节点。</li>
          <li><strong>删除操作：</strong> 当需要删除一个键值时，B-树首先找到键值所在的位置，然后进行删除。如果删除导致节点的键值数量低于限制，就会进行节点的合并操作，将相邻的节点进行合并。</li>
          <li><strong>查找操作：</strong> 查找操作从根节点开始，根据键值大小逐级定位到目标节点。由于B-树的平衡性，查找效率相对较高。</li>
        </ol>
      </li>
      <li>
        <p><strong>B+树索引（B+tree Index）：</strong> B+树索引是在B-树索引基础上进行改进的一种索引结构。与B-树相比，B+树索引在内部节点中不存储数据，只存储键值和指向叶子节点的指针，这样可以提高内部节点的利用率，减少树的深度，进而提高查询性能。</p>

        <blockquote>
          <p>在关系型数据库中，创建B+树索引通常也是通过CREATE INDEX语句来实现的。以下是一个示例代码：</p>
        </blockquote>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 Students 的表格中创建一个B+树索引，用于加速按照学生姓名（Name）的检索
CREATE INDEX idx_name ON Students(Name);
</code></pre></div>        </div>

        <blockquote>
          <p>上述代码在 Students 表格的 Name 列上创建了一个名为 idx_name 的B+树索引。</p>
        </blockquote>

        <blockquote>
          <p>使用B+树索引可以提高数据的检索速度，特别是在大数据量的情况下，它可以加速数据的查找、范围查询和排序操作。</p>
        </blockquote>

        <h3 id="特点-1">特点：</h3>

        <ol>
          <li><strong>分离索引和数据：</strong> 在B+树中，所有的数据都存储在叶子节点中，而非叶子节点只包含键值和指向下一个节点的指针。这种分离索引和数据的设计使得B+树的查询效率更高。</li>
          <li><strong>叶子节点形成有序链表：</strong> B+树的叶子节点按照键值大小顺序形成一个有序链表。这样的设计方便范围查询和范围扫描。</li>
          <li><strong>高度平衡：</strong> B+树保持了树的高度平衡，因此在进行数据检索时，需要的磁盘I/O次数相对较少，提高了查询效率。</li>
          <li><strong>适用于范围查询：</strong> 由于B+树的叶子节点形成有序链表，因此B+树非常适合执行范围查询操作。在范围查询时，只需要沿着叶子节点的链表进行遍历即可。</li>
        </ol>

        <h3 id="工作原理-1">工作原理：</h3>

        <ol>
          <li><strong>树结构：</strong> B+树是一种多叉树，每个非叶子节点存储的是键值和指向子节点的指针，叶子节点存储的是键值和对应的数据记录。</li>
          <li><strong>插入操作：</strong> 插入操作从根节点开始，根据键值大小逐级定位到叶子节点。如果叶子节点的容量已满，则进行分裂操作，并将中间值提升到父节点。</li>
          <li><strong>删除操作：</strong> 删除操作从根节点开始，根据键值大小逐级定位到叶子节点。如果删除导致叶子节点的数据量过小，则进行合并操作，并将合并后的节点与相邻节点连接。</li>
          <li><strong>查找操作：</strong> 查找操作从根节点开始，根据键值大小逐级定位到叶子节点。在叶子节点中进行二分查找或顺序查找，找到对应的数据记录。</li>
        </ol>
      </li>
      <li>
        <p><strong>哈希索引（Hash Index）：</strong> 哈希索引使用哈希表作为索引结构，它将索引列的值通过哈希函数映射到哈希表中的存储位置。哈希索引适用于等值查询，具有快速的检索速度，但不支持范围查询。</p>

        <blockquote>
          <p>在MySQL中，哈希索引通常不是主流索引类型，但可以在特定场景下使用。</p>
        </blockquote>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 Students 的表格中创建一个哈希索引，用于加速按照学生ID（StudentID）的等值查询
CREATE INDEX idx_student_id ON Students(StudentID) USING HASH;
</code></pre></div>        </div>

        <p>上述代码在 Students 表格的 StudentID 列上创建了一个名为 idx_student_id 的哈希索引。</p>

        <h3 id="特点-2">特点：</h3>

        <ol>
          <li><strong>快速的等值查询：</strong> 哈希索引使用哈希函数将索引列的值转换为哈希码，并将其映射到哈希表中的存储位置。因此，对于等值查询操作，哈希索引具有很快的查询速度。</li>
          <li><strong>不支持范围查询：</strong> 哈希索引通常不支持范围查询，因为哈希函数是将键值映射到特定的位置，而不是按照顺序存储。因此，范围查询的效率较低。</li>
          <li><strong>适用于内存存储：</strong> 哈希索引适用于内存存储的场景，因为哈希表在内存中的访问速度非常快。在内存中，哈希索引可以实现非常快速的查询操作。</li>
          <li><strong>冲突处理：</strong> 哈希函数可能会导致不同的键值映射到相同的哈希码，这种情况称为哈希冲突。为了解决冲突，哈希索引通常使用开放地址法、链地址法等方法进行冲突处理。</li>
        </ol>

        <h3 id="工作原理-2">工作原理：</h3>

        <ol>
          <li><strong>创建哈希表：</strong> 在创建哈希索引时，数据库系统会创建一个哈希表，用于存储哈希索引列的值和对应的存储位置。</li>
          <li><strong>计算哈希码：</strong> 当执行查询操作时，数据库系统首先使用哈希函数计算查询条件的哈希码。</li>
          <li><strong>定位数据：</strong> 哈希索引根据哈希码定位到哈希表中的存储位置，并检索对应的数据记录。</li>
          <li><strong>处理冲突：</strong> 如果发生哈希冲突，即多个键值映射到同一个哈希码的情况，哈希索引会使用冲突处理方法解决冲突，例如开放地址法或链地址法。</li>
          <li><strong>查询结果：</strong> 哈希索引返回匹配查询条件的数据记录，完成查询操作。</li>
        </ol>
      </li>
      <li>
        <p><strong>全文索引（Full-Text Index）：</strong> 全文索引是针对文本字段的一种特殊索引结构，用于支持全文搜索和文本检索功能。全文索引通常使用倒排索引（Inverted Index）实现，允许用户在文本数据中进行关键字搜索和模糊匹配。</p>

        <blockquote>
          <p>在MySQL中创建全文索引：</p>
        </blockquote>

        <p>假设我们有一个名为 <code class="language-plaintext highlighter-rouge">articles</code> 的表，其中包含了一个 <code class="language-plaintext highlighter-rouge">content</code> 列，存储了文章的内容。</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 articles 的表格中创建一个全文索引，用于加速文章内容的全文搜索
CREATE FULLTEXT INDEX idx_content ON articles(content);
</code></pre></div>        </div>

        <p>上述代码在 <code class="language-plaintext highlighter-rouge">articles</code> 表的 <code class="language-plaintext highlighter-rouge">content</code> 列上创建了一个名为 <code class="language-plaintext highlighter-rouge">idx_content</code> 的全文索引。</p>

        <p>一旦创建了全文索引，就可以使用全文搜索功能来进行文本搜索。以下是一个简单的例子：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在 articles 表中进行全文搜索，查找包含 "database" 关键词的文章
SELECT * FROM articles WHERE MATCH(content) AGAINST('database');
</code></pre></div>        </div>

        <p>上述查询将返回所有包含 “database” 关键词的文章。全文搜索会考虑词根、同义词等方面，使得搜索更加灵活和准确。</p>

        <h3 id="特点-3">特点：</h3>

        <ol>
          <li><strong>支持文本搜索：</strong> 全文索引允许用户对文本数据进行全文搜索，而不仅仅是对固定的关键字或短语进行匹配。用户可以输入搜索词或关键字，系统会返回与搜索条件匹配的文本数据。</li>
          <li><strong>支持模糊匹配：</strong> 全文索引通常支持模糊匹配和通配符查询，用户可以使用通配符或模糊查询符号进行模糊匹配，从而扩大搜索范围。</li>
          <li><strong>自然语言处理：</strong> 全文索引通常会使用自然语言处理技术，例如分词、词干提取和同义词处理，从而提高搜索的准确性和效率。</li>
          <li><strong>语言支持：</strong> 全文索引通常支持多种语言，可以处理不同语言的文本数据，并提供相应的搜索和分析功能。</li>
        </ol>

        <h3 id="工作原理-3">工作原理：</h3>

        <ol>
          <li><strong>建立索引：</strong> 在全文索引中，数据库系统会对文本字段中的单词和短语建立索引。建立索引的过程包括分词、词干提取、同义词处理等步骤。</li>
          <li><strong>分词处理：</strong> 在建立索引时，全文索引会对文本数据进行分词处理，将文本分割成单词或短语，并去除停用词等无意义的词语。</li>
          <li><strong>建立倒排索引：</strong> 全文索引通常使用倒排索引（Inverted Index）结构，将每个单词或短语与包含该词语的文档进行关联。倒排索引提供了快速查找单词或短语出现位置的能力。</li>
          <li><strong>搜索操作：</strong> 当执行全文搜索操作时，数据库系统会根据用户输入的搜索条件，在全文索引中进行搜索，并返回匹配的文档列表。</li>
          <li><strong>评分和排名：</strong> 全文索引通常会根据匹配的程度对搜索结果进行评分和排名，从而提供更加精确和相关的搜索结果。</li>
        </ol>
      </li>
      <li>
        <p><strong>空间索引（Spatial Index）：</strong> 空间索引是用于地理空间数据的一种特殊索引结构，支持空间查询和空间分析操作。空间索引通常使用R树（R-tree）或其变体实现，用于加速空间数据的检索和查询。</p>

        <blockquote>
          <p>PostgreSQL数据库中创建和使用空间索引（以PostGIS为例）：</p>
        </blockquote>

        <p>假设我们有一个名为 <code class="language-plaintext highlighter-rouge">locations</code> 的表，其中包含了一个 <code class="language-plaintext highlighter-rouge">geom</code> 列，存储了位置的几何信息。</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 locations 的表格中创建一个空间索引，用于加速位置数据的空间查询
CREATE INDEX idx_geom ON locations USING GIST (geom);
</code></pre></div>        </div>

        <p>上述代码在 <code class="language-plaintext highlighter-rouge">locations</code> 表的 <code class="language-plaintext highlighter-rouge">geom</code> 列上创建了一个名为 <code class="language-plaintext highlighter-rouge">idx_geom</code> 的空间索引，使用了GIST（Generalized Search Tree）索引类型，这是PostGIS中的一种常用索引类型。</p>

        <p>一旦创建了空间索引，就可以使用空间查询功能来进行位置数据的空间查询。以下是一个简单的例子：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在 locations 表中进行空间查询，查找包含指定点的位置
SELECT *
FROM locations
WHERE ST_Contains(geom, ST_GeomFromText('POINT(10 20)'));
</code></pre></div>        </div>

        <p>上述查询将返回所有包含指定点的位置数据。在这个例子中，ST_Contains函数用于判断一个几何对象是否包含另一个几何对象，ST_GeomFromText函数用于将文本表示的几何对象转换为几何对象。</p>

        <h3 id="特点-4">特点：</h3>

        <ol>
          <li><strong>支持地理空间数据：</strong> 空间索引适用于具有地理空间属性的数据，例如地理坐标、地图数据、空间区域等。</li>
          <li><strong>快速的空间查询：</strong> 空间索引可以加速空间数据的查询操作，例如空间范围查询、距离查询、相交查询等。</li>
          <li><strong>支持空间分析：</strong> 空间索引提供了空间数据分析功能，例如空间聚合、空间缓冲区分析、空间连接等。</li>
          <li><strong>适用于多种数据类型：</strong> 空间索引不仅适用于点、线、面等基本地理要素数据，还可以处理多种复杂的空间数据类型，例如多边形、多点、多线等。</li>
        </ol>

        <h3 id="工作原理-4">工作原理：</h3>

        <ol>
          <li><strong>空间数据模型：</strong> 空间索引基于空间数据模型，将地理空间数据抽象为几何对象，例如点、线、面等。</li>
          <li><strong>索引结构：</strong> 空间索引使用特定的索引结构来存储和组织空间数据，常见的空间索引结构包括R树（R-tree）和其变种，例如R树、R*树、Quadtree等。</li>
          <li><strong>数据分割：</strong> 空间索引将空间数据分割成多个空间单元，每个空间单元都对应一个索引节点。这样可以提高查询效率，减少搜索空间。</li>
          <li><strong>索引查询：</strong> 当执行空间查询操作时，数据库系统根据查询条件在空间索引中进行搜索，找到与查询条件相匹配的空间对象。</li>
          <li><strong>空间关系判断：</strong> 空间索引支持空间关系判断，例如判断两个空间对象之间的相交关系、包含关系、相邻关系等。</li>
        </ol>
      </li>
      <li>
        <p><strong>位图索引（Bitmap Index）：</strong> 位图索引是一种特殊的索引结构，适用于低基数（Cardinality）列，即具有较少唯一值的列。位图索引将每个唯一值映射到一个位图中，以便进行位运算快速检索满足条件的行。</p>

        <blockquote>
          <p>Oracle数据库中创建和使用位图索引：</p>
        </blockquote>

        <p>假设我们有一个名为 <code class="language-plaintext highlighter-rouge">employees</code> 的表，其中包含了一个存储员工部门的列 <code class="language-plaintext highlighter-rouge">department_id</code>，我们希望为这个列创建一个位图索引。</p>

        <p>首先，创建位图索引：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
CREATE BITMAP INDEX idx_department_id ON employees(department_id);
</code></pre></div>        </div>

        <p>上述代码在 <code class="language-plaintext highlighter-rouge">employees</code> 表的 <code class="language-plaintext highlighter-rouge">department_id</code> 列上创建了一个名为 <code class="language-plaintext highlighter-rouge">idx_department_id</code> 的位图索引。</p>

        <p>一旦创建了位图索引，可以使用位图索引来加速数据的检索和过滤。以下是一个简单的例子：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 查询部门ID为 100 的员工
SELECT * FROM employees
WHERE department_id = 100;
</code></pre></div>        </div>

        <p>在上述查询中，如果数据库优化器选择使用位图索引，它会利用位图索引快速地找到部门ID为 100 的员工。</p>

        <h3 id="特点-5">特点：</h3>

        <ol>
          <li><strong>适用于低基数列：</strong> 位图索引适用于具有低基数（即唯一值较少）的列。在这种情况下，位图索引的存储效率较高。</li>
          <li><strong>压缩存储：</strong> 位图索引可以通过压缩技术来节省存储空间。由于每个位图只包含两种值（0和1），因此可以使用压缩算法来减少存储空间。</li>
          <li><strong>快速的等值查询：</strong> 位图索引能够快速地执行等值查询操作。通过将位图与查询条件进行位运算，可以快速定位到匹配的行。</li>
          <li><strong>支持位运算操作：</strong> 位图索引支持位运算操作，例如AND、OR、NOT等，这使得它可以轻松地处理多个位图之间的逻辑操作。</li>
        </ol>

        <h3 id="工作原理-5">工作原理：</h3>

        <ol>
          <li><strong>位图创建：</strong> 在创建位图索引时，数据库系统会为每个唯一的列值创建一个位图。位图的长度等于数据表中的行数。</li>
          <li><strong>位图填充：</strong> 对于每个位图，如果对应的列值在数据表的某一行中存在，则在位图中的相应位置置为1，否则置为0。</li>
          <li><strong>查询操作：</strong> 当执行等值查询操作时，数据库系统会将查询条件转换为位图形式，并与位图索引进行位运算。根据位运算的结果，确定匹配的行。</li>
          <li><strong>位图合并：</strong> 对于涉及多个位图的查询，位图索引可以执行位运算操作将多个位图合并，从而得到最终的匹配结果。</li>
          <li><strong>性能考虑：</strong> 位图索引的性能受到存储空间和内存访问速度的影响。在处理大型数据表时，位图索引可能会占用大量的存储空间，并且需要在内存中加载位图进行操作，因此需要仔细评估其性能。</li>
        </ol>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>索引类型：</strong> 数据库系统支持不同类型的索引，包括：</p>

    <ul>
      <li><strong>单列索引（Single-column Index）：</strong> 基于单个列的值创建的索引。</li>
      <li><strong>复合索引（Composite Index）：</strong> 基于多个列的值创建的索引。</li>
      <li><strong>唯一索引（Unique Index）：</strong> 索引列中的值必须唯一。</li>
      <li><strong>主键索引（Primary Key Index）：</strong> 用于唯一标识表格中每一行的索引。</li>
      <li><strong>聚集索引（Clustered Index）：</strong> 索引中的数据按照物理顺序存储，常与主键关联。</li>
      <li><strong>非聚集索引（Non-clustered Index）：</strong> 索引中的数据存储在与表格数据分开的位置。</li>
    </ul>

    <ol>
      <li>
        <p><strong>单列索引（Single-column Index）：</strong> 单列索引基于表中的单个列创建。它是最简单的索引类型，适用于对单个列进行等值查询或范围查询的情况。常见的单列索引包括B-树索引和哈希索引。</p>
      </li>
      <li>
        <p><strong>复合索引（Composite Index）：</strong> 复合索引基于表中的多个列创建。它适用于需要同时考虑多个列的查询条件，可以提高这些列上的联合查询性能。复合索引的顺序对查询性能有影响，应根据查询的频率和条件选择适当的列顺序。</p>
      </li>
      <li>
        <p><strong>唯一索引（Unique Index）：</strong> 唯一索引要求索引列的值必须是唯一的，不允许重复值。它通常用于加速对唯一键的等值查询，并确保表中的数据完整性。</p>
      </li>
      <li>
        <p><strong>主键索引（Primary Key Index）：</strong> 主键索引是唯一索引的一种特殊形式，它用于标识表中的唯一行。主键索引不允许空值，通常用于加速对主键列的等值查询。</p>
      </li>
      <li>
        <p><strong>全文索引（Full-Text Index）：</strong> 全文索引用于对文本数据进行全文搜索和检索。它适用于包含大量文本的列，例如文章内容或博客评论。全文索引可以提供对文本数据的高效搜索功能。</p>
      </li>
      <li>
        <p><strong>空间索引（Spatial Index）：</strong> 空间索引用于处理具有地理空间属性的数据，例如地理坐标或地图数据。它支持空间查询和分析操作，常用的结构包括R树。</p>
      </li>
      <li>
        <p><strong>位图索引（Bitmap Index）：</strong> 位图索引适用于低基数列，即具有较少唯一值的列。它将每个唯一值映射到一个位图中，用于加速位运算检索。</p>
      </li>
      <li>
        <p><strong>哈希索引（Hash Index）：</strong> 哈希索引使用哈希函数将索引列的值映射到哈希表中，适用于等值查询。然而，哈希索引不适用于范围查询，因为哈希函数无法保证有序性。</p>

        <ol>
          <li><strong>单列索引：</strong></li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 Employees 的表格中创建一个单列索引，用于加速 LastName 列的检索
CREATE INDEX idx_lastname ON Employees(LastName);
</code></pre></div>        </div>

        <ol>
          <li><strong>复合索引：</strong></li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 Employees 的表格中创建一个复合索引，用于加速 LastName 和 FirstName 列的组合检索
CREATE INDEX idx_lastname_firstname ON Employees(LastName, FirstName);
</code></pre></div>        </div>

        <ol>
          <li><strong>唯一索引：</strong></li>
        </ol>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code-- 在名为 Employees 的表格中创建一个唯一索引，确保 EmployeeID 列的数值唯一
CREATE UNIQUE INDEX idx_employeeid_unique ON Employees(EmployeeID);
</code></pre></div>        </div>

        <p>上述代码示例是基于 MySQL 语法的简化版本，实际使用时需要根据所选用的数据库系统和其支持的语法进行调整。不同数据库系统可能会有不同的索引实现和语法。</p>

        <p>在关系型数据库中，主键索引、聚集索引和非聚集索引是常见的索引类型，它们在数据库中起着不同的作用。</p>

        <ol>
          <li><strong>主键索引</strong>：</li>
        </ol>

        <p>主键索引是一种唯一索引，用于唯一标识表中的每一行数据。主键索引确保表中的每一行都具有唯一的标识，通常是通过一个或多个列的组合来定义的。在大多数数据库系统中，主键索引会自动创建，如果没有显式指定主键索引，数据库系统会自动创建一个主键索引。</p>

        <p>在 MySQL 中创建主键索引的示例代码如下：</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 在名为 Employees 的表格中创建一个主键索引，用于标识 EmployeeID 列的唯一性</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="n">Employees</span> <span class="k">ADD</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">EmployeeID</span><span class="p">);</span>
</code></pre></div>        </div>

        <ol>
          <li><strong>聚集索引</strong>：</li>
        </ol>

        <p>聚集索引是一种特殊的索引，它指定了数据在物理存储中的顺序，表中的数据按照聚集索引的顺序进行存储。在大多数情况下，主键索引就是一种聚集索引，因为主键索引定义了表中数据的物理存储顺序。</p>

        <p>在 SQL Server 中，主键索引默认就是聚集索引，示例代码如下：</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 在名为 Employees 的表格中创建一个主键索引，用于标识 EmployeeID 列的唯一性</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="n">Employees</span> <span class="k">ADD</span> <span class="k">CONSTRAINT</span> <span class="n">PK_Employees</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="n">CLUSTERED</span> <span class="p">(</span><span class="n">EmployeeID</span><span class="p">);</span>
</code></pre></div>        </div>

        <ol>
          <li><strong>非聚集索引</strong>：</li>
        </ol>

        <p>非聚集索引是一种独立于数据物理存储顺序的索引，在查询时使用非聚集索引可以快速定位到目标数据，然后再根据索引指向的位置获取数据。非聚集索引通常适用于那些没有指定聚集索引或者需要额外的索引来优化查询性能的情况。</p>

        <p>在 MySQL 中创建非聚集索引的示例代码如下：</p>

        <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 在名为 Employees 的表格中创建一个非聚集索引，用于加速 LastName 列的检索</span>
<span class="k">CREATE</span> <span class="k">INDEX</span> <span class="n">idx_lastname</span> <span class="k">ON</span> <span class="n">Employees</span><span class="p">(</span><span class="n">LastName</span><span class="p">);</span>
</code></pre></div>        </div>

        <p>需要注意的是，每个数据库系统的索引实现和语法可能会有所不同，上述示例是基于 MySQL 和 SQL Server 的实现。在实际使用时，需要根据所选用的数据库系统和其支持的语法进行调整。</p>
      </li>
    </ol>
  </li>
  <li>
    <p><strong>索引创建：</strong> 索引可以在表格创建时定义，也可以在表格已存在时单独创建。创建索引时需要考虑索引列的选择、索引类型、索引的大小等因素，以及对查询性能的影响。</p>

    <ol>
      <li><strong>选择索引列：</strong> 首先确定需要创建索引的列。通常选择作为查询条件或经常用于检索数据的列作为索引列。索引列的选择应基于查询的频率、数据分布和性能需求。</li>
      <li><strong>选择索引类型：</strong> 根据索引列的特点和查询需求选择适当的索引类型。常见的索引类型包括单列索引、复合索引、唯一索引等。每种索引类型都有其适用的场景和限制。</li>
      <li><strong>创建索引语句：</strong> 使用数据库管理系统提供的DDL（数据定义语言）语句来创建索引。具体的创建索引语句语法和选项取决于所使用的数据库管理系统。以下是一些常见数据库管理系统中创建索引的示例：</li>
    </ol>

    <ul>
      <li>
        <p>在 MySQL 中，创建单列索引的语法如下：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
CREATE INDEX index_name ON table_name(column_name);
</code></pre></div>        </div>
      </li>
      <li>
        <p>创建复合索引：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
CREATE INDEX index_name ON table_name(column1, column2);
</code></pre></div>        </div>
      </li>
      <li>
        <p>创建唯一索引：</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sqlCopy code
CREATE UNIQUE INDEX index_name ON table_name(column_name);
</code></pre></div>        </div>
      </li>
    </ul>

    <ol>
      <li><strong>执行创建索引语句：</strong> 执行创建索引的语句，让数据库管理系统在后台完成索引的创建过程。创建大型表格的索引可能需要一些时间，取决于表格大小和系统负载等因素。</li>
      <li><strong>验证索引创建：</strong> 创建索引后，可以通过查询数据库系统的系统表格或元数据来验证索引是否成功创建。在大多数数据库系统中，可以查询系统表格或使用特定的管理工具来查看索引的信息和状态</li>
    </ol>
  </li>
  <li>
    <p><strong>索引优势：</strong> 索引可以加快数据检索的速度，特别是在大型数据表格中。通过使用索引，数据库系统可以避免全表扫描，而是直接定位到符合查询条件的数据行，从而提高了查询的效率。</p>

    <ol>
      <li><strong>提高查询性能：</strong> 索引可以加速数据检索操作，通过创建索引，数据库系统可以避免全表扫描，而是直接定位到符合查询条件的数据行，从而提高了查询的效率。</li>
      <li><strong>加速排序和分组操作：</strong> 对于需要排序和分组的查询，索引可以大大减少排序和分组操作的时间复杂度，提高了查询的速度。</li>
      <li><strong>保证数据完整性：</strong> 唯一索引和主键索引可以确保索引列中的数据唯一，从而保证了表格数据的完整性。</li>
      <li><strong>支持连接操作：</strong> 索引可以加速连接操作，特别是在复杂的查询中，通过合适的索引可以使连接操作更加高效。</li>
    </ol>
  </li>
  <li>
    <p><strong>索引注意事项：</strong> 尽管索引可以提高查询性能，但过多或不必要的索引可能会增加数据库写操作的成本，因为每次写操作都需要维护索引。此外，索引也需要占用存储空间，因此需要权衡查询性能和存储资源的使用。</p>

    <ol>
      <li><strong>过度索引化：</strong> 过度创建索引可能会导致数据库性能下降。每个索引都需要额外的存储空间和维护成本，因此需要权衡创建索引的数量和对性能的影响。</li>
      <li><strong>更新代价高昂：</strong> 对表格进行更新、插入和删除操作时，数据库系统需要更新索引，这可能会导致写操作的性能下降。因此，需要在索引设计时考虑写操作的频率和成本。</li>
      <li><strong>选择适当的索引列：</strong> 索引的效果取决于选择的索引列，选择不合适的索引列可能导致索引失效或性能下降。需要根据查询的需求、数据分布和查询频率等因素选择合适的索引列。</li>
      <li><strong>定期维护和优化：</strong> 索引需要定期维护和优化，以确保其与表格数据的同步和一致性。随着数据库的使用和演化，可能需要调整和优化索引，以满足新的查询需求和性能要求。</li>
      <li><strong>使用合适的索引类型：</strong> 不同类型的索引适用于不同的查询需求和场景。需要根据具体的业务需求和查询模式选择合适的索引类型，以提高查询性能和优化数据库操作。</li>
    </ol>
  </li>
</ol>

<h2 id="结论">结论</h2>

<p>数据库原理是构建稳健、高效和可靠数据库系统的基础。了解这些原理对于数据库设计和管理至关重要。</p>

<hr />]]></content><author><name></name></author><category term="notes" /><category term="codes" /><summary type="html"><![CDATA[数据库原理主要内容 1. 数据库是什么？ 数据库是一个组织数据的集合，可供快速访问、管理和更新。它是应用程序的基础，用于存储和检索数据。 数据库是一个组织数据的集合，可供快速访问、管理和更新的系统。它是一个电子化的数据存储系统，旨在有效地存储和检索大量的数据。数据库系统能够存储各种类型的数据，包括文字、数字、图像、音频和视频等，以及它们之间的关系。通过使用数据库，用户可以轻松地进行数据的添加、删除、修改和查询，以满足各种应用程序和业务需求。（以下以MySQL为栗子） 2. 数据库的基本原则 数据唯一性： 每条数据都应该有一个唯一的标识符，例如主键。 主键约束（Primary Key Constraint）： 在关系型数据库中，可以通过定义一个主键来确保数据的唯一性。主键是一列或一组列，其值在整个表中必须唯一。通过将主键约束应用于表中的一个或多个列，可以防止重复的数据记录。 ​ 创建一个包含主键约束的表 -- 创建一个学生表（Student），包含学生的学号、姓名和年龄信息，其中学号为主键 CREATE TABLE Student ( student_id INT PRIMARY KEY, -- 学号作为主键 name VARCHAR(50), age INT ); 唯一约束（Unique Constraint）： 除了主键之外，还可以使用唯一约束来保证数据的唯一性。唯一约束要求某一列或一组列中的值在表中是唯一的，但不要求其成为主键。 sqlCopy code -- 创建一个用户表（User），包含用户名和电子邮件地址，要求用户名和电子邮件地址都是唯一的 CREATE TABLE User ( user_id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE, -- 用户名必须唯一 email VARCHAR(100) UNIQUE -- 电子邮件地址必须唯一 ); 索引（Index）： 在数据库中创建索引可以提高数据的检索效率，同时也可以帮助确保数据的唯一性。通过在列上创建唯一索引，可以强制该列中的值保持唯一。 ​ 创建一个索引： -- 在一个名为 students 的表中，对 name 列创建一个索引 CREATE INDEX idx_name ON students (name); 在上面的示例中，idx_name 是索引的名称，students 是表的名称，name 是要创建索引的列名。 数据完整性： 数据应该保持准确和完整，不应该存在不一致或缺失的数据。 实体完整性（Entity Integrity）： 实体完整性确保每个表中的行都具有唯一的标识符，通常是一个主键。这意味着每个表中的每行都必须具有一个主键值，并且主键值不能是空值或重复的。通过实体完整性约束，防止了表中的行缺失主键值或存在重复的行。 域完整性（Domain Integrity）： 域完整性确保数据库中的数据符合预定义的规范和范围。它包括数据类型的限制、取值范围的约束、格式要求等。例如，一个字段的数据类型为整数，那么它就不能存储非整数类型的值；又如，一个字段的取值范围限定在特定范围内。 引用完整性（Referential Integrity）： 引用完整性确保数据库中的引用关系保持一致和有效。在关系数据库中，引用完整性通常通过外键约束实现。外键约束指定了一个表中的列（外键），它引用了另一个表中的主键。引用完整性要求在外键引用的表中，对应的主键值必须存在，或者必须为 NULL（如果允许空值）。这样可以确保引用关系的有效性，防止出现无效引用或孤立的数据。 用户定义的完整性规则（User-defined Integrity Rules）： 在某些情况下，数据库管理员可能会定义特定的完整性规则，以确保数据满足特定的业务规则或约束条件。这些规则可以通过触发器（Triggers）、存储过程（Stored Procedures）等方式来实现。 数据一致性： 数据库中的数据应该保持一致性，即不同的数据之间的关联关系应该得到维护。 实体间的一致性： 数据库中的不同实体之间的关系应该得到维护。例如，在关系型数据库中，表之间的关联关系应该保持一致，确保相关数据的完整性和正确性。 事务一致性： 事务是数据库操作的一个基本单位，它应该保证数据库从一个一致状态转移到另一个一致状态。数据库管理系统通过实现事务的原子性、一致性、隔离性和持久性（ACID属性）来确保事务的一致性。 索引和约束的一致性： 数据库中的索引和约束应该与数据的实际状态保持一致。例如，如果一个表中的数据发生了变化，相关的索引和约束应该及时更新，以反映最新的数据状态。 数据更新的一致性： 当数据库中的数据发生变化时，应该保证相关的数据更新是一致的和正确的。这包括在数据插入、更新或删除操作中，保证数据的完整性、准确性和有效性。 复制和分布式数据的一致性： 在分布式数据库系统中，数据的复制和分布可能导致数据副本之间的不一致性。因此，数据库管理系统必须实现复制和分布式算法，以确保数据的一致性和同步性。 数据可恢复性： 数据库应该具备恢复数据的能力，以应对故障或错误。 备份和恢复策略： 数据库管理系统应该实施定期备份数据库的策略，以确保数据的安全性和可恢复性。备份数据应该存储在安全的位置，并且能够快速恢复数据库到之前的状态。 日志记录： 数据库系统应该记录所有的数据库操作和事务，以便在需要时进行恢复。事务日志记录了数据库中发生的所有变化，可以用来恢复数据库到一个一致的状态。 事务管理： 数据库管理系统应该支持事务的原子性、一致性、隔离性和持久性（ACID属性）。当事务执行失败或中断时，数据库系统应该能够回滚事务并保持数据库的一致性。 灾难恢复： 数据库管理系统应该具备灾难恢复的能力，以应对硬件故障、自然灾害或人为破坏等情况。灾难恢复计划应该包括备份数据的存储位置、紧急恢复过程和灾难恢复团队的角色和责任。 故障转移和高可用性： 数据库系统可以通过故障转移和高可用性技术来提高数据的可恢复性。这包括使用备用服务器、集群和自动故障检测和恢复机制等。 数据唯一性：每条数据都应该有一个唯一的标识符，通常是一个主键。这确保了每条数据在数据库中的唯一性，避免了重复数据的存在。 数据完整性：数据应该保持准确和完整，不应该存在不一致或缺失的数据。这可以通过定义数据类型、约束和规范来实现，确保数据在插入、更新和删除过程中保持完整性。 数据一致性：数据库中的数据应该保持一致性，即不同的数据之间的关联关系应该得到维护。例如，在关系型数据库中，外键约束可以用来维护表之间的关系，确保数据的一致性。 数据可恢复性：数据库应该具备恢复数据的能力，以应对故障、错误或意外事件。这包括定期备份数据库、实施事务处理和日志记录，以确保在发生故障时能够恢复数据到一致的状态。 数据安全性：数据库应该保护数据的安全性，防止未经授权的访问、修改或删除数据。这包括实施访问控制、加密数据、审计和监控数据库活动等措施，以保护数据免受恶意攻击和意外泄露的风险。 3. 数据库模型 数据库模型定义了数据在数据库中的组织方式。常见的数据库模型包括： 层次模型（Hierarchical Model）： 层次模型使用树形结构来组织数据，其中每个节点可以有一个或多个子节点，但只能有一个父节点。这种模型适合描述具有明确定义的父子关系的数据，例如组织结构和文件系统。 父子关系： 在层次模型中，每个数据元素都与其他元素之间建立了明确的父子关系。父节点是子节点的直接上级，而子节点是父节点的直接下级。 根节点： 根节点是层次结构的顶层节点，它不具有父节点。 分支节点： 分支节点是除了根节点之外的其他节点，它们既可以有父节点也可以有子节点。 叶子节点： 叶子节点是没有子节点的节点，它们位于层次结构的末端。 路径： 路径是从根节点到任意节点的一系列相连的节点。 ​ 使用递归关系来构建层次模型： -- 创建一个名为 Employee 的表，用于存储员工信息，并实现层次模型 CREATE TABLE Employee ( emp_id INT PRIMARY KEY, emp_name VARCHAR(100), manager_id INT, -- 管理者的员工ID FOREIGN KEY (manager_id) REFERENCES Employee(emp_id) -- 管理者ID是对应员工表的员工ID ); 在上面的示例中，Employee 表包含了员工的信息，其中包括员工ID (emp_id)、员工姓名 (emp_name) 和其直接上级的员工ID (manager_id)。manager_id 列是对应员工表的外键，它参考了自身的主键 emp_id，这样就可以构建员工与直接上级之间的层次关系。 网状模型（Network Model）： 网状模型是一种图形结构，其中数据元素可以具有多个父节点和多个子节点。这种模型允许更复杂的数据关系，但也更加复杂和难以理解，通常用于一些特定的应用场景。 记录类型（Record Types）： 网状模型使用记录类型来描述数据的结构。每个记录类型都定义了一组属性，并且可以包含一个或多个记录实例。 集合类型（Set Types）： 集合类型用于描述记录类型之间的关系。一个集合类型可以包含多个记录类型，并且可以定义记录类型之间的连接和关系。 拓扑结构： 网状模型中的数据组织形式具有拓扑结构，其中节点之间的关系不仅限于父子关系，还可以是任意的连接关系。 指针（Pointers）： 在网状模型中，使用指针来表示记录之间的关系。一个记录可以包含一个或多个指向其他记录的指针，从而形成网络结构。 数据访问路径： 在网状模型中，可以沿着指针定义的路径访问数据。与层次模型不同，网状模型允许多个路径访问同一个记录，提供了更大的灵活性和查询能力。 下面是一个简单的示例，演示如何使用指针来构建一个简单的网状模型： -- 创建一个名为 Relationship 的表，用于存储实体之间的关系 CREATE TABLE Relationship ( entity_id1 INT, entity_id2 INT, relationship_type VARCHAR(50), PRIMARY KEY (entity_id1, entity_id2), -- 将 entity_id1 和 entity_id2 作为复合主键 FOREIGN KEY (entity_id1) REFERENCES Entity(entity_id), -- entity_id1 是对应实体表的实体ID FOREIGN KEY (entity_id2) REFERENCES Entity(entity_id) -- entity_id2 是对应实体表的实体ID ); 在上面的示例中，Relationship 表包含了实体之间的关系，其中包括了 entity_id1 和 entity_id2 两个实体的ID，以及它们之间的关系类型 relationship_type。 entity_id1 和 entity_id2 列分别是对应实体表 Entity 的外键，它们参考了实体表中的实体ID。通过这种方式，可以在关系表中建立实体之间的多对多关系。 关系模型（Relational Model）： 关系模型是目前最广泛使用的数据库模型之一，它使用表格（或称为关系）来组织数据。每个表包含多个行（记录）和列（字段），其中每个字段具有唯一的名称和数据类型。关系模型通过主键和外键来定义表之间的关系，具有良好的结构化特性和简单的查询语言，例如结构化查询语言（SQL）。 表格（Table）： 关系模型中的数据被组织成表格的形式，每个表格也被称为关系（Relation）。每个表格由行（Records）和列（Fields）组成，每一行代表一个记录，每一列代表一个属性。 主键（Primary Key）： 每个表格都有一个或多个列组成的主键，主键的值在表格中是唯一的，并且不为空。主键用于唯一标识表格中的每条记录。 外键（Foreign Key）： 外键是一个表格中的列，它引用了另一个表格中的主键。外键用于建立表格之间的关系。 关系操作（Relational Operations）： 关系模型定义了一系列的操作，用于处理表格中的数据，包括选择（Select）、投影（Project）、连接（Join）、并集（Union）、差集（Difference）等。 数据完整性（Data Integrity）： 关系模型通过约束（Constraints）来保持数据的完整性，包括实体完整性、域完整性和引用完整性。 结构化查询语言（SQL）： 结构化查询语言是关系数据库管理系统中用于管理和查询数据的标准语言。它支持各种操作，包括数据查询、插入、更新和删除等。 关系模型的优点包括： 结构化：关系模型提供了一种结构化的方式来组织和存储数据，使得数据更容易理解和管理。 灵活性：关系模型的设计可以适应各种不同类型和规模的数据集，具有很高的灵活性。 数据独立性：关系模型通过将数据和数据操作分离，实现了数据独立性，使得应用程序可以独立于数据存储的物理结构进行开发和维护。 创建一个关系模型的表格： sqlCopy code-- 创建一个名为 Students 的表格，用于存储学生信息 CREATE TABLE Students ( student_id INT PRIMARY KEY, name VARCHAR(100), age INT, gender VARCHAR(10) ); 在上面的示例中，Students 表格定义了学生的信息，包括学生ID (student_id)、姓名 (name)、年龄 (age) 和性别 (gender)。 student_id 列被定义为主键 (PRIMARY KEY`)，确保每个学生ID的唯一性。 其列包括了学生的姓名、年龄和性别等属性。 面向对象模型（Object-Oriented Model）： 面向对象模型将数据组织为对象，每个对象具有属性和方法。这种模型适合于描述现实世界中的复杂对象和关系，例如物体、人员、事件等。 对象（Object）： 在面向对象模型中，数据被组织成对象的形式。对象包含了数据（属性）和行为（方法）的集合，能够完整地描述现实世界中的实体。 类（Class）： 类是对象的模板，它定义了对象的属性和方法。类可以用来创建多个具有相似属性和行为的对象。 继承（Inheritance）： 继承是面向对象模型中的一个重要特性，它允许一个类从另一个类继承属性和方法。这样可以促进代码的重用和扩展，提高了系统的可维护性和可扩展性。 多态（Polymorphism）： 多态允许不同的对象对相同的消息做出不同的响应。这意味着可以通过统一的接口来处理不同类型的对象，从而提高了系统的灵活性和可扩展性。 封装（Encapsulation）： 封装是一种将数据和操作封装在一起的机制，使得对象的内部状态对外部是不可见的。这样可以防止数据的不合法访问和修改，提高了系统的安全性和健壮性。 在关系型数据库中使用面向对象模型： sqlCopy code-- 创建一个名为 Person 的表格，用于存储人员信息 CREATE TABLE Person ( person_id INT PRIMARY KEY, first_name VARCHAR(50), last_name VARCHAR(50), date_of_birth DATE ); -- 创建一个名为 Address 的表格，用于存储地址信息 CREATE TABLE Address ( address_id INT PRIMARY KEY, street VARCHAR(100), city VARCHAR(50), state VARCHAR(50), zip_code VARCHAR(10) ); -- 创建一个名为 PersonAddress 的表格，用于建立 Person 和 Address 之间的关联关系 CREATE TABLE PersonAddress ( person_id INT, address_id INT, PRIMARY KEY (person_id, address_id), FOREIGN KEY (person_id) REFERENCES Person(person_id), FOREIGN KEY (address_id) REFERENCES Address(address_id) ); 在上面的示例中，我们创建了三个表格： Person 表格用于存储人员信息，包括 person_id、first_name、last_name 和 date_of_birth 等属性。 Address 表格用于存储地址信息，包括 address_id、street、city、state 和 zip_code 等属性。 PersonAddress 表格用于建立 Person 和 Address 之间的关联关系，它包含了 person_id 和 address_id 两个外键，分别参考了 Person 和 Address 表格中的主键。 文档模型（Document Model）： 文档模型将数据组织为文档（通常是JSON或XML格式），每个文档可以包含不同类型和结构的数据。这种模型适用于需要灵活处理和存储各种类型数据的场景，例如内容管理系统和大数据应用。 文档（Document）： 文档是文档模型中的基本单位，它可以是一个JSON对象、XML文档或类似的数据结构。文档可以包含任意数量和类型的字段，具有很高的灵活性。 集合（Collection）： 文档通常被组织在集合中，类似于关系数据库中的表格。一个集合可以包含多个文档，每个文档可以具有不同的结构。 嵌套文档（Nested Documents）： 文档模型允许文档内部包含其他文档，形成嵌套的层次结构。这样可以更好地表示复杂的数据关系和嵌套结构。 灵活性： 文档模型具有很高的灵活性，可以存储各种类型和格式的数据，适用于处理半结构化和非结构化数据。 查询语言： 文档数据库通常提供了灵活和强大的查询语言，用于查询和操作文档数据。这些查询语言通常支持各种条件查询、投影、聚合和排序等操作。 在 MongoDB 中使用文档模型存储数据： javascriptCopy code// 在 MongoDB 中插入一个文档 db.students.insertOne({ "student_id": 1001, "name": "John Doe", "age": 25, "courses": ["Math", "Science"], "address": { "street": "123 Main St", "city": "Anytown", "state": "CA", "zip": "12345" } }); 在上面的示例中，我们向 MongoDB 中的 students 集合插入了一个文档。这个文档包含了学生的信息，包括学生ID (student_id)、姓名 (name)、年龄 (age)、所修课程 (courses) 和地址信息 (address)。address 字段是一个嵌套的文档，包含了街道、城市、州和邮编等信息。 列存储模型（Columnar Store Model）： 列存储模型将数据按列存储，而不是按行存储。这种模型适用于需要快速分析和聚合大量数据的场景，例如数据仓库和数据分析应用。 列存储： 在列存储模型中，数据按列组织存储在内存或磁盘中。这意味着一个表的每一列都被存储在一起，而不是将整个行存储在一起。这种存储方式使得查询可以只检索需要的列，从而提高了查询效率和性能。 压缩技术： 列存储模型通常使用压缩技术来减少存储空间和提高查询性能。由于列中的数据通常具有较高的数据重复性，因此可以使用压缩算法来减少存储空间并加快数据读取速度。 向量化处理： 列存储模型可以利用向量化处理技术来进行高效的数据操作。向量化处理允许一次性处理多个数据元素，从而提高了数据处理的速度和效率。 分区和分布式处理： 列存储模型通常支持数据分区和分布式处理，可以将数据分成多个分区并分布在不同的节点上进行存储和处理。这样可以提高系统的扩展性和容错性。 适用场景： 列存储模型适用于需要快速分析和聚合大量数据的场景，例如数据仓库、在线分析处理（OLAP）和数据分析应用程序。 列存储模型的优点包括： 查询性能：由于列存储模型只检索需要的列，因此可以大大提高查询性能和响应速度。 压缩效率：列存储模型可以通过压缩技术减少存储空间的使用，节省存储成本。 分区和分布式处理：列存储模型支持数据分区和分布式处理，可以处理大规模数据并实现水平扩展。 在 Apache HBase 中使用列存储模型存储数据： javaCopy codeimport org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.util.Bytes; import java.io.IOException; public class HBaseExample { public static void main(String[] args) throws IOException { // 配置 HBase 连接 org.apache.hadoop.conf.Configuration config = HBaseConfiguration.create(); config.set("hbase.zookeeper.quorum", "localhost"); // 设置 ZooKeeper 地址 // 建立 HBase 连接 Connection connection = ConnectionFactory.createConnection(config); // 获取表格 Table table = connection.getTable(TableName.valueOf("my_table")); // 创建一个 Put 对象，并指定行键 Put put = new Put(Bytes.toBytes("row1")); // 添加列族和列 put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("col1"), Bytes.toBytes("value1")); put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("col2"), Bytes.toBytes("value2")); // 插入数据 table.put(put); // 关闭连接 connection.close(); } } 在上面的示例中，我们使用 Apache HBase 客户端 API 连接到 HBase，并向名为 my_table 的表格中插入了一行数据。 这里我们采用了列存储模型的方式来存储数据。数据在 HBase 中是按列族（Column Family）存储的，每个列族包含一组相关的列。在插入数据时，我们使用 addColumn 方法来添加列族和列。在列存储模型中，列族通常在表格设计时静态地定义，而列则动态地添加。 4. SQL（Structured Query Language） SQL 简介 SQL 是用于管理和查询数据库的标准语言。以下是一个简单的 SQL 查询示例： SELECT * FROM students WHERE age &gt; 18; SQL（Structured Query Language）是一种专门用于管理关系型数据库系统的标准化查询语言。它允许用户执行各种操作，包括查询数据、插入新数据、更新现有数据、删除数据等。SQL是关系数据库管理系统（RDBMS）的核心语言，几乎所有主流的关系数据库管理系统都支持SQL。 以下是SQL的一些基本概念和常见操作： DDL（数据定义语言）： DDL用于定义数据库的结构和模式。常见的DDL命令包括： CREATE TABLE：创建新表格。 ALTER TABLE：修改现有表格的结构。 DROP TABLE：删除表格。 CREATE INDEX：创建索引。 创建表格（CREATE TABLE）： sqlCopy codeCREATE TABLE Employees ( EmployeeID INT PRIMARY KEY, LastName VARCHAR(50), FirstName VARCHAR(50), BirthDate DATE, DepartmentID INT, FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID) ); 修改表格（ALTER TABLE）： sqlCopy codeALTER TABLE Employees ADD Email VARCHAR(100); 删除表格（DROP TABLE）： sqlCopy code DROP TABLE Employees; 创建索引（CREATE INDEX）： sqlCopy code CREATE INDEX idx_lastname ON Employees(LastName); 删除索引（DROP INDEX）： sqlCopy code DROP INDEX idx_lastname ON Employees; DDL DML（数据操作语言）： DML用于管理数据库中的数据。常见的DML命令包括： SELECT：从数据库中检索数据。 INSERT INTO：向表格中插入新数据。 UPDATE：更新表格中的现有数据。 DELETE FROM：从表格中删除数据。 插入数据（INSERT INTO）： sqlCopy codeINSERT INTO Employees (EmployeeID, LastName, FirstName, BirthDate, DepartmentID) VALUES (1, 'Smith', 'John', '1990-05-25', 101); 查询数据（SELECT）： sqlCopy codeSELECT EmployeeID, LastName, FirstName FROM Employees WHERE DepartmentID = 101; 更新数据（UPDATE）： sqlCopy codeUPDATE Employees SET DepartmentID = 102 WHERE LastName = 'Smith'; 删除数据（DELETE FROM）： sqlCopy codeDELETE FROM Employees WHERE EmployeeID = 1; DML DCL（数据控制语言）： DCL用于控制数据库的访问权限和安全性。常见的DCL命令包括： GRANT：授予用户特定权限。 REVOKE：收回用户的权限。 以下是一些常见的DCL代码示例： 授予权限（GRANT）： sqlCopy code GRANT SELECT, INSERT ON Employees TO user1; 撤销权限（REVOKE）： sqlCopy code REVOKE INSERT ON Employees FROM user1; DCL 数据查询： SQL的主要功能之一是查询数据库中的数据。通过使用SELECT语句，可以检索特定条件下的数据，进行筛选、排序和聚合等操作。 选择数据表格： 首先，确定从哪些数据表格中检索数据。在关系数据库中，通常会有多个表格存储不同类型的数据。 编写查询语句： 使用查询语言（如SQL），编写查询语句以指定所需的数据。查询语句通常由 SELECT 语句组成，可以包含多个选项，如 FROM、WHERE、ORDER BY、GROUP BY 等，用于指定要检索的数据以及对数据的排序、筛选和分组等操作。 选择数据列： 在 SELECT 语句中，指定要检索的数据列。可以使用 * 通配符检索所有列，也可以列出要检索的特定列名。 设置检索条件： 使用 WHERE 子句指定数据检索的条件，以筛选符合特定条件的数据。条件可以是简单的比较操作，也可以是复杂的逻辑表达式。 排序数据： 使用 ORDER BY 子句对检索到的数据进行排序，可以按照一个或多个列进行升序或降序排列。 聚合数据： 使用聚合函数（如 SUM、COUNT、AVG、MAX、MIN 等）对数据进行统计和汇总。 分组数据： 使用 GROUP BY 子句对数据进行分组，通常与聚合函数一起使用，用于对分组后的数据进行统计和分析。 执行查询： 将编写好的查询语句提交给数据库管理系统执行，获取查询结果。 解释查询结果： 分析和解释查询结果，确保数据符合预期并满足查询要求。 以下是一个简单的数据查询示例： sqlCopy code-- 从名为 Employees 的表中检索所有员工的姓氏和名字 SELECT LastName, FirstName FROM Employees; 这个查询语句从 Employees 表中选择了姓氏（LastName）和名字（FirstName）列的数据。 另外，SELECT语句还可以进行更复杂的查询，如下所示： sqlCopy code-- 从名为 Orders 的表中检索订单数量大于100的顾客ID SELECT CustomerID, COUNT(OrderID) AS OrderCount FROM Orders GROUP BY CustomerID HAVING COUNT(OrderID) &gt; 100; 这个查询语句从 Orders 表中选择了顾客ID（CustomerID），并对顾客ID进行分组，然后使用HAVING子句过滤出订单数量大于100的顾客ID。COUNT函数用于统计每个顾客ID的订单数量。 数据过滤和排序： SQL允许对检索到的数据进行过滤和排序，以便根据特定的条件选择所需的数据，并按照指定的顺序进行排列。 数据过滤： 数据过滤是根据特定的条件从数据库中选择符合条件的数据记录。常见的过滤操作使用 WHERE 子句来指定条件，只有满足条件的数据记录才会被检索出来。例如： sqlCopy code SELECT * FROM employees WHERE department = 'Sales'; 上面的查询语句将从名为 “employees” 的表中选择所有部门为 “Sales” 的员工记录。 数据排序： 数据排序是对查询结果按照指定的列或表达式进行排序，以便更容易地理解和分析数据。常见的排序操作使用 ORDER BY 子句来指定排序的列和排序顺序（升序或降序）。例如： sqlCopy code SELECT * FROM products ORDER BY price DESC; 上面的查询语句将从名为 “products” 的表中选择所有产品记录，并按照价格从高到低的顺序对其进行排序。 组合过滤和排序： 可以将数据过滤和排序操作组合在一起，以获取满足特定条件并按照指定顺序排列的数据记录。例如： sqlCopy code SELECT * FROM customers WHERE city = 'New York' ORDER BY last_name; 上面的查询语句将从名为 “customers” 的表中选择居住在纽约的客户记录，并按照客户姓氏的字母顺序对其进行排序。 在 SELECT 查询中使用 WHERE 子句和 ORDER BY 子句： sqlCopy code-- 从名为 Employees 的表中检索年龄大于等于 30 岁的员工，并按照姓氏进行升序排序 SELECT LastName, FirstName, Age FROM Employees WHERE Age &gt;= 30 ORDER BY LastName ASC; 在上面的示例中，我们使用 WHERE 子句过滤了年龄大于等于 30 岁的员工，并使用 ORDER BY 子句按照姓氏（LastName）进行升序排序。ASC 关键字表示升序排序（默认情况下，ORDER BY 子句会按照升序排序） 数据聚合： SQL支持对数据进行聚合操作，如求和、计数、平均值、最大值和最小值等，以便进行统计和分析。 聚合函数： 数据聚合通常使用聚合函数来执行计算。常见的聚合函数包括： COUNT()：计算数据行的数量。 SUM()：计算数据列的总和。 AVG()：计算数据列的平均值。 MAX()：计算数据列的最大值。 MIN()：计算数据列的最小值。 使用 GROUP BY 子句进行分组： 在执行聚合操作时，通常需要使用 GROUP BY 子句对数据进行分组。GROUP BY 子句将查询结果按照指定的列进行分组，然后对每个分组执行聚合函数计算。 sqlCopy codeSELECT department, COUNT(*) AS num_employees FROM employees GROUP BY department; 上面的查询语句将从名为 “employees” 的表中按照部门对员工进行分组，并计算每个部门的员工数量。 使用 HAVING 子句进行条件筛选： 与 WHERE 子句类似，HAVING 子句用于对分组后的数据进行条件筛选。它通常用于筛选聚合结果中满足特定条件的数据组。 sqlCopy codeSELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department HAVING AVG(salary) &gt; 50000; 上面的查询语句将从名为 “employees” 的表中按部门分组，并计算每个部门的平均工资。然后，它将仅显示平均工资超过 50000 的部门。 使用聚合函数进行数据聚合： sqlCopy code-- 统计名为 Orders 的表中订单的总数 SELECT COUNT(*) AS TotalOrders FROM Orders; 上面的示例中，我们使用 COUNT(*) 函数统计了 Orders 表中的订单总数，并将结果存储在 TotalOrders 列中。 另一个示例是计算销售总额的总和： sqlCopy code-- 计算名为 Sales 的表中销售总额 SELECT SUM(SalesAmount) AS TotalSales FROM Sales; 在这个示例中，我们使用 SUM(SalesAmount) 函数计算了 Sales 表中所有销售金额的总和，并将结果存储在 TotalSales 列中。 连接操作： SQL允许在多个表格之间建立连接，以便检索相关联的数据。常见的连接操作包括内连接、外连接和交叉连接。 在 SQL 中，连接操作通常使用 JOIN 关键字实现，有多种类型的连接可以使用，包括： 内连接（Inner Join）： 内连接返回两个表格中符合连接条件的行，即两个表格中的行必须具有相同的连接列值。 sqlCopy codeSELECT orders.order_id, customers.customer_name FROM orders INNER JOIN customers ON orders.customer_id = customers.customer_id; 左连接（Left Join）： 左连接返回左侧表格的所有行，以及与右侧表格中匹配的行。如果右侧表格中没有匹配的行，则返回 NULL 值。 sql codeSELECT customers.customer_name, orders.order_id FROM customers LEFT JOIN orders ON customers.customer_id = orders.customer_id; 右连接（Right Join）： 右连接返回右侧表格的所有行，以及与左侧表格中匹配的行。如果左侧表格中没有匹配的行，则返回 NULL 值。 sqlCopy codeSELECT orders.order_id, customers.customer_name FROM orders RIGHT JOIN customers ON orders.customer_id = customers.customer_id; 全连接（Full Join）： 全连接返回左侧表格和右侧表格的所有行，如果某一侧表格中没有匹配的行，则返回 NULL 值。 sqlCopy codeSELECT customers.customer_name, orders.order_id FROM customers FULL JOIN orders ON customers.customer_id = orders.customer_id; SQL作为一种标准化的查询语言，具有通用性和广泛应用性。无论是简单的数据检索还是复杂的数据处理和分析，SQL都可以满足各种数据库操作的需求。通过熟练掌握SQL语言，用户可以有效地管理和操作关系型数据库系统，从而更好地实现数据存储、管理和分析的目标。 数据库索引 数据库索引是一种提高检索效率的数据结构。创建索引可以加速数据表的查找操作。 索引结构： 索引通常是一个数据结构，它存储了表格中某一列或多列的值以及对应的行号。这样，当查询时，数据库系统可以使用索引快速定位到所需的数据行。 B-树索引（B-tree Index）： B-树索引是最常见和最广泛使用的索引结构之一。它是一种平衡树结构，具有良好的平衡性和高效的查询性能。B-树索引适用于范围查询和精确查询，并且在大多数关系型数据库管理系统中被广泛应用。 在SQL数据库中，创建B-树索引通常是通过CREATE INDEX语句来实现的。以下是一个示例代码： sqlCopy code-- 在名为 Employees 的表格中创建一个B-树索引，用于加速 LastName 列的检索 CREATE INDEX idx_lastname ON Employees(LastName); 上述代码在 Employees 表格的 LastName 列上创建了一个名为 idx_lastname 的B-树索引。 使用B-树索引可以加速数据的检索，特别是在涉及到大量数据的情况下。例如，如果我们要查询姓氏为 “Smith” 的员工信息，有了B-树索引，数据库引擎可以更快地定位到姓氏为 “Smith” 的员工记录，而不需要扫描整个表格。 特点： 平衡性： B-树是一种平衡树，确保在任何时候，从根节点到叶子节点的最长路径和最短路径之间的高度差不超过1。这种平衡性保证了树的深度相对较小，使得查询效率较高。 节点存储多个键值： B-树的节点可以存储多个键值，而不仅仅是两个。这有助于减少树的深度，提高查询效率。节点中的键值以升序排列。 支持范围查询： B-树支持范围查询，因为在一个节点中存在多个连续的键值，可以更容易地定位到范围内的数据。 适用于磁盘存储： B-树的设计考虑到了磁盘I/O的特性，使其适用于在磁盘上存储的场景。每个节点的大小通常被设计为磁盘页的大小，以最大限度地减少I/O操作。 工作原理： 树结构： B-树是一种多叉树，每个节点可以有多个子节点。树的根节点到叶子节点的路径长度是相等的。 插入操作： 当需要插入一个新的键值时，B-树首先在树中找到合适的位置，然后进行插入。如果插入导致节点的键值数量超过了限制，就会进行节点的分裂操作，将中间值提升到父节点，并将左右两侧的键值分别作为新的子节点。 删除操作： 当需要删除一个键值时，B-树首先找到键值所在的位置，然后进行删除。如果删除导致节点的键值数量低于限制，就会进行节点的合并操作，将相邻的节点进行合并。 查找操作： 查找操作从根节点开始，根据键值大小逐级定位到目标节点。由于B-树的平衡性，查找效率相对较高。 B+树索引（B+tree Index）： B+树索引是在B-树索引基础上进行改进的一种索引结构。与B-树相比，B+树索引在内部节点中不存储数据，只存储键值和指向叶子节点的指针，这样可以提高内部节点的利用率，减少树的深度，进而提高查询性能。 在关系型数据库中，创建B+树索引通常也是通过CREATE INDEX语句来实现的。以下是一个示例代码： sqlCopy code-- 在名为 Students 的表格中创建一个B+树索引，用于加速按照学生姓名（Name）的检索 CREATE INDEX idx_name ON Students(Name); 上述代码在 Students 表格的 Name 列上创建了一个名为 idx_name 的B+树索引。 使用B+树索引可以提高数据的检索速度，特别是在大数据量的情况下，它可以加速数据的查找、范围查询和排序操作。 特点： 分离索引和数据： 在B+树中，所有的数据都存储在叶子节点中，而非叶子节点只包含键值和指向下一个节点的指针。这种分离索引和数据的设计使得B+树的查询效率更高。 叶子节点形成有序链表： B+树的叶子节点按照键值大小顺序形成一个有序链表。这样的设计方便范围查询和范围扫描。 高度平衡： B+树保持了树的高度平衡，因此在进行数据检索时，需要的磁盘I/O次数相对较少，提高了查询效率。 适用于范围查询： 由于B+树的叶子节点形成有序链表，因此B+树非常适合执行范围查询操作。在范围查询时，只需要沿着叶子节点的链表进行遍历即可。 工作原理： 树结构： B+树是一种多叉树，每个非叶子节点存储的是键值和指向子节点的指针，叶子节点存储的是键值和对应的数据记录。 插入操作： 插入操作从根节点开始，根据键值大小逐级定位到叶子节点。如果叶子节点的容量已满，则进行分裂操作，并将中间值提升到父节点。 删除操作： 删除操作从根节点开始，根据键值大小逐级定位到叶子节点。如果删除导致叶子节点的数据量过小，则进行合并操作，并将合并后的节点与相邻节点连接。 查找操作： 查找操作从根节点开始，根据键值大小逐级定位到叶子节点。在叶子节点中进行二分查找或顺序查找，找到对应的数据记录。 哈希索引（Hash Index）： 哈希索引使用哈希表作为索引结构，它将索引列的值通过哈希函数映射到哈希表中的存储位置。哈希索引适用于等值查询，具有快速的检索速度，但不支持范围查询。 在MySQL中，哈希索引通常不是主流索引类型，但可以在特定场景下使用。 sqlCopy code-- 在名为 Students 的表格中创建一个哈希索引，用于加速按照学生ID（StudentID）的等值查询 CREATE INDEX idx_student_id ON Students(StudentID) USING HASH; 上述代码在 Students 表格的 StudentID 列上创建了一个名为 idx_student_id 的哈希索引。 特点： 快速的等值查询： 哈希索引使用哈希函数将索引列的值转换为哈希码，并将其映射到哈希表中的存储位置。因此，对于等值查询操作，哈希索引具有很快的查询速度。 不支持范围查询： 哈希索引通常不支持范围查询，因为哈希函数是将键值映射到特定的位置，而不是按照顺序存储。因此，范围查询的效率较低。 适用于内存存储： 哈希索引适用于内存存储的场景，因为哈希表在内存中的访问速度非常快。在内存中，哈希索引可以实现非常快速的查询操作。 冲突处理： 哈希函数可能会导致不同的键值映射到相同的哈希码，这种情况称为哈希冲突。为了解决冲突，哈希索引通常使用开放地址法、链地址法等方法进行冲突处理。 工作原理： 创建哈希表： 在创建哈希索引时，数据库系统会创建一个哈希表，用于存储哈希索引列的值和对应的存储位置。 计算哈希码： 当执行查询操作时，数据库系统首先使用哈希函数计算查询条件的哈希码。 定位数据： 哈希索引根据哈希码定位到哈希表中的存储位置，并检索对应的数据记录。 处理冲突： 如果发生哈希冲突，即多个键值映射到同一个哈希码的情况，哈希索引会使用冲突处理方法解决冲突，例如开放地址法或链地址法。 查询结果： 哈希索引返回匹配查询条件的数据记录，完成查询操作。 全文索引（Full-Text Index）： 全文索引是针对文本字段的一种特殊索引结构，用于支持全文搜索和文本检索功能。全文索引通常使用倒排索引（Inverted Index）实现，允许用户在文本数据中进行关键字搜索和模糊匹配。 在MySQL中创建全文索引： 假设我们有一个名为 articles 的表，其中包含了一个 content 列，存储了文章的内容。 sqlCopy code-- 在名为 articles 的表格中创建一个全文索引，用于加速文章内容的全文搜索 CREATE FULLTEXT INDEX idx_content ON articles(content); 上述代码在 articles 表的 content 列上创建了一个名为 idx_content 的全文索引。 一旦创建了全文索引，就可以使用全文搜索功能来进行文本搜索。以下是一个简单的例子： sqlCopy code-- 在 articles 表中进行全文搜索，查找包含 "database" 关键词的文章 SELECT * FROM articles WHERE MATCH(content) AGAINST('database'); 上述查询将返回所有包含 “database” 关键词的文章。全文搜索会考虑词根、同义词等方面，使得搜索更加灵活和准确。 特点： 支持文本搜索： 全文索引允许用户对文本数据进行全文搜索，而不仅仅是对固定的关键字或短语进行匹配。用户可以输入搜索词或关键字，系统会返回与搜索条件匹配的文本数据。 支持模糊匹配： 全文索引通常支持模糊匹配和通配符查询，用户可以使用通配符或模糊查询符号进行模糊匹配，从而扩大搜索范围。 自然语言处理： 全文索引通常会使用自然语言处理技术，例如分词、词干提取和同义词处理，从而提高搜索的准确性和效率。 语言支持： 全文索引通常支持多种语言，可以处理不同语言的文本数据，并提供相应的搜索和分析功能。 工作原理： 建立索引： 在全文索引中，数据库系统会对文本字段中的单词和短语建立索引。建立索引的过程包括分词、词干提取、同义词处理等步骤。 分词处理： 在建立索引时，全文索引会对文本数据进行分词处理，将文本分割成单词或短语，并去除停用词等无意义的词语。 建立倒排索引： 全文索引通常使用倒排索引（Inverted Index）结构，将每个单词或短语与包含该词语的文档进行关联。倒排索引提供了快速查找单词或短语出现位置的能力。 搜索操作： 当执行全文搜索操作时，数据库系统会根据用户输入的搜索条件，在全文索引中进行搜索，并返回匹配的文档列表。 评分和排名： 全文索引通常会根据匹配的程度对搜索结果进行评分和排名，从而提供更加精确和相关的搜索结果。 空间索引（Spatial Index）： 空间索引是用于地理空间数据的一种特殊索引结构，支持空间查询和空间分析操作。空间索引通常使用R树（R-tree）或其变体实现，用于加速空间数据的检索和查询。 PostgreSQL数据库中创建和使用空间索引（以PostGIS为例）： 假设我们有一个名为 locations 的表，其中包含了一个 geom 列，存储了位置的几何信息。 sqlCopy code-- 在名为 locations 的表格中创建一个空间索引，用于加速位置数据的空间查询 CREATE INDEX idx_geom ON locations USING GIST (geom); 上述代码在 locations 表的 geom 列上创建了一个名为 idx_geom 的空间索引，使用了GIST（Generalized Search Tree）索引类型，这是PostGIS中的一种常用索引类型。 一旦创建了空间索引，就可以使用空间查询功能来进行位置数据的空间查询。以下是一个简单的例子： sqlCopy code-- 在 locations 表中进行空间查询，查找包含指定点的位置 SELECT * FROM locations WHERE ST_Contains(geom, ST_GeomFromText('POINT(10 20)')); 上述查询将返回所有包含指定点的位置数据。在这个例子中，ST_Contains函数用于判断一个几何对象是否包含另一个几何对象，ST_GeomFromText函数用于将文本表示的几何对象转换为几何对象。 特点： 支持地理空间数据： 空间索引适用于具有地理空间属性的数据，例如地理坐标、地图数据、空间区域等。 快速的空间查询： 空间索引可以加速空间数据的查询操作，例如空间范围查询、距离查询、相交查询等。 支持空间分析： 空间索引提供了空间数据分析功能，例如空间聚合、空间缓冲区分析、空间连接等。 适用于多种数据类型： 空间索引不仅适用于点、线、面等基本地理要素数据，还可以处理多种复杂的空间数据类型，例如多边形、多点、多线等。 工作原理： 空间数据模型： 空间索引基于空间数据模型，将地理空间数据抽象为几何对象，例如点、线、面等。 索引结构： 空间索引使用特定的索引结构来存储和组织空间数据，常见的空间索引结构包括R树（R-tree）和其变种，例如R树、R*树、Quadtree等。 数据分割： 空间索引将空间数据分割成多个空间单元，每个空间单元都对应一个索引节点。这样可以提高查询效率，减少搜索空间。 索引查询： 当执行空间查询操作时，数据库系统根据查询条件在空间索引中进行搜索，找到与查询条件相匹配的空间对象。 空间关系判断： 空间索引支持空间关系判断，例如判断两个空间对象之间的相交关系、包含关系、相邻关系等。 位图索引（Bitmap Index）： 位图索引是一种特殊的索引结构，适用于低基数（Cardinality）列，即具有较少唯一值的列。位图索引将每个唯一值映射到一个位图中，以便进行位运算快速检索满足条件的行。 Oracle数据库中创建和使用位图索引： 假设我们有一个名为 employees 的表，其中包含了一个存储员工部门的列 department_id，我们希望为这个列创建一个位图索引。 首先，创建位图索引： sqlCopy code CREATE BITMAP INDEX idx_department_id ON employees(department_id); 上述代码在 employees 表的 department_id 列上创建了一个名为 idx_department_id 的位图索引。 一旦创建了位图索引，可以使用位图索引来加速数据的检索和过滤。以下是一个简单的例子： sqlCopy code-- 查询部门ID为 100 的员工 SELECT * FROM employees WHERE department_id = 100; 在上述查询中，如果数据库优化器选择使用位图索引，它会利用位图索引快速地找到部门ID为 100 的员工。 特点： 适用于低基数列： 位图索引适用于具有低基数（即唯一值较少）的列。在这种情况下，位图索引的存储效率较高。 压缩存储： 位图索引可以通过压缩技术来节省存储空间。由于每个位图只包含两种值（0和1），因此可以使用压缩算法来减少存储空间。 快速的等值查询： 位图索引能够快速地执行等值查询操作。通过将位图与查询条件进行位运算，可以快速定位到匹配的行。 支持位运算操作： 位图索引支持位运算操作，例如AND、OR、NOT等，这使得它可以轻松地处理多个位图之间的逻辑操作。 工作原理： 位图创建： 在创建位图索引时，数据库系统会为每个唯一的列值创建一个位图。位图的长度等于数据表中的行数。 位图填充： 对于每个位图，如果对应的列值在数据表的某一行中存在，则在位图中的相应位置置为1，否则置为0。 查询操作： 当执行等值查询操作时，数据库系统会将查询条件转换为位图形式，并与位图索引进行位运算。根据位运算的结果，确定匹配的行。 位图合并： 对于涉及多个位图的查询，位图索引可以执行位运算操作将多个位图合并，从而得到最终的匹配结果。 性能考虑： 位图索引的性能受到存储空间和内存访问速度的影响。在处理大型数据表时，位图索引可能会占用大量的存储空间，并且需要在内存中加载位图进行操作，因此需要仔细评估其性能。 索引类型： 数据库系统支持不同类型的索引，包括： 单列索引（Single-column Index）： 基于单个列的值创建的索引。 复合索引（Composite Index）： 基于多个列的值创建的索引。 唯一索引（Unique Index）： 索引列中的值必须唯一。 主键索引（Primary Key Index）： 用于唯一标识表格中每一行的索引。 聚集索引（Clustered Index）： 索引中的数据按照物理顺序存储，常与主键关联。 非聚集索引（Non-clustered Index）： 索引中的数据存储在与表格数据分开的位置。 单列索引（Single-column Index）： 单列索引基于表中的单个列创建。它是最简单的索引类型，适用于对单个列进行等值查询或范围查询的情况。常见的单列索引包括B-树索引和哈希索引。 复合索引（Composite Index）： 复合索引基于表中的多个列创建。它适用于需要同时考虑多个列的查询条件，可以提高这些列上的联合查询性能。复合索引的顺序对查询性能有影响，应根据查询的频率和条件选择适当的列顺序。 唯一索引（Unique Index）： 唯一索引要求索引列的值必须是唯一的，不允许重复值。它通常用于加速对唯一键的等值查询，并确保表中的数据完整性。 主键索引（Primary Key Index）： 主键索引是唯一索引的一种特殊形式，它用于标识表中的唯一行。主键索引不允许空值，通常用于加速对主键列的等值查询。 全文索引（Full-Text Index）： 全文索引用于对文本数据进行全文搜索和检索。它适用于包含大量文本的列，例如文章内容或博客评论。全文索引可以提供对文本数据的高效搜索功能。 空间索引（Spatial Index）： 空间索引用于处理具有地理空间属性的数据，例如地理坐标或地图数据。它支持空间查询和分析操作，常用的结构包括R树。 位图索引（Bitmap Index）： 位图索引适用于低基数列，即具有较少唯一值的列。它将每个唯一值映射到一个位图中，用于加速位运算检索。 哈希索引（Hash Index）： 哈希索引使用哈希函数将索引列的值映射到哈希表中，适用于等值查询。然而，哈希索引不适用于范围查询，因为哈希函数无法保证有序性。 单列索引： sqlCopy code-- 在名为 Employees 的表格中创建一个单列索引，用于加速 LastName 列的检索 CREATE INDEX idx_lastname ON Employees(LastName); 复合索引： sqlCopy code-- 在名为 Employees 的表格中创建一个复合索引，用于加速 LastName 和 FirstName 列的组合检索 CREATE INDEX idx_lastname_firstname ON Employees(LastName, FirstName); 唯一索引： sqlCopy code-- 在名为 Employees 的表格中创建一个唯一索引，确保 EmployeeID 列的数值唯一 CREATE UNIQUE INDEX idx_employeeid_unique ON Employees(EmployeeID); 上述代码示例是基于 MySQL 语法的简化版本，实际使用时需要根据所选用的数据库系统和其支持的语法进行调整。不同数据库系统可能会有不同的索引实现和语法。 在关系型数据库中，主键索引、聚集索引和非聚集索引是常见的索引类型，它们在数据库中起着不同的作用。 主键索引： 主键索引是一种唯一索引，用于唯一标识表中的每一行数据。主键索引确保表中的每一行都具有唯一的标识，通常是通过一个或多个列的组合来定义的。在大多数数据库系统中，主键索引会自动创建，如果没有显式指定主键索引，数据库系统会自动创建一个主键索引。 在 MySQL 中创建主键索引的示例代码如下： -- 在名为 Employees 的表格中创建一个主键索引，用于标识 EmployeeID 列的唯一性 ALTER TABLE Employees ADD PRIMARY KEY (EmployeeID); 聚集索引： 聚集索引是一种特殊的索引，它指定了数据在物理存储中的顺序，表中的数据按照聚集索引的顺序进行存储。在大多数情况下，主键索引就是一种聚集索引，因为主键索引定义了表中数据的物理存储顺序。 在 SQL Server 中，主键索引默认就是聚集索引，示例代码如下： -- 在名为 Employees 的表格中创建一个主键索引，用于标识 EmployeeID 列的唯一性 ALTER TABLE Employees ADD CONSTRAINT PK_Employees PRIMARY KEY CLUSTERED (EmployeeID); 非聚集索引： 非聚集索引是一种独立于数据物理存储顺序的索引，在查询时使用非聚集索引可以快速定位到目标数据，然后再根据索引指向的位置获取数据。非聚集索引通常适用于那些没有指定聚集索引或者需要额外的索引来优化查询性能的情况。 在 MySQL 中创建非聚集索引的示例代码如下： -- 在名为 Employees 的表格中创建一个非聚集索引，用于加速 LastName 列的检索 CREATE INDEX idx_lastname ON Employees(LastName); 需要注意的是，每个数据库系统的索引实现和语法可能会有所不同，上述示例是基于 MySQL 和 SQL Server 的实现。在实际使用时，需要根据所选用的数据库系统和其支持的语法进行调整。 索引创建： 索引可以在表格创建时定义，也可以在表格已存在时单独创建。创建索引时需要考虑索引列的选择、索引类型、索引的大小等因素，以及对查询性能的影响。 选择索引列： 首先确定需要创建索引的列。通常选择作为查询条件或经常用于检索数据的列作为索引列。索引列的选择应基于查询的频率、数据分布和性能需求。 选择索引类型： 根据索引列的特点和查询需求选择适当的索引类型。常见的索引类型包括单列索引、复合索引、唯一索引等。每种索引类型都有其适用的场景和限制。 创建索引语句： 使用数据库管理系统提供的DDL（数据定义语言）语句来创建索引。具体的创建索引语句语法和选项取决于所使用的数据库管理系统。以下是一些常见数据库管理系统中创建索引的示例： 在 MySQL 中，创建单列索引的语法如下： sqlCopy code CREATE INDEX index_name ON table_name(column_name); 创建复合索引： sqlCopy code CREATE INDEX index_name ON table_name(column1, column2); 创建唯一索引： sqlCopy code CREATE UNIQUE INDEX index_name ON table_name(column_name); 执行创建索引语句： 执行创建索引的语句，让数据库管理系统在后台完成索引的创建过程。创建大型表格的索引可能需要一些时间，取决于表格大小和系统负载等因素。 验证索引创建： 创建索引后，可以通过查询数据库系统的系统表格或元数据来验证索引是否成功创建。在大多数数据库系统中，可以查询系统表格或使用特定的管理工具来查看索引的信息和状态 索引优势： 索引可以加快数据检索的速度，特别是在大型数据表格中。通过使用索引，数据库系统可以避免全表扫描，而是直接定位到符合查询条件的数据行，从而提高了查询的效率。 提高查询性能： 索引可以加速数据检索操作，通过创建索引，数据库系统可以避免全表扫描，而是直接定位到符合查询条件的数据行，从而提高了查询的效率。 加速排序和分组操作： 对于需要排序和分组的查询，索引可以大大减少排序和分组操作的时间复杂度，提高了查询的速度。 保证数据完整性： 唯一索引和主键索引可以确保索引列中的数据唯一，从而保证了表格数据的完整性。 支持连接操作： 索引可以加速连接操作，特别是在复杂的查询中，通过合适的索引可以使连接操作更加高效。 索引注意事项： 尽管索引可以提高查询性能，但过多或不必要的索引可能会增加数据库写操作的成本，因为每次写操作都需要维护索引。此外，索引也需要占用存储空间，因此需要权衡查询性能和存储资源的使用。 过度索引化： 过度创建索引可能会导致数据库性能下降。每个索引都需要额外的存储空间和维护成本，因此需要权衡创建索引的数量和对性能的影响。 更新代价高昂： 对表格进行更新、插入和删除操作时，数据库系统需要更新索引，这可能会导致写操作的性能下降。因此，需要在索引设计时考虑写操作的频率和成本。 选择适当的索引列： 索引的效果取决于选择的索引列，选择不合适的索引列可能导致索引失效或性能下降。需要根据查询的需求、数据分布和查询频率等因素选择合适的索引列。 定期维护和优化： 索引需要定期维护和优化，以确保其与表格数据的同步和一致性。随着数据库的使用和演化，可能需要调整和优化索引，以满足新的查询需求和性能要求。 使用合适的索引类型： 不同类型的索引适用于不同的查询需求和场景。需要根据具体的业务需求和查询模式选择合适的索引类型，以提高查询性能和优化数据库操作。 结论 数据库原理是构建稳健、高效和可靠数据库系统的基础。了解这些原理对于数据库设计和管理至关重要。]]></summary></entry><entry><title type="html">数据结构</title><link href="https://right202209.github.io/blog/Date-Structure/" rel="alternate" type="text/html" title="数据结构" /><published>2024-02-07T00:00:00+00:00</published><updated>2024-02-07T00:00:00+00:00</updated><id>https://right202209.github.io/blog/Date%20Structure</id><content type="html" xml:base="https://right202209.github.io/blog/Date-Structure/"><![CDATA[<p>数据结构。</p>

<h3 id="1-数组array">1. 数组（Array）</h3>

<ul>
  <li>
    <p><strong>解释</strong>：</p>
  </li>
  <li>
    <p>数组是一种线性数据结构，由一系列连续的内存单元组成，用于存储相同类型的元素。</p>
  </li>
  <li>
    <p><strong>基本操作</strong>：</p>
  </li>
  <li>
    <p>访问、插入、删除、查找。</p>
  </li>
  <li>
    <p><strong>示例代码</strong>（Python）：</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 创建数组
</span><span class="n">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
  
<span class="c1"># 访问元素
</span><span class="k">print</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>  <span class="c1"># 输出：1
</span>  
<span class="c1"># 插入元素
</span><span class="n">arr</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
  
<span class="c1"># 删除元素
</span><span class="k">del</span> <span class="n">arr</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
  
<span class="c1"># 查找元素
</span><span class="k">if</span> <span class="mi">3</span> <span class="ow">in</span> <span class="n">arr</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Element found"</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="2-链表linked-list">2. 链表（Linked List）</h3>

<ul>
  <li>
    <p><strong>解释</strong>：</p>
  </li>
  <li>
    <p>链表是一种线性数据结构，由一系列节点组成，每个节点包含数据和指向下一个节点的引用。</p>
  </li>
  <li>
    <p><strong>基本操作</strong>：</p>
  </li>
  <li>
    <p>插入、删除、查找。</p>
  </li>
  <li>
    <p><strong>示例代码</strong>（Python）：</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 定义节点
</span><span class="k">class</span> <span class="nc">Node</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span>
        <span class="bp">self</span><span class="p">.</span><span class="nb">next</span> <span class="o">=</span> <span class="bp">None</span>
  
<span class="c1"># 创建链表
</span><span class="k">class</span> <span class="nc">LinkedList</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">head</span> <span class="o">=</span> <span class="bp">None</span>
  
    <span class="c1"># 在链表末尾插入节点
</span>    <span class="k">def</span> <span class="nf">append</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="n">new_node</span> <span class="o">=</span> <span class="n">Node</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">head</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">head</span> <span class="o">=</span> <span class="n">new_node</span>
            <span class="k">return</span>
        <span class="n">last_node</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">head</span>
        <span class="k">while</span> <span class="n">last_node</span><span class="p">.</span><span class="nb">next</span><span class="p">:</span>
            <span class="n">last_node</span> <span class="o">=</span> <span class="n">last_node</span><span class="p">.</span><span class="nb">next</span>
        <span class="n">last_node</span><span class="p">.</span><span class="nb">next</span> <span class="o">=</span> <span class="n">new_node</span>
  
    <span class="c1"># 在链表中删除节点
</span>    <span class="k">def</span> <span class="nf">delete</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
        <span class="n">temp</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">head</span>
        <span class="k">if</span> <span class="n">temp</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">temp</span><span class="p">.</span><span class="n">data</span> <span class="o">==</span> <span class="n">key</span><span class="p">:</span>
                <span class="bp">self</span><span class="p">.</span><span class="n">head</span> <span class="o">=</span> <span class="n">temp</span><span class="p">.</span><span class="nb">next</span>
                <span class="n">temp</span> <span class="o">=</span> <span class="bp">None</span>
                <span class="k">return</span>
        <span class="k">while</span> <span class="n">temp</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">temp</span><span class="p">.</span><span class="n">data</span> <span class="o">==</span> <span class="n">key</span><span class="p">:</span>
                <span class="k">break</span>
            <span class="n">prev</span> <span class="o">=</span> <span class="n">temp</span>
            <span class="n">temp</span> <span class="o">=</span> <span class="n">temp</span><span class="p">.</span><span class="nb">next</span>
        <span class="k">if</span> <span class="n">temp</span> <span class="o">==</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">return</span>
        <span class="n">prev</span><span class="p">.</span><span class="nb">next</span> <span class="o">=</span> <span class="n">temp</span><span class="p">.</span><span class="nb">next</span>
        <span class="n">temp</span> <span class="o">=</span> <span class="bp">None</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="栈">栈</h3>

<p>笔记：栈（Stack）是一种线性数据结构，具有后进先出（Last In, First Out，LIFO）的特性，即最后进入栈的元素最先被访问或移出。栈通常具有以下基本操作：</p>

<ol>
  <li><strong>压入（Push）</strong>：将元素添加到栈的顶部。</li>
  <li><strong>弹出（Pop）</strong>：从栈顶移除元素。</li>
  <li><strong>查看栈顶元素（Peek）</strong>：获取栈顶的元素值，但不对栈进行修改。</li>
  <li><strong>判空（isEmpty）</strong>：判断栈是否为空。</li>
  <li><strong>获取栈的大小（getSize）</strong>：获取栈中元素的数量。</li>
</ol>

<p>笔记：栈可以通过数组或链表实现。</p>

<h3 id="栈的应用">栈的应用：</h3>

<ol>
  <li><strong>函数调用栈</strong>：在编程中，函数调用时使用栈来保存函数的局部变量和返回地址。</li>
  <li><strong>表达式求值</strong>：如中缀表达式转换为后缀表达式并求值。</li>
  <li><strong>内存管理</strong>：栈用于跟踪内存中变量的分配和释放。</li>
  <li><strong>浏览器历史记录</strong>：浏览器使用栈来实现“后退”和“前进”按钮的功能。</li>
  <li><strong>撤销操作</strong>：许多应用程序使用栈来实现撤销操作。</li>
</ol>

<h3 id="栈的示例代码python">栈的示例代码（Python）：</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Stack</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">isEmpty</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">items</span> <span class="o">==</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">push</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">pop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">():</span>
            <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">.</span><span class="n">pop</span><span class="p">()</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"Stack is empty"</span>

    <span class="k">def</span> <span class="nf">peek</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">():</span>
            <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"Stack is empty"</span>

    <span class="k">def</span> <span class="nf">getSize</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">)</span>

<span class="c1"># 示例
</span><span class="n">stack</span> <span class="o">=</span> <span class="n">Stack</span><span class="p">()</span>
<span class="n">stack</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">stack</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">stack</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Stack peek:"</span><span class="p">,</span> <span class="n">stack</span><span class="p">.</span><span class="n">peek</span><span class="p">())</span>  <span class="c1"># 输出：3
</span><span class="k">print</span><span class="p">(</span><span class="s">"Stack size:"</span><span class="p">,</span> <span class="n">stack</span><span class="p">.</span><span class="n">getSize</span><span class="p">())</span>  <span class="c1"># 输出：3
</span><span class="k">print</span><span class="p">(</span><span class="s">"Popped item:"</span><span class="p">,</span> <span class="n">stack</span><span class="p">.</span><span class="n">pop</span><span class="p">())</span>  <span class="c1"># 输出：3
</span></code></pre></div></div>

<p>笔记：栈是一种简单而强大的数据结构，常用于许多编程场景中。理解栈的原理和应用有助于提高编程效率和解决问题的能力。</p>

<h2 id="队列">队列</h2>

<p>笔记：队列（Queue）是一种线性数据结构，具有先进先出（First In, First Out，FIFO）的特性，即最先进入队列的元素最先被访问或移出。队列通常具有以下基本操作：</p>

<ol>
  <li><strong>入队（Enqueue）</strong>：将元素添加到队列的尾部。</li>
  <li><strong>出队（Dequeue）</strong>：从队列的头部移除元素。</li>
  <li><strong>查看队首元素（Peek）</strong>：获取队列头部的元素值，但不对队列进行修改。</li>
  <li><strong>判空（isEmpty）</strong>：判断队列是否为空。</li>
  <li><strong>获取队列的大小（getSize）</strong>：获取队列中元素的数量。</li>
</ol>

<p>笔记：队列可以通过数组或链表实现。</p>

<h3 id="队列的应用">队列的应用：</h3>

<ol>
  <li><strong>任务调度</strong>：操作系统中进程的调度使用队列来实现先来先服务（FCFS）或其他调度算法。</li>
  <li><strong>消息传递</strong>：在计算机网络和消息队列系统中，队列用于传递和处理消息。</li>
  <li><strong>广度优先搜索（BFS）</strong>：在图的搜索算法中，BFS使用队列来保存遍历的顶点。</li>
  <li><strong>缓存</strong>：在计算机系统中，队列用于实现缓存淘汰策略，如最近最少使用（LRU）。</li>
  <li><strong>打印队列</strong>：打印机使用队列来管理打印作业的顺序。</li>
</ol>

<h3 id="队列的示例代码python">队列的示例代码（Python）：</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Queue</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">isEmpty</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">items</span> <span class="o">==</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">enqueue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">dequeue</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">():</span>
            <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"Queue is empty"</span>

    <span class="k">def</span> <span class="nf">peek</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">():</span>
            <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"Queue is empty"</span>

    <span class="k">def</span> <span class="nf">getSize</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">items</span><span class="p">)</span>

<span class="c1"># 示例
</span><span class="n">queue</span> <span class="o">=</span> <span class="n">Queue</span><span class="p">()</span>
<span class="n">queue</span><span class="p">.</span><span class="n">enqueue</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">queue</span><span class="p">.</span><span class="n">enqueue</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">queue</span><span class="p">.</span><span class="n">enqueue</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Queue peek:"</span><span class="p">,</span> <span class="n">queue</span><span class="p">.</span><span class="n">peek</span><span class="p">())</span>  <span class="c1"># 输出：1
</span><span class="k">print</span><span class="p">(</span><span class="s">"Queue size:"</span><span class="p">,</span> <span class="n">queue</span><span class="p">.</span><span class="n">getSize</span><span class="p">())</span>  <span class="c1"># 输出：3
</span><span class="k">print</span><span class="p">(</span><span class="s">"Dequeued item:"</span><span class="p">,</span> <span class="n">queue</span><span class="p">.</span><span class="n">dequeue</span><span class="p">())</span>  <span class="c1"># 输出：1
</span></code></pre></div></div>

<p>笔记：队列是一种常用的数据结构，在许多领域都有广泛的应用。理解队列的原理和使用方法有助于提高编程的效率和解决问题的能力。</p>

<p>笔记：以下是C++代码示例，涵盖了数组、链表、队列、树、图、集合和映射的基本实现，并附有简要解释：</p>

<h3 id="数组array">数组（Array）：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>数组是一种用于存储相同类型元素的线性数据结构。在这个例子中，我们创建了一个包含五个整数的数组，并通过循环遍历打印数组中的元素。</li>
</ul>

<h3 id="链表linked-list">链表（Linked List）：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Node</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">;</span>
    <span class="n">Node</span><span class="o">*</span> <span class="n">next</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">Node</span><span class="o">*</span> <span class="n">head</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Node</span><span class="p">();</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>
    <span class="n">Node</span><span class="o">*</span> <span class="n">second</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Node</span><span class="p">();</span>
    <span class="n">second</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">second</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">second</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>链表是一种由节点组成的线性数据结构，每个节点包含数据和指向下一个节点的指针。在这个例子中，我们创建了两个节点，并使用指针连接它们，形成一个简单的链表。</li>
</ul>

<h3 id="队列queue">队列（Queue）：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>队列是一种先进先出（FIFO）的线性数据结构，支持在队尾插入元素，队头删除元素。在这个例子中，我们使用标准库中的队列来演示队列的基本操作。</li>
</ul>

<h3 id="树tree">树（Tree）：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">TreeNode</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">;</span>
    <span class="n">TreeNode</span><span class="o">*</span> <span class="n">left</span><span class="p">;</span>
    <span class="n">TreeNode</span><span class="o">*</span> <span class="n">right</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">TreeNode</span><span class="o">*</span> <span class="n">root</span> <span class="o">=</span> <span class="k">new</span> <span class="n">TreeNode</span><span class="p">();</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="k">new</span> <span class="n">TreeNode</span><span class="p">();</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="k">new</span> <span class="n">TreeNode</span><span class="p">();</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>树是一种非线性数据结构，由节点组成，每个节点有一个父节点和零个或多个子节点。在这个例子中，我们创建了一个简单的二叉树，并分配了节点的数据和连接关系。</li>
</ul>

<h3 id="图graph">图（Graph）：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">graph</span> <span class="o">=</span> <span class="p">{</span>
        <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span>
        <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
        <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
        <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">}</span>
    <span class="p">};</span>
    <span class="c1">// 可以根据需要对图进行进一步的操作</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>图是由节点和边组成的非线性数据结构。在这个例子中，我们使用邻接矩阵表示图的连接关系。</li>
</ul>

<h3 id="集合set">集合（Set）：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;set&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">s</span><span class="p">;</span>
    <span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
    <span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">s</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">it</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>集合是一种不重复元素的数据结构。在这个例子中，我们使用集合来存储整数，并通过迭代器遍历集合中的元素。</li>
</ul>

<h3 id="映射map">映射（Map）：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">map</span><span class="o">&lt;</span><span class="n">string</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">m</span><span class="p">;</span>
    <span class="n">m</span><span class="p">[</span><span class="s">"one"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">m</span><span class="p">[</span><span class="s">"two"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">m</span><span class="p">[</span><span class="s">"three"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">m</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">first</span> <span class="o">&lt;&lt;</span> <span class="s">": "</span> <span class="o">&lt;&lt;</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>映射是一种键值对的数据结构。在这个例子中，我们使用映射来存储字符串和对应的整数，并通过迭代器遍历映射中的键值对。</li>
</ul>

<p>笔记：这些示例展示了 C++ 中基本数据结构的简单实现，帮助理解它们的基本概念和用法。</p>

<p>笔记：以下是C代码示例，涵盖了数组、链表、队列、树、图、集合和映射的基本实现，并附有简要解释：</p>

<h3 id="数组array-1">数组（Array）：</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>数组是一种用于存储相同类型元素的线性数据结构。在这个例子中，我们创建了一个包含五个整数的数组，并通过循环遍历打印数组中的元素。</li>
</ul>

<h3 id="链表linked-list-1">链表（Linked List）：</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span>
<span class="k">struct</span> <span class="n">Node</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">Node</span><span class="o">*</span> <span class="n">next</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">Node</span><span class="o">*</span> <span class="n">head</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">Node</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">Node</span><span class="p">));</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">Node</span><span class="o">*</span> <span class="n">second</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">Node</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">Node</span><span class="p">));</span>
    <span class="n">second</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">second</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">second</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>链表是一种由节点组成的线性数据结构，每个节点包含数据和指向下一个节点的指针。在这个例子中，我们创建了两个节点，并使用指针连接它们，形成一个简单的链表。</li>
</ul>

<h3 id="队列queue-1">队列（Queue）：</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span>
<span class="k">struct</span> <span class="n">Queue</span> <span class="p">{</span>
    <span class="kt">int</span><span class="o">*</span> <span class="n">items</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">front</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">rear</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">capacity</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">Queue</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">capacity</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">front</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">rear</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">items</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">q</span><span class="p">.</span><span class="n">capacity</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
    <span class="n">q</span><span class="p">.</span><span class="n">items</span><span class="p">[</span><span class="o">++</span><span class="n">q</span><span class="p">.</span><span class="n">rear</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">items</span><span class="p">[</span><span class="o">++</span><span class="n">q</span><span class="p">.</span><span class="n">rear</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">items</span><span class="p">[</span><span class="o">++</span><span class="n">q</span><span class="p">.</span><span class="n">rear</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">q</span><span class="p">.</span><span class="n">front</span> <span class="o">&lt;=</span> <span class="n">q</span><span class="p">.</span><span class="n">rear</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">q</span><span class="p">.</span><span class="n">items</span><span class="p">[</span><span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="o">++</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">free</span><span class="p">(</span><span class="n">q</span><span class="p">.</span><span class="n">items</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>队列是一种先进先出（FIFO）的线性数据结构，支持在队尾插入元素，队头删除元素。在这个例子中，我们使用数组实现了一个简单的队列。</li>
</ul>

<h3 id="树tree-1">树（Tree）：</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span>
<span class="k">struct</span> <span class="n">TreeNode</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">TreeNode</span><span class="o">*</span> <span class="n">left</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">TreeNode</span><span class="o">*</span> <span class="n">right</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">TreeNode</span><span class="o">*</span> <span class="n">root</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">TreeNode</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">TreeNode</span><span class="p">));</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">TreeNode</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">TreeNode</span><span class="p">));</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">TreeNode</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">TreeNode</span><span class="p">));</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>树是一种非线性数据结构，由节点组成，每个节点有一个父节点和零个或多个子节点。在这个例子中，我们创建了一个简单的二叉树，并分配了节点的数据和连接关系。</li>
</ul>

<h3 id="图graph-1">图（Graph）：</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">graph</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
        <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span>
        <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
        <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
        <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">}</span>
    <span class="p">};</span>
    <span class="c1">// 可以根据需要对图进行进一步的操作</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>图是由节点和边组成的非线性数据结构。在这个例子中，我们使用邻接矩阵表示图的连接关系。</li>
</ul>

<h3 id="集合set-1">集合（Set）：</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdbool.h&gt;</span><span class="cp">
</span>
<span class="cp">#define SET_SIZE 5
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">set</span><span class="p">[</span><span class="n">SET_SIZE</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">SET_SIZE</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">set</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>集合是一种不重复元素的数据结构。在这个例子中，我们创建了一个整数集合并打印了集合中的元素。</li>
</ul>

<h3 id="映射map-1">映射（Map）：</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">Map</span> <span class="p">{</span>
        <span class="kt">char</span> <span class="n">key</span><span class="p">;</span>
        <span class="kt">int</span> <span class="n">value</span><span class="p">;</span>
    <span class="p">};</span>
    <span class="k">struct</span> <span class="n">Map</span> <span class="n">map</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
        <span class="p">{</span><span class="sc">'a'</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
        <span class="p">{</span><span class="sc">'b'</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span>
        <span class="p">{</span><span class="sc">'c'</span><span class="p">,</span> <span class="mi">3</span><span class="p">}</span>
    <span class="p">};</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%c: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">map</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">key</span><span class="p">,</span> <span class="n">map</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">value</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>映射是一种键值对的数据结构。在这个例子中，我们使用结构体数组实现了一个简单的映射，并打印了映射中的键值对。</li>
</ul>

<p>笔记：这些示例展示了 C 中基本数据结构的简单实现，帮助理解它们的基本概念和用法。</p>

<h3 id="c语言实现">C语言实现：</h3>

<h4 id="平衡树balanced-tree">平衡树（Balanced Tree）：</h4>

<p>笔记：平衡树是一种树形数据结构，确保在插入或删除元素时树的高度保持较小的增量，从而保持树的平衡性。常见的平衡树包括AVL树、红黑树等。</p>

<h4 id="堆heap">堆（Heap）：</h4>

<p>笔记：堆是一种特殊的树形数据结构，通常是一个数组对象，用于表示完全二叉树。堆的性质是父节点的键值总是保持固定的序关系，如小顶堆中父节点的值小于或等于子节点的值，大顶堆则相反。</p>

<h4 id="哈希表hash-table">哈希表（Hash Table）：</h4>

<p>笔记：哈希表是一种数据结构，用于存储键值对。哈希表通过将键映射到表中的一个位置来加快查找速度。在哈希表中，键的值经过哈希函数计算后得到一个索引，然后将值存储在对应的索引位置。</p>

<h4 id="图算法graph-algorithms">图算法（Graph Algorithms）：</h4>

<p>笔记：图算法是针对图数据结构的算法，用于解决图中的各种问题，如最短路径、最小生成树、图的遍历等。常见的图算法包括深度优先搜索（DFS）、广度优先搜索（BFS）、Dijkstra算法、Prim算法等。</p>

<h3 id="c语言实现-1">C++语言实现：</h3>

<h4 id="平衡树balanced-tree-1">平衡树（Balanced Tree）：</h4>

<p>笔记：C++中可以使用STL提供的<code class="language-plaintext highlighter-rouge">set</code>和<code class="language-plaintext highlighter-rouge">map</code>来实现平衡树，<code class="language-plaintext highlighter-rouge">set</code>基于红黑树实现，<code class="language-plaintext highlighter-rouge">map</code>是基于红黑树实现的关联容器，确保元素有序。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;set&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// 使用set实现平衡树</span>
    <span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">balancedTree</span><span class="p">;</span>
    <span class="n">balancedTree</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="n">balancedTree</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">balancedTree</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
    <span class="c1">// 使用map实现平衡树</span>
    <span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">balancedMap</span><span class="p">;</span>
    <span class="n">balancedMap</span><span class="p">[</span><span class="sc">'a'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">balancedMap</span><span class="p">[</span><span class="sc">'b'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">balancedMap</span><span class="p">[</span><span class="sc">'c'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="堆heap-1">堆（Heap）：</h4>

<p>笔记：C++中可以使用STL提供的<code class="language-plaintext highlighter-rouge">priority_queue</code>来实现堆，它是一个基于堆的优先队列容器，支持在队列的头部进行快速插入和删除操作。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// 最小堆</span>
    <span class="n">priority_queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">greater</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">minHeap</span><span class="p">;</span>
    <span class="n">minHeap</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="n">minHeap</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">minHeap</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
    <span class="c1">// 最大堆</span>
    <span class="n">priority_queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">maxHeap</span><span class="p">;</span>
    <span class="n">maxHeap</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="n">maxHeap</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">maxHeap</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="哈希表hash-table-1">哈希表（Hash Table）：</h4>

<p>笔记：C++中可以使用STL提供的<code class="language-plaintext highlighter-rouge">unordered_map</code>来实现哈希表，它是一个基于哈希函数的关联容器，支持在常数时间内进行插入、删除和查找操作。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;unordered_map&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">string</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">hashTable</span><span class="p">;</span>
    <span class="n">hashTable</span><span class="p">[</span><span class="s">"apple"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
    <span class="n">hashTable</span><span class="p">[</span><span class="s">"banana"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">hashTable</span><span class="p">[</span><span class="s">"orange"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">15</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="图算法graph-algorithms-1">图算法（Graph Algorithms）：</h4>

<p>笔记：C++中可以使用图算法库Boost Graph Library（BGL）来实现各种图算法，包括最短路径、最小生成树、图的遍历等。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;boost/graph/adjacency_list.hpp&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;boost/graph/dijkstra_shortest_paths.hpp&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;boost/graph/kruskal_min_spanning_tree.hpp&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">boost</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">typedef</span> <span class="n">adjacency_list</span><span class="o">&lt;</span><span class="n">vecS</span><span class="p">,</span> <span class="n">vecS</span><span class="p">,</span> <span class="n">undirectedS</span><span class="p">,</span> <span class="n">no_property</span><span class="p">,</span> <span class="n">property</span><span class="o">&lt;</span><span class="n">edge_weight_t</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">Graph</span><span class="p">;</span>
    <span class="n">Graph</span> <span class="n">g</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
    <span class="n">add_edge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">g</span><span class="p">);</span>
    <span class="n">add_edge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">g</span><span class="p">);</span>
    <span class="n">add_edge</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">g</span><span class="p">);</span>
    
    <span class="c1">// 最短路径</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">distances</span><span class="p">(</span><span class="n">num_vertices</span><span class="p">(</span><span class="n">g</span><span class="p">));</span>
    <span class="n">dijkstra_shortest_paths</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">distance_map</span><span class="p">(</span><span class="o">&amp;</span><span class="n">distances</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>

    <span class="c1">// 最小生成树</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">Graph</span><span class="o">::</span><span class="n">edge_descriptor</span><span class="o">&gt;</span> <span class="n">spanning_tree</span><span class="p">;</span>
    <span class="n">kruskal_minimum_spanning_tree</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">back_in</span>
</code></pre></div></div>

<h4 id="遍历traversal">遍历（Traversal）：</h4>

<p>笔记：遍历是指访问数据结构中的所有元素的过程。常见的数据结构包括数组、链表、树和图。以下是C++中常见数据结构的遍历方法：</p>

<h5 id="数组遍历">数组遍历：</h5>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>数组遍历是通过循环逐个访问数组中的元素。</li>
</ul>

<h5 id="链表遍历">链表遍历：</h5>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Node</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">;</span>
    <span class="n">Node</span><span class="o">*</span> <span class="n">next</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">Node</span><span class="o">*</span> <span class="n">head</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Node</span><span class="p">();</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">Node</span><span class="o">*</span> <span class="n">current</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">current</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">current</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
        <span class="n">current</span> <span class="o">=</span> <span class="n">current</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>链表遍历是通过指针依次访问链表中的节点。</li>
</ul>

<h5 id="树的遍历">树的遍历：</h5>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">TreeNode</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">;</span>
    <span class="n">TreeNode</span><span class="o">*</span> <span class="n">left</span><span class="p">;</span>
    <span class="n">TreeNode</span><span class="o">*</span> <span class="n">right</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">void</span> <span class="n">inorderTraversal</span><span class="p">(</span><span class="n">TreeNode</span><span class="o">*</span> <span class="n">root</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">root</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
    <span class="n">inorderTraversal</span><span class="p">(</span><span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">root</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="n">inorderTraversal</span><span class="p">(</span><span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">TreeNode</span><span class="o">*</span> <span class="n">root</span> <span class="o">=</span> <span class="k">new</span> <span class="n">TreeNode</span><span class="p">();</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">root</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">inorderTraversal</span><span class="p">(</span><span class="n">root</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>树的中序遍历是先访问左子树，然后访问根节点，最后访问右子树。</li>
</ul>

<h5 id="图的遍历">图的遍历：</h5>

<p>笔记：对于图的遍历，通常使用深度优先搜索（DFS）或广度优先搜索（BFS）。</p>

<h4 id="排序sorting">排序（Sorting）：</h4>

<p>笔记：排序是将一组数据按照一定的规则重新排列的过程，常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">sort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">arr</span> <span class="o">+</span> <span class="n">n</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>以上是C++中使用STL的<code class="language-plaintext highlighter-rouge">sort</code>函数对数组进行排序的示例。</li>
</ul>

<h4 id="搜索searching">搜索（Searching）：</h4>

<p>笔记：搜索是在数据集合中查找特定元素的过程。常见的搜索算法包括线性搜索、二分搜索等。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">linearSearch</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">i</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="kt">int</span> <span class="n">target</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">linearSearch</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">target</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">index</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element found at index: "</span> <span class="o">&lt;&lt;</span> <span class="n">index</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element not found"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>以上是C++中线性搜索的示例。</li>
</ul>

<h3 id="排序sorting-1">排序（Sorting）：</h3>

<p>笔记：排序是将一组数据按照一定的规则重新排列的过程，常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。</p>

<h4 id="冒泡排序bubble-sort">冒泡排序（Bubble Sort）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">bubbleSort</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">swap</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">arr</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">bubbleSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>冒泡排序是一种基本的排序算法，它重复地走访过要排序的元素列，依次比较相邻的两个元素，如果顺序不对则交换。</li>
</ul>

<h3 id="搜索searching-1">搜索（Searching）：</h3>

<p>笔记：搜索是在数据集合中查找特定元素的过程。常见的搜索算法包括线性搜索、二分搜索等。</p>

<h4 id="二分搜索binary-search">二分搜索（Binary Search）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">binarySearch</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">left</span><span class="p">,</span> <span class="kt">int</span> <span class="n">right</span><span class="p">,</span> <span class="kt">int</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;=</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="n">left</span> <span class="o">+</span> <span class="p">(</span><span class="n">right</span> <span class="o">-</span> <span class="n">left</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">mid</span><span class="p">]</span> <span class="o">==</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">mid</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">mid</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">left</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">right</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="kt">int</span> <span class="n">target</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">binarySearch</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">target</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">index</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element found at index: "</span> <span class="o">&lt;&lt;</span> <span class="n">index</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element not found"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>二分搜索是一种在有序数组中查找特定元素的搜索算法，它通过将目标值与数组中间元素比较来决定下一步搜索的方向。</li>
</ul>

<h3 id="排序sorting-2">排序（Sorting）：</h3>

<h4 id="选择排序selection-sort">选择排序（Selection Sort）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">selectionSort</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">minIndex</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">minIndex</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">minIndex</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="n">swap</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">arr</span><span class="p">[</span><span class="n">minIndex</span><span class="p">]);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">selectionSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>选择排序是一种简单直观的排序算法，它的基本思想是每一次从待排序的数据元素中选出最小（或最大）的一个元素，存放在序列的起始位置。</li>
</ul>

<h4 id="插入排序insertion-sort">插入排序（Insertion Sort）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">insertionSort</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">key</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">key</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">arr</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
            <span class="n">j</span> <span class="o">=</span> <span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">arr</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">key</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">insertionSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>插入排序是一种简单直观的排序算法，它的基本思想是每次将一个待排序的元素，按其关键字的大小插入到已经排好序的一组元素的适当位置上。</li>
</ul>

<h3 id="搜索searching-2">搜索（Searching）：</h3>

<h4 id="线性搜索linear-search">线性搜索（Linear Search）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">linearSearch</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">i</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="kt">int</span> <span class="n">target</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">linearSearch</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">target</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">index</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element found at index: "</span> <span class="o">&lt;&lt;</span> <span class="n">index</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element not found"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>线性搜索是一种基础的搜索算法，它逐个地检查数据结构中的每个元素，直到找到目标元素或搜索到数据结构的末尾。</li>
</ul>

<h3 id="排序sorting-3">排序（Sorting）：</h3>

<h4 id="快速排序quick-sort">快速排序（Quick Sort）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">swap</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span><span class="o">*</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="o">*</span><span class="n">a</span><span class="p">;</span>
    <span class="o">*</span><span class="n">a</span> <span class="o">=</span> <span class="o">*</span><span class="n">b</span><span class="p">;</span>
    <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">temp</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">partition</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">low</span><span class="p">,</span> <span class="kt">int</span> <span class="n">high</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">pivot</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">high</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">low</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">low</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">high</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">pivot</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">i</span><span class="o">++</span><span class="p">;</span>
            <span class="n">swap</span><span class="p">(</span><span class="o">&amp;</span><span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">]);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">swap</span><span class="p">(</span><span class="o">&amp;</span><span class="n">arr</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">arr</span><span class="p">[</span><span class="n">high</span><span class="p">]);</span>
    <span class="k">return</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">quickSort</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">low</span><span class="p">,</span> <span class="kt">int</span> <span class="n">high</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">low</span> <span class="o">&lt;</span> <span class="n">high</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">pi</span> <span class="o">=</span> <span class="n">partition</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">low</span><span class="p">,</span> <span class="n">high</span><span class="p">);</span>
        <span class="n">quickSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">low</span><span class="p">,</span> <span class="n">pi</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
        <span class="n">quickSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">pi</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">high</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">quickSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>快速排序是一种高效的排序算法，它采用了分治的思想，通过选择一个基准元素，将数据分割成两个子数组，小于基准的元素放在左边，大于基准的元素放在右边，然后对子数组进行递归排序。</li>
</ul>

<h4 id="归并排序merge-sort">归并排序（Merge Sort）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">merge</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">m</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n1</span> <span class="o">=</span> <span class="n">m</span> <span class="o">-</span> <span class="n">l</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">n2</span> <span class="o">=</span> <span class="n">r</span> <span class="o">-</span> <span class="n">m</span><span class="p">;</span>

    <span class="kt">int</span> <span class="n">L</span><span class="p">[</span><span class="n">n1</span><span class="p">],</span> <span class="n">R</span><span class="p">[</span><span class="n">n2</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">l</span> <span class="o">+</span> <span class="n">i</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n2</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span>
        <span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">m</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">j</span><span class="p">];</span>

    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="n">l</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">n1</span> <span class="o">&amp;&amp;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n2</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">arr</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
            <span class="n">i</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">arr</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
            <span class="n">j</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">k</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">n1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">arr</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="n">i</span><span class="o">++</span><span class="p">;</span>
        <span class="n">k</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">n2</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">arr</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
        <span class="n">j</span><span class="o">++</span><span class="p">;</span>
        <span class="n">k</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">mergeSort</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&gt;=</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="n">l</span> <span class="o">+</span> <span class="p">(</span><span class="n">r</span> <span class="o">-</span> <span class="n">l</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">mergeSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">);</span>
    <span class="n">mergeSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
    <span class="n">merge</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">mergeSort</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>归并排序是一种稳定的排序算法，它将数据分成两个子序列，分别进行递归排序，然后合并两个有序子序列。</li>
</ul>

<h3 id="搜索searching-3">搜索（Searching）：</h3>

<h4 id="二分搜索binary-search-1">二分搜索（Binary Search）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">binarySearch</span><span class="p">(</span><span class="kt">int</span> <span class="n">arr</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">left</span><span class="p">,</span> <span class="kt">int</span> <span class="n">right</span><span class="p">,</span> <span class="kt">int</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;=</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="n">left</span> <span class="o">+</span> <span class="p">(</span><span class="n">right</span> <span class="o">-</span> <span class="n">left</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">mid</span><span class="p">]</span> <span class="o">==</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">mid</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">mid</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">left</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">right</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="kt">int</span> <span class="n">target</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">binarySearch</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">target</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">index</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element found at index: "</span> <span class="o">&lt;&lt;</span> <span class="n">index</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element not found"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>二分搜索是一种高效的搜索算法，但它要求数据必须是有序的。它通过反复将查找范围划分为两半并比较中间元素来减少需要检查的元素数量。</li>
</ul>

<h4 id="深度优先搜索depth-first-searchdfs">深度优先搜索（Depth First Search，DFS）：</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stack&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">dfs</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;&amp;</span> <span class="n">graph</span><span class="p">,</span> <span class="kt">int</span> <span class="n">start</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">graph</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span> <span class="n">visited</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>
    <span class="n">stack</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">s</span><span class="p">;</span>
    <span class="n">s</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">start</span><span class="p">);</span>
    <span class="n">visited</span><span class="p">[</span><span class="n">start</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"DFS Traversal: "</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">s</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">node</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">top</span><span class="p">();</span>
        <span class="n">s</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">node</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">neighbor</span> <span class="o">:</span> <span class="n">graph</span><span class="p">[</span><span class="n">node</span><span class="p">])</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">visited</span><span class="p">[</span><span class="n">neighbor</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">s</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">neighbor</span><span class="p">);</span>
                <span class="n">visited</span><span class="p">[</span><span class="n">neighbor</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">graph</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">}</span> <span class="p">};</span>
    <span class="kt">int</span> <span class="n">start</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">dfs</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">start</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>深度优先搜索是一种图遍历算法，它沿着图的深度遍历图的节点，尽可能深地搜索图的分支。DFS 使用栈来实现，它从起始节点开始，沿着一条路径一直到达最深的节点，然后回溯，继续搜索下一条分支。</li>
</ul>

<p>笔记：以上是一些常见的排序和搜索算法的C++实现，它们在实际的编程中具有广泛的应用场景。</p>

<h2 id="bfs">BFS</h2>

<p>笔记：以下是广度优先搜索（Breadth First Search，BFS）的C++实现示例：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">bfs</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;&amp;</span> <span class="n">graph</span><span class="p">,</span> <span class="kt">int</span> <span class="n">start</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">graph</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span> <span class="n">visited</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>
    <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">start</span><span class="p">);</span>
    <span class="n">visited</span><span class="p">[</span><span class="n">start</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"BFS Traversal: "</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">node</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">node</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">neighbor</span> <span class="o">:</span> <span class="n">graph</span><span class="p">[</span><span class="n">node</span><span class="p">])</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">visited</span><span class="p">[</span><span class="n">neighbor</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">neighbor</span><span class="p">);</span>
                <span class="n">visited</span><span class="p">[</span><span class="n">neighbor</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">graph</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">}</span> <span class="p">};</span>
    <span class="kt">int</span> <span class="n">start</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">bfs</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">start</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>广度优先搜索是一种图遍历算法，它从图的某个顶点开始，先访问其所有的相邻节点，然后再依次访问相邻节点的相邻节点，以此类推。BFS使用队列来实现，从起始节点开始，将其加入队列，然后按层级依次访问节点，直到队列为空为止。</li>
</ul>

<p>笔记：快速幂（Fast Exponentiation）是一种用于计算幂运算的算法，它可以在较短的时间内计算出大整数的幂，时间复杂度为 O(logN)。快速幂算法的基本思想是利用指数的二进制表示来减少乘法的次数。</p>

<p>笔记：以下是快速幂的C++实现示例：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">long</span> <span class="kt">long</span> <span class="nf">fastPower</span><span class="p">(</span><span class="kt">long</span> <span class="kt">long</span> <span class="n">base</span><span class="p">,</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">exponent</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">exponent</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">exponent</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">result</span> <span class="o">*=</span> <span class="n">base</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">base</span> <span class="o">*=</span> <span class="n">base</span><span class="p">;</span>
        <span class="n">exponent</span> <span class="o">/=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">base</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">exponent</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">result</span> <span class="o">=</span> <span class="n">fastPower</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">exponent</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">base</span> <span class="o">&lt;&lt;</span> <span class="s">" raised to the power of "</span> <span class="o">&lt;&lt;</span> <span class="n">exponent</span> <span class="o">&lt;&lt;</span> <span class="s">" is: "</span> <span class="o">&lt;&lt;</span> <span class="n">result</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，<code class="language-plaintext highlighter-rouge">fastPower</code>函数接受两个参数：底数（base）和指数（exponent），并返回底数的指数次幂。在函数内部，我们使用了一个 while 循环来迭代计算结果。在每次迭代中，我们检查指数的最低位（exponent % 2）是否为1，如果是，则将当前的底数乘到结果中。然后，将底数自乘以进行下一次迭代，并将指数除以2以向右移动到下一个二进制位。</p>

<p>笔记：通过这种方式，我们可以在 O(logN) 的时间复杂度内计算出给定底数和指数的幂运算结果。</p>

<p>笔记：矩阵快速幂是快速幂算法的一种扩展，用于高效地计算矩阵的幂。它在计算矩阵的幂时，利用了矩阵乘法的性质，并通过将指数表示为二进制来减少乘法的次数，从而降低了时间复杂度。</p>

<p>笔记：以下是矩阵快速幂的C++实现示例：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">typedef</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">Matrix</span><span class="p">;</span>

<span class="n">Matrix</span> <span class="nf">multiply</span><span class="p">(</span><span class="n">Matrix</span> <span class="o">&amp;</span><span class="n">A</span><span class="p">,</span> <span class="n">Matrix</span> <span class="o">&amp;</span><span class="n">B</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">A</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="n">B</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">size</span><span class="p">();</span>
    <span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="n">B</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">Matrix</span> <span class="n">C</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="c1">//</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span><span class="c1">//</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">p</span><span class="p">;</span> <span class="o">++</span><span class="n">k</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+=</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">*</span> <span class="n">B</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">j</span><span class="p">];</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">C</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">Matrix</span> <span class="n">matrixPower</span><span class="p">(</span><span class="n">Matrix</span> <span class="o">&amp;</span><span class="n">A</span><span class="p">,</span> <span class="kt">int</span> <span class="n">exponent</span><span class="p">)</span> <span class="p">{</span> <span class="c1">//A</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">A</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">Matrix</span> <span class="n">result</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span><span class="c1">//</span>
        <span class="n">result</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 单位矩阵</span>
    <span class="p">}</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">exponent</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="c1">//</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">exponent</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="c1">//</span>
            <span class="n">result</span> <span class="o">=</span> <span class="n">multiply</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">A</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">A</span> <span class="o">=</span> <span class="n">multiply</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">A</span><span class="p">);</span> <span class="c1">// 矩阵平方</span>
        <span class="n">exponent</span> <span class="o">/=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span><span class="c1">//</span>
    <span class="n">Matrix</span> <span class="n">A</span> <span class="o">=</span> <span class="p">{</span><span class="cm">/**/</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">}</span><span class="cm">/**/</span><span class="p">};</span> <span class="c1">// 斐波那契矩阵</span>
    <span class="kt">int</span> <span class="n">exponent</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span> <span class="c1">// 指数</span>
    <span class="n">Matrix</span> <span class="n">result</span> <span class="o">=</span> <span class="n">matrixPower</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">exponent</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Resulting matrix after raising to the power of "</span> <span class="o">&lt;&lt;</span> <span class="n">exponent</span> <span class="o">&lt;&lt;</span> <span class="s">":"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">result</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">result</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">result</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们定义了两个函数，<code class="language-plaintext highlighter-rouge">multiply</code>函数用于计算两个矩阵的乘积，<code class="language-plaintext highlighter-rouge">matrixPower</code>函数用于计算矩阵的指数次幂。在 <code class="language-plaintext highlighter-rouge">matrixPower</code> 函数中，我们首先初始化一个单位矩阵作为结果矩阵，然后利用循环和矩阵乘法进行幂运算的计算。通过这种方式，我们可以高效地计算矩阵的幂运算结果。</p>

<p>笔记：动态规划（Dynamic Programming，DP）是一种通过将复杂问题分解成更小的子问题来解决的优化技术。它通常用于优化递归算法，避免重复计算子问题。</p>

<p>笔记：以下是动态规划的一般步骤：</p>

<ol>
  <li><strong>定义子问题</strong>：将原始问题分解为更小的子问题。</li>
  <li><strong>找出状态转移方程</strong>：确定子问题之间的关系，即如何将更大的问题的解构建为更小问题的解。</li>
  <li><strong>确定初始条件</strong>：确定最小子问题的解，通常是基本情况的解。</li>
  <li><strong>自底向上求解</strong>：根据状态转移方程，从最小的子问题开始，依次解决更大的问题，直到达到原始问题的解。</li>
</ol>

<p>笔记：动态规划常用于解决一些优化问题，如最长公共子序列、背包问题、最短路径问题等。</p>

<p>笔记：下面是一个动态规划的示例，解决了斐波那契数列问题：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">fibonacci</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">n</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">dp</span><span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">dp</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">];</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Fibonacci number at position "</span> <span class="o">&lt;&lt;</span> <span class="n">n</span> <span class="o">&lt;&lt;</span> <span class="s">" is: "</span> <span class="o">&lt;&lt;</span> <span class="n">fibonacci</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们利用动态规划的思想解决了斐波那契数列问题。我们定义了一个长度为 n+1 的动态规划数组 dp，其中 dp[i] 表示斐波那契数列中第 i 个数的值。然后我们使用迭代的方式，根据状态转移方程 dp[i] = dp[i-1] + dp[i-2] 依次求解 dp 数组的值，最终返回 dp[n] 即可得到斐波那契数列第 n 个数的值。</p>

<p>笔记：贪心算法（Greedy Algorithm）是一种在每一步选择中都采取在当前状态下最好或最优（即局部最优解）的选择，从而希望能够导致全局最优解的算法策略。贪心算法通常不会回溯，因为它一旦做出选择就不会改变。</p>

<p>笔记：贪心算法适用于满足以下两个条件的问题：</p>

<ol>
  <li>最优子结构：问题的最优解包含了子问题的最优解。</li>
  <li>贪心选择性质：通过局部最优选择，能够得到全局最优解。</li>
</ol>

<p>笔记：贪心算法的优点在于简单、高效，容易实现。然而，它并不是所有问题都适用，因为它可能会产生局部最优解但不一定能得到全局最优解。</p>

<p>笔记：以下是一个简单的贪心算法示例，解决了活动选择问题（Activity Selection Problem）：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Activity</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">start</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">finish</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">bool</span> <span class="n">compare</span><span class="p">(</span><span class="n">Activity</span> <span class="n">a</span><span class="p">,</span> <span class="n">Activity</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">finish</span> <span class="o">&lt;</span> <span class="n">b</span><span class="p">.</span><span class="n">finish</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">selectActivities</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Activity</span><span class="o">&gt;&amp;</span> <span class="n">activities</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">sort</span><span class="p">(</span><span class="n">activities</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">activities</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">compare</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Selected activities: "</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">activities</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"("</span> <span class="o">&lt;&lt;</span> <span class="n">activities</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">start</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span> <span class="o">&lt;&lt;</span> <span class="n">activities</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">finish</span> <span class="o">&lt;&lt;</span> <span class="s">") "</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">prev_finish</span> <span class="o">=</span> <span class="n">activities</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">finish</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">activities</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">start</span> <span class="o">&gt;=</span> <span class="n">prev_finish</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"("</span> <span class="o">&lt;&lt;</span> <span class="n">activities</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">start</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span> <span class="o">&lt;&lt;</span> <span class="n">activities</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">finish</span> <span class="o">&lt;&lt;</span> <span class="s">") "</span><span class="p">;</span>
            <span class="n">prev_finish</span> <span class="o">=</span> <span class="n">activities</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">finish</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">Activity</span><span class="o">&gt;</span> <span class="n">activities</span> <span class="o">=</span> <span class="p">{</span><span class="cm">/**/</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">6</span><span class="p">},</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">9</span><span class="p">},</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">},</span> <span class="p">{</span><span class="mi">6</span><span class="p">,</span> <span class="mi">10</span><span class="p">},</span> <span class="p">{</span><span class="mi">8</span><span class="p">,</span> <span class="mi">11</span><span class="p">},</span> <span class="p">{</span><span class="mi">8</span><span class="p">,</span> <span class="mi">12</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">14</span><span class="p">},</span> <span class="p">{</span><span class="mi">12</span><span class="p">,</span> <span class="mi">16</span><span class="p">}};</span>
    <span class="n">selectActivities</span><span class="p">(</span><span class="n">activities</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们定义了一个活动结构体，包含了每个活动的开始时间和结束时间。然后我们按照活动的结束时间对活动进行排序，然后从排好序的活动中选择最早结束的活动，并确保选中的活动与已选中的活动不重叠。这样，我们就可以通过贪心算法求解出最大的可选活动数量。</p>

<p>笔记：以下是贪心算法的另一个示例，解决了找零钱问题（Coin Change Problem）：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">makeChange</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">coins</span><span class="p">,</span> <span class="kt">int</span> <span class="n">amount</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">result</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">coins</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="o">--</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">amount</span> <span class="o">&gt;=</span> <span class="n">coins</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">amount</span> <span class="o">-=</span> <span class="n">coins</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
            <span class="n">result</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">coins</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">coins</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">25</span><span class="p">};</span> <span class="c1">// 美分硬币面额</span>
    <span class="kt">int</span> <span class="n">amount</span> <span class="o">=</span> <span class="mi">99</span><span class="p">;</span> <span class="c1">// 找零的金额</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">change</span> <span class="o">=</span> <span class="n">makeChange</span><span class="p">(</span><span class="n">coins</span><span class="p">,</span> <span class="n">amount</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Change for "</span> <span class="o">&lt;&lt;</span> <span class="n">amount</span> <span class="o">&lt;&lt;</span> <span class="s">" cents: "</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">coin</span> <span class="o">:</span> <span class="n">change</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">coin</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们有一组美分硬币的面额，以及一个需要找零的金额。我们按照硬币面额从大到小的顺序进行贪心选择，每次尽量选择面额最大的硬币。通过循环遍历硬币面额，我们不断地将最大面额的硬币加入找零列表中，直到达到需要找零的金额。最终返回的找零列表即为贪心算法所得到的结果。</p>

<p>笔记：需要注意的是，贪心算法并不一定能够得到最优解，它只能得到局部最优解。在找零钱的问题中，如果硬币面额不是常见的面额组合（如1、5、10、25美分），贪心算法可能无法得到最小数量的硬币找零方案。</p>

<p>笔记：二分答案是一种常用的优化技巧，通常用于解决满足某个条件的最优解问题。它的基本思想是，在一个有序的解空间中，利用二分查找的思想来快速地确定满足条件的解的范围。</p>

<p>笔记：下面是一个简单的示例，演示了如何使用二分答案来解决一个简单的问题：</p>

<p>笔记：假设有一个升序排列的数组 <code class="language-plaintext highlighter-rouge">nums</code>，我们要找到数组中第一个大于等于目标值 <code class="language-plaintext highlighter-rouge">target</code> 的元素的下标。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">binarySearch</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">,</span> <span class="kt">int</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">right</span> <span class="o">=</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;=</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="n">left</span> <span class="o">+</span> <span class="p">(</span><span class="n">right</span> <span class="o">-</span> <span class="n">left</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">mid</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">right</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">left</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">left</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">?</span> <span class="n">left</span> <span class="o">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// 返回找到的元素的下标，如果找不到则返回 -1</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">nums</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">9</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">target</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">binarySearch</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">target</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">index</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"The index of the first element greater than or equal to "</span> <span class="o">&lt;&lt;</span> <span class="n">target</span> <span class="o">&lt;&lt;</span> <span class="s">" is: "</span> <span class="o">&lt;&lt;</span> <span class="n">index</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"No such element found."</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们使用了二分答案的思想。我们首先设定一个有序的解空间，在这个示例中，解空间即为数组 <code class="language-plaintext highlighter-rouge">nums</code> 的索引范围。然后我们通过不断地调整左右边界来缩小解空间，最终找到满足条件的最优解。</p>

<p>笔记：二分答案是一种非常高效的优化技巧，在解决一些需要在有序解空间中查找满足条件的最优解的问题时非常有用。</p>

<p>笔记：二分答案的思想还可以应用于更复杂的问题，例如求解满足某种条件的最优解，或者在一个有序的范围内查找满足某种条件的解的位置。</p>

<p>笔记：下面是一个更复杂的示例，演示了如何使用二分答案来解决一个数值范围内的问题：</p>

<p>笔记：假设有一个函数 <code class="language-plaintext highlighter-rouge">bool isValid(int x)</code>，可以用来判断一个整数 <code class="language-plaintext highlighter-rouge">x</code> 是否满足某种条件。现在要在一个给定的区间 <code class="language-plaintext highlighter-rouge">[left, right]</code> 中找到满足条件的最小整数。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">bool</span> <span class="nf">isValid</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// 假设这里是一个条件判断函数，用于判断整数 x 是否满足某种条件</span>
    <span class="k">return</span> <span class="n">x</span> <span class="o">&gt;=</span> <span class="mi">10</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">binarySearch</span><span class="p">(</span><span class="kt">int</span> <span class="n">left</span><span class="p">,</span> <span class="kt">int</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="n">left</span> <span class="o">+</span> <span class="p">(</span><span class="n">right</span> <span class="o">-</span> <span class="n">left</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">isValid</span><span class="p">(</span><span class="n">mid</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">right</span> <span class="o">=</span> <span class="n">mid</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">left</span> <span class="o">=</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">left</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">right</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="n">binarySearch</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"The smallest integer that satisfies the condition is: "</span> <span class="o">&lt;&lt;</span> <span class="n">result</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们通过二分答案的思想，在给定的区间 <code class="language-plaintext highlighter-rouge">[left, right]</code> 中查找满足条件的最小整数。我们首先设定了一个有序的解空间，然后不断地调整左右边界来缩小解空间，直到找到满足条件的最小整数。</p>

<p>笔记：二分答案的思想可以应用于各种各样的问题，它是一种非常高效且常用的算法优化技巧。</p>

<p>笔记：前缀和（Prefix Sum）是一种常用的技巧，用于高效地计算数组或序列的区间和。它的基本思想是预处理数组，将数组中每个位置的前缀和存储起来，然后利用前缀和的性质来快速计算任意区间的和。</p>

<p>笔记：以下是一个简单的示例，演示了如何使用前缀和来计算数组的区间和：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">calculatePrefixSum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">prefixSum</span><span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// 初始化前缀和数组，多出的一个位置用于处理边界情况</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">prefixSum</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="c1">// 计算前缀和</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">prefixSum</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">rangeSum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">prefixSum</span><span class="p">,</span> <span class="kt">int</span> <span class="n">left</span><span class="p">,</span> <span class="kt">int</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">right</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">left</span><span class="p">];</span> <span class="c1">// 利用前缀和计算区间和</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">nums</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">prefixSum</span> <span class="o">=</span> <span class="n">calculatePrefixSum</span><span class="p">(</span><span class="n">nums</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// 求区间 [1, 3] 的和</span>
    <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">rangeSum</span><span class="p">(</span><span class="n">prefixSum</span><span class="p">,</span> <span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"The sum of elements in the range ["</span> <span class="o">&lt;&lt;</span> <span class="n">left</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span> <span class="o">&lt;&lt;</span> <span class="n">right</span> <span class="o">&lt;&lt;</span> <span class="s">"] is: "</span> <span class="o">&lt;&lt;</span> <span class="n">sum</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们首先计算了数组 <code class="language-plaintext highlighter-rouge">nums</code> 的前缀和，然后通过前缀和数组可以快速地计算任意区间的和。利用前缀和的性质，区间 <code class="language-plaintext highlighter-rouge">[left, right]</code> 的和等于前缀和数组中右边界 <code class="language-plaintext highlighter-rouge">right+1</code> 对应的值减去左边界 <code class="language-plaintext highlighter-rouge">left</code> 对应的值。</p>

<p>笔记：前缀和的优势在于在预处理阶段计算了所有可能的区间和，使得在查询阶段可以快速地得到结果，时间复杂度为 O(1)。这使得前缀和成为了解决涉及区间和的问题时一个非常高效的技巧。</p>

<p>笔记：除了用于计算数组的区间和，前缀和还可以应用于解决其他类型的问题，比如查找数组中的连续子数组，使得子数组的和满足特定条件。</p>

<p>笔记：以下是一个示例，演示了如何使用前缀和来解决一个查找数组中满足特定条件的连续子数组的问题：</p>

<p>笔记：假设给定一个整数数组 <code class="language-plaintext highlighter-rouge">nums</code>，我们要找到一个连续的子数组，使得子数组的和等于目标值 <code class="language-plaintext highlighter-rouge">target</code>。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unordered_map&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">subarraySum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">,</span> <span class="kt">int</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">prefixSumCount</span><span class="p">;</span> <span class="c1">// 前缀和及其出现次数的哈希表</span>
    <span class="n">prefixSumCount</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 初始化前缀和为0的出现次数为1</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">num</span> <span class="o">:</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">sum</span> <span class="o">+=</span> <span class="n">num</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">prefixSumCount</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">sum</span> <span class="o">-</span> <span class="n">target</span><span class="p">)</span> <span class="o">!=</span> <span class="n">prefixSumCount</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">count</span> <span class="o">+=</span> <span class="n">prefixSumCount</span><span class="p">[</span><span class="n">sum</span> <span class="o">-</span> <span class="n">target</span><span class="p">];</span> <span class="c1">// 如果存在前缀和为 sum - target 的子数组，则增加计数</span>
        <span class="p">}</span>
        <span class="n">prefixSumCount</span><span class="p">[</span><span class="n">sum</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 更新前缀和出现次数</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">count</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">nums</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">target</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="n">subarraySum</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">target</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Number of subarrays with sum equal to "</span> <span class="o">&lt;&lt;</span> <span class="n">target</span> <span class="o">&lt;&lt;</span> <span class="s">" is: "</span> <span class="o">&lt;&lt;</span> <span class="n">count</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们使用了一个哈希表 <code class="language-plaintext highlighter-rouge">prefixSumCount</code> 来存储前缀和及其出现次数。我们从左到右遍历数组 <code class="language-plaintext highlighter-rouge">nums</code>，在遍历的过程中，计算当前位置的前缀和，并检查是否存在前缀和为 <code class="language-plaintext highlighter-rouge">sum - target</code> 的子数组。如果存在，则增加计数器。</p>

<p>笔记：利用前缀和的思想，我们可以在线性时间内解决这个问题，而不需要通过枚举所有可能的子数组来寻找满足条件的解。这种方法在解决数组和子数组相关的问题时非常高效。</p>

<p>笔记：容斥原理（Inclusion-Exclusion Principle）是组合数学中的一种重要原理，用于计算多个集合的并集、交集和补集等操作的元素个数。它是一种通过排除重复计数来计算所需结果的方法。</p>

<p>笔记：容斥原理的基本形式是：如果有若干个集合，要求它们的并集中的元素个数，可以通过依次加上每个集合的元素个数，然后减去每两个集合的交集的元素个数，再加上每三个集合的交集的元素个数，依次类推，直到最后加上或减去所有集合的交集的元素个数。</p>

<p>笔记：以下是一个简单的示例，演示了如何使用容斥原理计算多个集合的并集中的元素个数：</p>

<p>笔记：假设有三个集合 A、B、C，我们要求它们的并集中的元素个数。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;set&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">inclusionExclusion</span><span class="p">(</span><span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">A</span><span class="p">,</span> <span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">B</span><span class="p">,</span> <span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">C</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">totalElements</span> <span class="o">=</span> <span class="n">A</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">+</span> <span class="n">B</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">+</span> <span class="n">C</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="kt">int</span> <span class="n">intersectionAB</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">intersectionAC</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">intersectionBC</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">intersectionABC</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">:</span> <span class="n">A</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">B</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">intersectionAB</span><span class="o">++</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">C</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">intersectionAC</span><span class="o">++</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">B</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">C</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">intersectionABC</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">:</span> <span class="n">B</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">C</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">intersectionBC</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="n">totalElements</span> <span class="o">-</span> <span class="n">intersectionAB</span> <span class="o">-</span> <span class="n">intersectionAC</span> <span class="o">-</span> <span class="n">intersectionBC</span> <span class="o">+</span> <span class="n">intersectionABC</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">A</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span>
    <span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">B</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
    <span class="n">set</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">C</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="n">inclusionExclusion</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Number of elements in the union of sets A, B, C is: "</span> <span class="o">&lt;&lt;</span> <span class="n">count</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们首先计算了三个集合的元素个数，并分别计算了它们之间的交集元素个数。然后根据容斥原理的公式，依次减去交集的元素个数，再加上交集的交集的元素个数，得到最终的结果。</p>

<p>笔记：二维前缀和是一种用于高效计算二维数组区域和的技巧。它类似于一维前缀和，通过预处理的方式，将原始二维数组转换为一个对应的二维前缀和数组，以便快速计算任意二维区域的和。</p>

<p>笔记：以下是一个简单的示例，演示了如何使用二维前缀和来计算二维数组区域和：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">calculatePrefixSum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;&amp;</span> <span class="n">matrix</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">size</span><span class="p">();</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">prefixSum</span><span class="p">(</span><span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">prefixSum</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">matrix</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">prefixSum</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">rangeSum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;&amp;</span> <span class="n">prefixSum</span><span class="p">,</span> <span class="kt">int</span> <span class="n">row1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">col1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">row2</span><span class="p">,</span> <span class="kt">int</span> <span class="n">col2</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">row2</span> <span class="o">+</span> <span class="mi">1</span><span class="p">][</span><span class="n">col2</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">row1</span><span class="p">][</span><span class="n">col2</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">row2</span> <span class="o">+</span> <span class="mi">1</span><span class="p">][</span><span class="n">col1</span><span class="p">]</span> <span class="o">+</span> <span class="n">prefixSum</span><span class="p">[</span><span class="n">row1</span><span class="p">][</span><span class="n">col1</span><span class="p">];</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">matrix</span> <span class="o">=</span> <span class="p">{</span><span class="cm">/**/</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">},</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">},</span> <span class="p">{</span><span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">}};</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">prefixSum</span> <span class="o">=</span> <span class="n">calculatePrefixSum</span><span class="p">(</span><span class="n">matrix</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">row1</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">col1</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">row2</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">col2</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">// 计算二维区域和的左上角和右下角坐标</span>
    <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">rangeSum</span><span class="p">(</span><span class="n">prefixSum</span><span class="p">,</span> <span class="n">row1</span><span class="p">,</span> <span class="n">col1</span><span class="p">,</span> <span class="n">row2</span><span class="p">,</span> <span class="n">col2</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Sum of elements in the range ["</span> <span class="o">&lt;&lt;</span> <span class="n">row1</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span> <span class="o">&lt;&lt;</span> <span class="n">col1</span> <span class="o">&lt;&lt;</span> <span class="s">"] to ["</span> <span class="o">&lt;&lt;</span> <span class="n">row2</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span> <span class="o">&lt;&lt;</span> <span class="n">col2</span> <span class="o">&lt;&lt;</span> <span class="s">"] is: "</span> <span class="o">&lt;&lt;</span> <span class="n">sum</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们首先计算了二维数组的前缀和数组。然后，通过利用前缀和数组的性质，可以在常量时间内计算任意二维区域的和，这种方法的时间复杂度为 O(1)。</p>

<p>笔记：高精度（High Precision）计算是指对于超出常规数据类型表示范围的数字进行精确计算。在计算机科学中，常见的数据类型（如int、float、double）有其表示范围和精度限制，无法精确表示超出其范围的大整数或小数。</p>

<p>笔记：在处理需要高精度计算的问题时，一种常见的方法是使用字符串来表示数字，然后模拟手工计算的方式进行运算。这种方法可以有效地处理大整数或精确小数，但通常会牺牲计算速度。</p>

<p>笔记：以下是一个简单的示例，演示了如何使用字符串来实现高精度加法：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="n">string</span> <span class="nf">addStrings</span><span class="p">(</span><span class="n">string</span> <span class="n">num1</span><span class="p">,</span> <span class="n">string</span> <span class="n">num2</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">string</span> <span class="n">result</span> <span class="o">=</span> <span class="s">""</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">carry</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">num1</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">num2</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">carry</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">digit1</span> <span class="o">=</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">num1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="sc">'0'</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span>
        <span class="kt">int</span> <span class="n">digit2</span> <span class="o">=</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">num2</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">-</span> <span class="sc">'0'</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span>
        <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">digit1</span> <span class="o">+</span> <span class="n">digit2</span> <span class="o">+</span> <span class="n">carry</span><span class="p">;</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">to_string</span><span class="p">(</span><span class="n">sum</span> <span class="o">%</span> <span class="mi">10</span><span class="p">)</span> <span class="o">+</span> <span class="n">result</span><span class="p">;</span>
        <span class="n">carry</span> <span class="o">=</span> <span class="n">sum</span> <span class="o">/</span> <span class="mi">10</span><span class="p">;</span>
        <span class="n">i</span><span class="o">--</span><span class="p">;</span>
        <span class="n">j</span><span class="o">--</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">string</span> <span class="n">num1</span> <span class="o">=</span> <span class="s">"123456789"</span><span class="p">;</span>
    <span class="n">string</span> <span class="n">num2</span> <span class="o">=</span> <span class="s">"987654321"</span><span class="p">;</span>
    <span class="n">string</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">addStrings</span><span class="p">(</span><span class="n">num1</span><span class="p">,</span> <span class="n">num2</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Sum of "</span> <span class="o">&lt;&lt;</span> <span class="n">num1</span> <span class="o">&lt;&lt;</span> <span class="s">" and "</span> <span class="o">&lt;&lt;</span> <span class="n">num2</span> <span class="o">&lt;&lt;</span> <span class="s">" is: "</span> <span class="o">&lt;&lt;</span> <span class="n">sum</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们通过模拟手工加法的方式，从字符串的最后一位（个位）开始，依次相加，同时考虑进位。最终得到两个大整数的和。</p>

<p>笔记：对于高精度计算，除了加法，还可以实现减法、乘法、除法等运算，以及其他复杂的数学运算。这种方法虽然可能比较慢，但可以保证计算的精确性，适用于需要精确计算的场景。</p>

<p>笔记：模拟是一种常用的算法技巧，通常用于模拟实际问题的解决过程。它的基本思想是通过编写代码模拟实际问题的操作步骤，逐步推进问题的解决。</p>

<p>笔记：模拟常常用于解决一些具体的问题，比如游戏、仿真、物理系统等。在算法竞赛中，模拟也是常见的题型之一，题目可能涉及到模拟人物移动、模拟交通流量、模拟系统状态变化等。</p>

<p>笔记：以下是一个简单的示例，演示了如何使用模拟技巧解决一个问题：</p>

<p>笔记：假设有一个游戏中的小人，初始位置在原点 (0, 0)，根据输入的指令（方向和步数），移动小人的位置，并输出最终位置。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">movePerson</span><span class="p">(</span><span class="kt">int</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">y</span><span class="p">,</span> <span class="kt">char</span> <span class="n">direction</span><span class="p">,</span> <span class="kt">int</span> <span class="n">steps</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">direction</span> <span class="o">==</span> <span class="sc">'U'</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">y</span> <span class="o">+=</span> <span class="n">steps</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">direction</span> <span class="o">==</span> <span class="sc">'D'</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">y</span> <span class="o">-=</span> <span class="n">steps</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">direction</span> <span class="o">==</span> <span class="sc">'L'</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">x</span> <span class="o">-=</span> <span class="n">steps</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">direction</span> <span class="o">==</span> <span class="sc">'R'</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">x</span> <span class="o">+=</span> <span class="n">steps</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">string</span> <span class="n">instructions</span> <span class="o">=</span> <span class="s">"UDLR"</span><span class="p">;</span> <span class="c1">// 指令串，U表示向上移动，D表示向下移动，L表示向左移动，R表示向右移动</span>
    <span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// 初始位置</span>
    <span class="kt">int</span> <span class="n">steps</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 每次移动的步数</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">char</span> <span class="n">direction</span> <span class="o">:</span> <span class="n">instructions</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">movePerson</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">direction</span><span class="p">,</span> <span class="n">steps</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Final position of the person: ("</span> <span class="o">&lt;&lt;</span> <span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span> <span class="o">&lt;&lt;</span> <span class="n">y</span> <span class="o">&lt;&lt;</span> <span class="s">")"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们定义了一个模拟移动小人的函数 <code class="language-plaintext highlighter-rouge">movePerson()</code>，根据输入的指令来移动小人的位置。然后我们通过遍历输入的指令串，依次执行移动操作，最终得到小人的最终位置。</p>

<p>笔记：模拟是一种非常灵活的算法技巧，可以根据具体问题的特点来编写相应的模拟代码。通过模拟，我们可以更好地理解问题的本质，并且能够解决一些复杂的实际问题。</p>

<p>笔记：并查集（Disjoint Set Union，DSU），又称为不相交集合数据结构，是一种用于处理集合合并与查询的数据结构。它主要用于解决集合的合并、查询等问题，常被应用于图论、网络连接问题、最小生成树算法（如Kruskal算法）等领域。</p>

<p>笔记：并查集的基本操作包括：</p>

<ol>
  <li><strong>MakeSet(x)</strong>：创建一个新的集合，其中包含元素x。</li>
  <li><strong>Find(x)</strong>：查找元素x所在的集合（根结点）。</li>
  <li><strong>Union(x, y)</strong>：将包含元素x和元素y的两个集合合并为一个集合。</li>
</ol>

<p>笔记：以下是一个简单的并查集的实现示例：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">class</span> <span class="nc">DisjointSet</span> <span class="p">{</span>
<span class="nl">private:</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">parent</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="n">DisjointSet</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">parent</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// 初始时每个元素都是独立的集合，其父结点为自身</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">Find</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">!=</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span> <span class="c1">// 路径压缩，将x的父结点设为根结点</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">Union</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">rootX</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
        <span class="kt">int</span> <span class="n">rootY</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">rootX</span> <span class="o">!=</span> <span class="n">rootY</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">rootY</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootX</span><span class="p">;</span> <span class="c1">// 将y的根结点指向x的根结点，完成合并操作</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">DisjointSet</span> <span class="n">dsu</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>

    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>

    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(1): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(3): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(4): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们首先创建了一个大小为n的并查集，然后通过Union操作将不同的元素合并到同一个集合中，并通过Find操作查找元素所在的集合（根结点）。</p>

<p>笔记：并查集的优化还有路径压缩、按秩合并等，可以进一步提高效率，特别是在大规模应用中。</p>

<p>笔记：在并查集的基本实现之上，有几种优化策略可以进一步提高效率：</p>

<ol>
  <li>
    <p><strong>路径压缩（Path Compression）</strong>：在Find操作中，将节点的父节点设置为根节点，以减少下次查找的时间。这样，路径上的所有节点都直接连接到根节点，减少了树的高度。</p>
  </li>
  <li>
    <p><strong>按秩合并（Union by Rank）</strong>：在Union操作中，将具有较小秩的树的根节点连接到具有较大秩的树的根节点上。秩可以理解为树的高度的上界，树的高度越低，操作效率越高。</p>
  </li>
</ol>

<p>笔记：下面是一个并查集的优化实现示例，结合了路径压缩和按秩合并：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">class</span> <span class="nc">DisjointSet</span> <span class="p">{</span>
<span class="nl">private:</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">parent</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">rank</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="n">DisjointSet</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">parent</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
        <span class="n">rank</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// 初始时每个元素都是独立的集合，其父结点为自身</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">Find</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">!=</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span> <span class="c1">// 路径压缩，将x的父结点设为根结点</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">Union</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">rootX</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
        <span class="kt">int</span> <span class="n">rootY</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">rootX</span> <span class="o">!=</span> <span class="n">rootY</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootY</span><span class="p">;</span> <span class="c1">// 将x的根结点连接到y的根结点上</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootY</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootX</span><span class="p">;</span> <span class="c1">// 将y的根结点连接到x的根结点上</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootY</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootX</span><span class="p">;</span>
                <span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 如果秩相同，则任意选择一个作为根结点，并增加秩</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">DisjointSet</span> <span class="n">dsu</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>

    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>

    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(1): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(3): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(4): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：这个示例中的并查集实现结合了路径压缩和按秩合并两种优化策略，可以在保持算法正确性的同时提高效率，特别是在大规模应用中。</p>

<p>笔记：在并查集的基本实现和优化之上，还可以应用一些高级技巧来解决特定类型的问题，例如路径压缩优化的启发式合并（Path Compression with Heuristic Union）。</p>

<p>笔记：启发式合并是一种在进行Union操作时，根据某种启发式规则决定将哪个集合合并到另一个集合中的策略。这种策略可以根据具体的应用场景来选择，以最大程度地提高并查集的效率。</p>

<p>笔记：以下是一个简单的示例，演示了如何在并查集中应用路径压缩优化的启发式合并策略：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">class</span> <span class="nc">DisjointSet</span> <span class="p">{</span>
<span class="nl">private:</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">parent</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">rank</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="n">DisjointSet</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">parent</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
        <span class="n">rank</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// 初始时每个元素都是独立的集合，其父结点为自身</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">Find</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">!=</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span> <span class="c1">// 路径压缩，将x的父结点设为根结点</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">Union</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">rootX</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
        <span class="kt">int</span> <span class="n">rootY</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">rootX</span> <span class="o">!=</span> <span class="n">rootY</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootY</span><span class="p">;</span> <span class="c1">// 将x的根结点连接到y的根结点上</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootY</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootX</span><span class="p">;</span> <span class="c1">// 将y的根结点连接到x的根结点上</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">==</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 如果秩相同，则任意选择一个作为根结点，并增加秩</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">DisjointSet</span> <span class="n">dsu</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>

    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>

    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(1): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(3): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Find(4): "</span> <span class="o">&lt;&lt;</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们在进行Union操作时，根据两个集合的秩（rank）来决定哪个集合合并到另一个集合中。这种启发式策略可以有效地保持并查集的平衡性，从而提高整体效率。</p>

<p>笔记：通过合理选择并实现合适的启发式策略，可以使并查集在解决各种实际问题时更加高效。</p>

<p>笔记：在继续讨论并查集的应用之前，我们可以进一步探讨一些常见的应用场景和问题，这些问题可以通过并查集高效地解决。</p>

<p>笔记：一些常见的并查集应用包括：</p>

<ol>
  <li>
    <p><strong>连通性问题</strong>：并查集最常见的应用之一是解决连通性问题，比如判断图中的节点是否连通，或者在网络中查找是否存在通路。通过将具有相同根节点的节点视为同一个集合，可以快速判断两个节点是否连通。</p>
  </li>
  <li>
    <p><strong>最小生成树算法（Minimum Spanning Tree，MST）</strong>：Kruskal算法是一种基于并查集的最小生成树算法，它通过对边进行排序，然后依次添加边到最小生成树中，同时保证不形成环路，直到所有节点都连接在一起。</p>
  </li>
  <li>
    <p><strong>区域合并问题</strong>：在二维网格中，区域合并问题涉及将相邻的相同区域合并在一起。这可以通过并查集来实现，每个单元格对应一个节点，通过合并相邻的单元格来合并区域。</p>
  </li>
  <li>
    <p><strong>社交网络中的关系处理</strong>：在社交网络中，可以使用并查集来处理关系，比如判断两个人是否属于同一个朋友圈、组织或团体。</p>
  </li>
  <li>
    <p><strong>图的连通性问题</strong>：在图论中，可以使用并查集来判断图的连通性，或者判断是否存在环路等。</p>
  </li>
</ol>

<p>笔记：这些是并查集的一些常见应用场景，它在解决这些问题时能够提供高效的算法和数据结构支持。在实际应用中，我们可以根据具体问题的特点，灵活运用并查集算法来解决各种连通性和合并性问题。</p>

<p>笔记：带权并查集（Weighted Union-Find Disjoint Set）是对普通的并查集进行了扩展，使其支持在合并操作时维护集合的权值或秩信息。这种扩展使得在某些应用场景下能更加灵活地处理问题，特别是涉及到集合合并时需要考虑权值或秩的情况。</p>

<p>笔记：在普通的并查集中，每个集合的权值或秩信息通常是相等的，但在带权并查集中，每个节点都可以携带不同的权值或秩信息。</p>

<p>笔记：以下是带权并查集的基本实现示例：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">class</span> <span class="nc">WeightedUnionFind</span> <span class="p">{</span>
<span class="nl">private:</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">parent</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">rank</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">weight</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="n">WeightedUnionFind</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">parent</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
        <span class="n">rank</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="n">weight</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// 初始时每个元素都是独立的集合，其父结点为自身</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">Find</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">!=</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">root</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span>
            <span class="n">weight</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">+=</span> <span class="n">weight</span><span class="p">[</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]];</span> <span class="c1">// 路径压缩，累加权值信息</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">root</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">Union</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">,</span> <span class="kt">int</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">rootX</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
        <span class="kt">int</span> <span class="n">rootY</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">rootX</span> <span class="o">!=</span> <span class="n">rootY</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootY</span><span class="p">;</span>
                <span class="n">weight</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">=</span> <span class="n">w</span> <span class="o">-</span> <span class="n">weight</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">+</span> <span class="n">weight</span><span class="p">[</span><span class="n">y</span><span class="p">];</span> <span class="c1">// 更新权值信息</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootY</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootX</span><span class="p">;</span>
                <span class="n">weight</span><span class="p">[</span><span class="n">rootY</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">-</span> <span class="n">weight</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span> <span class="c1">// 更新权值信息</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">==</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 如果秩相同，则任意选择一个作为根结点，并增加秩</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">bool</span> <span class="n">Same</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">Find</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="n">Find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">Diff</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">Same</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span> <span class="p">{</span>
            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// 如果不属于同一个集合，返回-1</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">weight</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">-</span> <span class="n">weight</span><span class="p">[</span><span class="n">x</span><span class="p">];</span> <span class="c1">// 返回y的权值减去x的权值</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">WeightedUnionFind</span> <span class="n">wuf</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>

    <span class="n">wuf</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
    <span class="n">wuf</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">wuf</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>

    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Diff(0, 2): "</span> <span class="o">&lt;&lt;</span> <span class="n">wuf</span><span class="p">.</span><span class="n">Diff</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="c1">// 5 - 2 = 3</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Diff(1, 3): "</span> <span class="o">&lt;&lt;</span> <span class="n">wuf</span><span class="p">.</span><span class="n">Diff</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="c1">// 5 - 2 = 3</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在带权并查集中，除了维护每个节点的父节点和秩信息外，还需要维护每个节点的权值信息。在合并操作时，需要根据节点的权值信息来更新合并后集合的权值信息。同时，在Find操作中，需要更新路径上每个节点的权值信息，以保证正确的权值计算。通过带权并查集，我们可以更灵活地处理一些具有权值信息的合并问题。</p>

<p>笔记：带权并查集主要用于处理一些需要考虑权值信息的合并和查询问题，常见的应用场景包括：</p>

<ol>
  <li>
    <p><strong>最小生成树算法（Minimum Spanning Tree，MST）</strong>：在Kruskal算法中，需要判断加入一条边后是否会形成环路，并且在形成最小生成树时，要选择权值最小的边。带权并查集可以用于判断两个节点是否在同一个连通分量中，并且可以快速获取连通分量中的最小权值。</p>
  </li>
  <li>
    <p><strong>网络连接问题</strong>：在网络连接问题中，节点表示网络设备或者计算机，边表示网络连接。带权并查集可以用来判断两个节点是否在同一个网络中，同时可以用来查找网络中的最小权值连接。</p>
  </li>
  <li>
    <p><strong>区域合并问题</strong>：在二维网格中，带权并查集可以用来合并相邻的相同区域，并且可以根据合并后的区域的权值信息来进行判断和处理。</p>
  </li>
  <li>
    <p><strong>优先级合并问题</strong>：在一些优先级合并的场景中，带权并查集可以用来维护节点之间的优先级关系，同时可以根据节点的权值信息进行合适的合并操作。</p>
  </li>
  <li>
    <p><strong>社交网络中的关系处理</strong>：在社交网络中，可以使用带权并查集来处理关系，比如判断两个人是否属于同一个朋友圈、组织或团体，并且可以根据节点的权值信息来进行合适的处理和操作。</p>
  </li>
</ol>

<p>笔记：这些应用场景是带权并查集在实际问题中的一些常见应用，它能够帮助我们高效地处理具有权值信息的合并和查询问题，并且可以应用于各种领域的算法和数据结构中。</p>

<h2 id="最小生成树">最小生成树</h2>

<p>笔记：最小生成树（Minimum Spanning Tree，MST）是一个无向图的生成树，它包含图中的所有顶点，并且具有最小总权值的所有边。最小生成树在许多应用中都有重要的作用，比如网络设计、电力传输、通信网络等领域。</p>

<p>笔记：最小生成树算法有多种实现方式，其中最常见的算法包括：</p>

<ol>
  <li>
    <p><strong>Kruskal算法</strong>：Kruskal算法是一种贪心算法，它通过不断地选择具有最小权值的边，且不会形成环路，从而构建最小生成树。Kruskal算法通常基于并查集数据结构实现，用于判断边的两个顶点是否在同一个连通分量中。</p>
  </li>
  <li>
    <p><strong>Prim算法</strong>：Prim算法是一种基于顶点的贪心算法，它从一个初始顶点开始，逐步添加新的顶点，直到生成最小生成树。Prim算法通常基于优先队列（最小堆）实现，用于选择具有最小权值的边。</p>
  </li>
</ol>

<p>笔记：下面是Kruskal算法的基本实现示例：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">weight</span><span class="p">;</span>
    <span class="n">Edge</span><span class="p">(</span><span class="kt">int</span> <span class="n">_u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">_v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">_weight</span><span class="p">)</span> <span class="o">:</span> <span class="n">u</span><span class="p">(</span><span class="n">_u</span><span class="p">),</span> <span class="n">v</span><span class="p">(</span><span class="n">_v</span><span class="p">),</span> <span class="n">weight</span><span class="p">(</span><span class="n">_weight</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">};</span>

<span class="k">class</span> <span class="nc">DisjointSet</span> <span class="p">{</span>
<span class="nl">private:</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">parent</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">rank</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="n">DisjointSet</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">parent</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
        <span class="n">rank</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// 初始时每个元素都是独立的集合，其父结点为自身</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">Find</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">!=</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span> <span class="c1">// 路径压缩，将x的父结点设为根结点</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">parent</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">Union</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">rootX</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
        <span class="kt">int</span> <span class="n">rootY</span> <span class="o">=</span> <span class="n">Find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">rootX</span> <span class="o">!=</span> <span class="n">rootY</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootY</span><span class="p">;</span> <span class="c1">// 将x的根结点连接到y的根结点上</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">parent</span><span class="p">[</span><span class="n">rootY</span><span class="p">]</span> <span class="o">=</span> <span class="n">rootX</span><span class="p">;</span> <span class="c1">// 将y的根结点连接到x的根结点上</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span> <span class="o">==</span> <span class="n">rank</span><span class="p">[</span><span class="n">rootY</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">rank</span><span class="p">[</span><span class="n">rootX</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 如果秩相同，则任意选择一个作为根结点，并增加秩</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">kruskalMST</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;&amp;</span> <span class="n">edges</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">sort</span><span class="p">(</span><span class="n">edges</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">edges</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="k">const</span> <span class="n">Edge</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">Edge</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">weight</span> <span class="o">&lt;</span> <span class="n">b</span><span class="p">.</span><span class="n">weight</span><span class="p">;</span> <span class="c1">// 按边的权值升序排序</span>
    <span class="p">});</span>

    <span class="n">DisjointSet</span> <span class="n">dsu</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">minCost</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="n">Edge</span><span class="o">&amp;</span> <span class="n">edge</span> <span class="o">:</span> <span class="n">edges</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="n">edge</span><span class="p">.</span><span class="n">u</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dsu</span><span class="p">.</span><span class="n">Find</span><span class="p">(</span><span class="n">edge</span><span class="p">.</span><span class="n">v</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">dsu</span><span class="p">.</span><span class="n">Union</span><span class="p">(</span><span class="n">edge</span><span class="p">.</span><span class="n">u</span><span class="p">,</span> <span class="n">edge</span><span class="p">.</span><span class="n">v</span><span class="p">);</span>
            <span class="n">minCost</span> <span class="o">+=</span> <span class="n">edge</span><span class="p">.</span><span class="n">weight</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">minCost</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;</span> <span class="n">edges</span> <span class="o">=</span> <span class="p">{</span><span class="cm">/**/</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">15</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">}};</span>

    <span class="kt">int</span> <span class="n">minCost</span> <span class="o">=</span> <span class="n">kruskalMST</span><span class="p">(</span><span class="n">edges</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Minimum Cost of Spanning Tree: "</span> <span class="o">&lt;&lt;</span> <span class="n">minCost</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们使用Kruskal算法来计算图的最小生成树的总权值。首先将边按照权值升序排序，然后依次选择边，如果边的两个顶点不在同一个连通分量中，就将它们合并，并将边的权值加到总权值中。最终得到的总权值即为最小生成树的总权值。</p>

<p>笔记：Prim算法是另一种常用的最小生成树算法，它基于顶点的贪心策略，在构建最小生成树的过程中，每次选择与当前树连接的顶点中权值最小的边，将其加入最小生成树的集合中。Prim算法通常使用优先队列（最小堆）来选择下一个顶点，以保证每次选择的边权值最小。</p>

<p>笔记：以下是Prim算法的基本实现示例：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;climits&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">to</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">weight</span><span class="p">;</span>
    <span class="n">Edge</span><span class="p">(</span><span class="kt">int</span> <span class="n">_to</span><span class="p">,</span> <span class="kt">int</span> <span class="n">_weight</span><span class="p">)</span> <span class="o">:</span> <span class="n">to</span><span class="p">(</span><span class="n">_to</span><span class="p">),</span> <span class="n">weight</span><span class="p">(</span><span class="n">_weight</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">};</span>

<span class="k">class</span> <span class="nc">Graph</span> <span class="p">{</span>
<span class="nl">private:</span>
    <span class="kt">int</span> <span class="n">V</span><span class="p">;</span> <span class="c1">// 顶点数</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;&gt;</span> <span class="n">adj</span><span class="p">;</span> <span class="c1">// 邻接表表示的图</span>

<span class="nl">public:</span>
    <span class="n">Graph</span><span class="p">(</span><span class="kt">int</span> <span class="n">V</span><span class="p">)</span> <span class="o">:</span> <span class="n">V</span><span class="p">(</span><span class="n">V</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">adj</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">V</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">addEdge</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">weight</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">adj</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">Edge</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">weight</span><span class="p">));</span>
        <span class="n">adj</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">Edge</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">weight</span><span class="p">));</span> <span class="c1">// 无向图，双向连接</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">primMST</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">key</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">INT_MAX</span><span class="p">);</span> <span class="c1">// 存储顶点到最小生成树的最小权值</span>
        <span class="n">vector</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span> <span class="n">inMST</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span> <span class="c1">// 记录顶点是否已经加入最小生成树</span>
        <span class="kt">int</span> <span class="n">minCost</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// 最小生成树的总权值</span>

        <span class="c1">// 创建一个优先队列，按边的权值进行排序</span>
        <span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">,</span> <span class="n">greater</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;&gt;&gt;</span> <span class="n">pq</span><span class="p">;</span>

        <span class="c1">// 选择任意一个顶点作为起始点</span>
        <span class="kt">int</span> <span class="n">src</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">key</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// 将起始点的权值设为0</span>
        <span class="n">pq</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">make_pair</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">src</span><span class="p">));</span>

        <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">pq</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">pq</span><span class="p">.</span><span class="n">top</span><span class="p">().</span><span class="n">second</span><span class="p">;</span> <span class="c1">// 选择当前最小权值的顶点</span>
            <span class="n">pq</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">inMST</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="k">continue</span><span class="p">;</span> <span class="c1">// 如果顶点已经在最小生成树中，跳过</span>

            <span class="n">inMST</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// 将顶点加入最小生成树</span>

            <span class="c1">// 遍历与当前顶点相邻的边</span>
            <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="n">Edge</span><span class="o">&amp;</span> <span class="n">edge</span> <span class="o">:</span> <span class="n">adj</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="p">{</span>
                <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">edge</span><span class="p">.</span><span class="n">to</span><span class="p">;</span>
                <span class="kt">int</span> <span class="n">weight</span> <span class="o">=</span> <span class="n">edge</span><span class="p">.</span><span class="n">weight</span><span class="p">;</span>

                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inMST</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">weight</span> <span class="o">&lt;</span> <span class="n">key</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">key</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">;</span> <span class="c1">// 更新顶点到最小生成树的最小权值</span>
                    <span class="n">pq</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">make_pair</span><span class="p">(</span><span class="n">key</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">v</span><span class="p">));</span> <span class="c1">// 将顶点加入优先队列中</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="c1">// 计算最小生成树的总权值</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">V</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">minCost</span> <span class="o">+=</span> <span class="n">key</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">minCost</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">V</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">Graph</span> <span class="n">graph</span><span class="p">(</span><span class="n">V</span><span class="p">);</span>

    <span class="c1">// 添加图的边</span>
    <span class="n">graph</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
    <span class="n">graph</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span>
    <span class="n">graph</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">graph</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>
    <span class="n">graph</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
    <span class="n">graph</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">);</span>
    <span class="n">graph</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>

    <span class="c1">// 计算最小生成树的总权值</span>
    <span class="kt">int</span> <span class="n">minCost</span> <span class="o">=</span> <span class="n">graph</span><span class="p">.</span><span class="n">primMST</span><span class="p">();</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Minimum Cost of Spanning Tree: "</span> <span class="o">&lt;&lt;</span> <span class="n">minCost</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在Prim算法的实现中，我们使用了优先队列来存储待选的边，并通过不断地选择权值最小的边来构建最小生成树。该算法的时间复杂度为 O(ElogV)，其中 E 是边的数量，V 是顶点的数量。</p>

<h2 id="stl">STL</h2>

<p>笔记：STL（Standard Template Library）是C++标准库的一部分，提供了许多常用的数据结构和算法实现。STL包括多个组件，其中一些主要的组件有：</p>

<ol>
  <li>
    <p><strong>容器（Containers）</strong>：STL提供了多种容器，包括向量（vector）、列表（list）、双端队列（deque）、集合（set）、映射（map）等。这些容器提供了不同的数据组织方式，以满足不同的需求。</p>
  </li>
  <li>
    <p><strong>迭代器（Iterators）</strong>：迭代器是STL中用于遍历容器元素的抽象概念，它提供了统一的访问容器元素的接口。STL中的算法通常接受迭代器作为参数，以便对容器中的元素进行操作。</p>
  </li>
  <li>
    <p><strong>算法（Algorithms）</strong>：STL提供了大量的算法，涵盖了排序、搜索、复制、删除、变换等各种常见操作。这些算法通常定义在<algorithm>头文件中，可以直接使用。</algorithm></p>
  </li>
  <li>
    <p><strong>函数对象（Function Objects）</strong>：STL中的函数对象是一种可调用对象，它可以像函数一样被调用，但可以保持状态。函数对象在STL中被广泛用于算法的参数。</p>
  </li>
  <li>
    <p><strong>适配器（Adapters）</strong>：STL提供了一些适配器，用于将一个容器或迭代器接口转换成另一个容器或迭代器接口。常见的适配器包括堆栈（stack）、队列（queue）、优先队列（priority_queue）等。</p>
  </li>
</ol>

<p>笔记：下面是一个简单的示例，演示了STL中向量容器、迭代器和算法的使用：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// 创建一个向量容器并初始化</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span> <span class="o">=</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span>

    <span class="c1">// 使用迭代器遍历并输出向量中的元素</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Original vector: "</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">it</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="c1">// 使用STL中的算法对向量进行排序</span>
    <span class="n">sort</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>

    <span class="c1">// 使用迭代器遍历并输出排序后的向量</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Sorted vector: "</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">it</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="c1">// 使用STL中的算法查找向量中是否存在元素值为6的元素</span>
    <span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="mi">6</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element 6 found at position: "</span> <span class="o">&lt;&lt;</span> <span class="n">distance</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">it</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Element 6 not found in vector."</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：这个示例演示了如何使用STL中的向量容器、迭代器和算法。通过STL提供的丰富工具，我们可以更加方便地处理数据结构和算法问题，提高代码的效率和可读性。</p>

<h3 id="vector">vector</h3>

<p>笔记：<code class="language-plaintext highlighter-rouge">std::vector</code> 是 C++ 标准库中最常用的动态数组容器。它提供了动态大小的数组功能，可以在运行时根据需要动态增加或减少元素的个数。以下是关于 <code class="language-plaintext highlighter-rouge">std::vector</code> 的一些重要特性和用法：</p>

<h3 id="特性">特性：</h3>

<ol>
  <li>
    <p><strong>动态大小：</strong> <code class="language-plaintext highlighter-rouge">std::vector</code> 可以动态增长或缩小，根据需要自动调整内部存储空间。</p>
  </li>
  <li>
    <p><strong>随机访问：</strong> 可以通过索引直接访问 <code class="language-plaintext highlighter-rouge">std::vector</code> 中的元素，时间复杂度为 O(1)。</p>
  </li>
  <li>
    <p><strong>连续存储：</strong> <code class="language-plaintext highlighter-rouge">std::vector</code> 中的元素在内存中是连续存储的，这使得访问元素的速度更快。</p>
  </li>
  <li>
    <p><strong>自动管理内存：</strong> <code class="language-plaintext highlighter-rouge">std::vector</code> 自动处理内存的分配和释放，使得使用更加方便。</p>
  </li>
</ol>

<h3 id="用法示例">用法示例：</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// 创建一个空的 vector</span>
    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span><span class="p">;</span>

    <span class="c1">// 添加元素到 vector</span>
    <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
    <span class="n">vec</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>

    <span class="c1">// 使用迭代器遍历 vector</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Vector elements: "</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">it</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>

    <span class="c1">// 访问 vector 中的元素</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"First element: "</span> <span class="o">&lt;&lt;</span> <span class="n">vec</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Second element: "</span> <span class="o">&lt;&lt;</span> <span class="n">vec</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>

    <span class="c1">// 修改 vector 中的元素</span>
    <span class="n">vec</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>

    <span class="c1">// 删除 vector 中的元素</span>
    <span class="n">vec</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span>

    <span class="c1">// 获取 vector 的大小和容量</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Size of vector: "</span> <span class="o">&lt;&lt;</span> <span class="n">vec</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Capacity of vector: "</span> <span class="o">&lt;&lt;</span> <span class="n">vec</span><span class="p">.</span><span class="n">capacity</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>

    <span class="c1">// 清空 vector</span>
    <span class="n">vec</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span>

    <span class="c1">// 检查 vector 是否为空</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Vector is empty"</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们演示了如何使用 <code class="language-plaintext highlighter-rouge">std::vector</code> 创建动态数组，添加、访问、修改和删除元素，以及获取其大小、容量，并清空向量。<code class="language-plaintext highlighter-rouge">std::vector</code> 提供了简单而强大的动态数组功能，在许多场景下都是首选的容器类型。</p>

<h2 id="背包问题">背包问题</h2>

<p>笔记：背包问题是一个经典的组合优化问题，在计算机科学和组合数学中都有重要的应用。背包问题通常包括一个背包容量限制以及一组物品，每个物品都有自己的重量和价值。目标是在不超过背包容量的情况下，选择合适的物品放入背包，使得背包中物品的总价值最大。</p>

<p>笔记：背包问题通常分为两种类型：</p>

<ol>
  <li>
    <p><strong>0-1背包问题（0-1 Knapsack Problem）：</strong> 每个物品要么全部装入背包，要么不装入，不能选择部分装入物品。这意味着每种物品只有两种状态：选中或不选中。</p>
  </li>
  <li>
    <p><strong>分数背包问题（Fractional Knapsack Problem）：</strong> 每个物品可以被分割成更小的部分放入背包，所以可以选择部分装入物品。这样，每种物品就有更多的状态，可以是部分选中。</p>
  </li>
</ol>

<p>笔记：以下是两种背包问题的基本介绍和解决方法：</p>

<h3 id="0-1背包问题">0-1背包问题：</h3>

<h4 id="解决方法">解决方法：</h4>

<ol>
  <li>
    <p><strong>动态规划（Dynamic Programming）：</strong> 使用动态规划算法可以有效地解决0-1背包问题。定义一个二维数组 <code class="language-plaintext highlighter-rouge">dp[i][j]</code>，表示在前 i 个物品中，背包容量为 j 时可以获得的最大价值。然后根据递推关系进行状态转移，最终得到 <code class="language-plaintext highlighter-rouge">dp[n][W]</code> 就是所求的最大价值，其中 n 表示物品数量，W 表示背包容量。</p>
  </li>
  <li>
    <p><strong>回溯法（Backtracking）：</strong> 可以使用回溯法穷举所有可能的选择方案，然后选择价值最大的方案作为最优解。但是由于背包问题的指数级复杂度，回溯法不适合处理大规模的背包问题。</p>
  </li>
</ol>

<h3 id="分数背包问题">分数背包问题：</h3>

<h4 id="解决方法-1">解决方法：</h4>

<ol>
  <li><strong>贪心算法（Greedy Algorithm）：</strong> 对于分数背包问题，贪心算法是一个常用的解决方法。贪心算法根据每种物品的单位重量价值来进行选择，优先选择单位重量价值最高的物品放入背包。这种方法可以得到一个近似最优解，但不一定能够保证获得最优解。</li>
</ol>

<p>笔记：背包问题是一个经典的组合优化问题，对于0-1背包问题，动态规划是最常用的解决方法，而对于分数背包问题，贪心算法通常是一个简单而有效的解决方案。</p>

<p>笔记：在继续讨论背包问题之前，我们可以详细了解一下0-1背包问题和分数背包问题的解决方法，以及它们的特点和应用场景。</p>

<h3 id="0-1背包问题0-1-knapsack-problem">0-1背包问题（0-1 Knapsack Problem）：</h3>

<h4 id="特点">特点：</h4>

<ul>
  <li>每种物品只有两种状态：选中或不选中。</li>
  <li>物品不可分割，要么全部装入背包，要么不装入。</li>
</ul>

<h4 id="解决方法-2">解决方法：</h4>

<ol>
  <li><strong>动态规划（Dynamic Programming）：</strong> 使用动态规划算法来解决0-1背包问题，通常需要构建一个二维数组 <code class="language-plaintext highlighter-rouge">dp[i][j]</code>，表示在前 i 个物品中，背包容量为 j 时可以获得的最大价值。然后根据递推关系进行状态转移，最终得到 <code class="language-plaintext highlighter-rouge">dp[n][W]</code> 就是所求的最大价值，其中 n 表示物品数量，W 表示背包容量。</li>
</ol>

<h3 id="分数背包问题fractional-knapsack-problem">分数背包问题（Fractional Knapsack Problem）：</h3>

<h4 id="特点-1">特点：</h4>

<ul>
  <li>每种物品可以被分割成更小的部分放入背包。</li>
  <li>物品可以选择部分装入背包。</li>
</ul>

<h4 id="解决方法-3">解决方法：</h4>

<ol>
  <li><strong>贪心算法（Greedy Algorithm）：</strong> 对于分数背包问题，贪心算法是一个常用的解决方法。贪心算法根据每种物品的单位重量价值来进行选择，优先选择单位重量价值最高的物品放入背包。这种方法可以得到一个近似最优解，但不一定能够保证获得最优解。</li>
</ol>

<h3 id="应用场景">应用场景：</h3>

<ul>
  <li>背包问题在资源分配和优化领域有着广泛的应用，比如货物装载、资源分配、投资组合优化等。</li>
  <li>0-1背包问题常见于资源有限、决策离散的场景，如物品装载、任务调度等。</li>
  <li>分数背包问题常见于资源可以分割、决策连续的场景，如化工原料混合、机器加工等。</li>
</ul>

<p>笔记：以上是关于背包问题的一些基本概念、解决方法和应用场景。在实际问题中，根据具体的情况和要求，选择合适的背包问题类型和解决方法来解决问题是非常重要的。</p>

<p>笔记：多重背包问题是背包问题的一个变种，与0-1背包问题和分数背包问题不同，多重背包问题中每种物品都有限定的数量可供选择，即每种物品都有多个相同的物品可供放入背包。与普通的背包问题相比，多重背包问题增加了对物品数量的限制，这使得问题更加复杂。</p>

<h3 id="解决方法-4">解决方法：</h3>

<ol>
  <li>
    <p><strong>二进制拆分法：</strong> 将多重背包问题转化为0-1背包问题。对于每种物品，根据其数量进行二进制拆分，将每种物品拆分成若干个数量为 1 的物品和数量为 2 的物品，然后使用0-1背包问题的动态规划算法进行求解。</p>
  </li>
  <li>
    <p><strong>多重背包问题优化：</strong> 在动态规划算法中，可以对多重背包问题进行优化。对于数量较大的物品，可以考虑采用优化策略，比如分组思想、二进制优化等方法，以减少时间和空间复杂度。</p>
  </li>
</ol>

<h3 id="应用场景-1">应用场景：</h3>

<ul>
  <li>多重背包问题常见于需要考虑资源数量限制的场景，如货物运输、物资调配等。</li>
  <li>在实际问题中，有些物品可能存在多个相同的副本，需要根据具体的资源分配情况进行合理的选择和分配。</li>
</ul>

<p>笔记：下面是一个简单的示例，演示了如何使用动态规划算法解决多重背包问题：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">multipleKnapsack</span><span class="p">(</span><span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="kt">int</span> <span class="n">W</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">weight</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">value</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">quantity</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">dp</span><span class="p">(</span><span class="n">W</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">W</span><span class="p">;</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="n">weight</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="o">--</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;=</span> <span class="n">quantity</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">k</span> <span class="o">*</span> <span class="n">weight</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">j</span><span class="p">;</span> <span class="o">++</span><span class="n">k</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">dp</span><span class="p">[</span><span class="n">j</span> <span class="o">-</span> <span class="n">k</span> <span class="o">*</span> <span class="n">weight</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">+</span> <span class="n">k</span> <span class="o">*</span> <span class="n">value</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">W</span><span class="p">];</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// 物品种类数</span>
    <span class="kt">int</span> <span class="n">W</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span> <span class="c1">// 背包容量</span>

    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">weight</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> <span class="c1">// 每种物品的重量</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">value</span> <span class="o">=</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> <span class="c1">// 每种物品的价值</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">quantity</span> <span class="o">=</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">};</span> <span class="c1">// 每种物品的数量</span>

    <span class="kt">int</span> <span class="n">maxValue</span> <span class="o">=</span> <span class="n">multipleKnapsack</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">W</span><span class="p">,</span> <span class="n">weight</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">quantity</span><span class="p">);</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Maximum value that can be obtained: "</span> <span class="o">&lt;&lt;</span> <span class="n">maxValue</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>笔记：在这个示例中，我们使用动态规划算法解决了一个多重背包问题。通过状态转移方程，我们可以有效地计算出背包容量为W时可以获得的最大价值。</p>

<p>笔记：完全背包问题和混合背包问题是背包问题的两个变种，它们分别考虑了不同的限制条件和特性。</p>

<h3 id="完全背包问题unbounded-knapsack-problem">完全背包问题（Unbounded Knapsack Problem）：</h3>

<p>笔记：完全背包问题是背包问题的一个变种，与0-1背包问题不同，完全背包问题中每种物品的数量是无限的，即可以选择多次放入同一种物品。因此，完全背包问题通常更加复杂，需要使用不同的解决方法。</p>

<h4 id="解决方法-5">解决方法：</h4>

<ol>
  <li><strong>动态规划：</strong> 使用动态规划算法可以有效地解决完全背包问题。与0-1背包问题类似，定义一个二维数组 <code class="language-plaintext highlighter-rouge">dp[i][j]</code>，表示在前 i 个物品中，背包容量为 j 时可以获得的最大价值。然后根据递推关系进行状态转移，最终得到 <code class="language-plaintext highlighter-rouge">dp[n][W]</code> 就是所求的最大价值，其中 n 表示物品数量，W 表示背包容量。</li>
</ol>

<h3 id="混合背包问题mixed-knapsack-problem">混合背包问题（Mixed Knapsack Problem）：</h3>

<p>笔记：混合背包问题是背包问题的另一个变种，它将0-1背包问题、完全背包问题和多重背包问题组合在一起，每种物品可以根据情况选择放入背包、不放入背包或者放入有限的数量。混合背包问题考虑了更复杂的资源分配情况，因此需要更灵活的解决方法。</p>

<h4 id="解决方法-6">解决方法：</h4>

<ol>
  <li><strong>动态规划：</strong> 可以将混合背包问题转化为0-1背包问题、完全背包问题和多重背包问题的组合，然后使用动态规划算法进行求解。根据每种物品的限制条件和背包容量，分别求解最优解，并将结果合并得到最终的解决方案。</li>
</ol>

<p>笔记：混合背包问题的解决方法通常需要根据具体的限制条件和资源分配情况进行灵活的选择和组合。在实际应用中，根据问题的具体要求和限制条件，选择合适的解决方法是非常重要的。</p>]]></content><author><name></name></author><category term="notes" /><category term="codes" /><summary type="html"><![CDATA[数据结构。 1. 数组（Array） 解释： 数组是一种线性数据结构，由一系列连续的内存单元组成，用于存储相同类型的元素。 基本操作： 访问、插入、删除、查找。 示例代码（Python）： # 创建数组 arr = [1, 2, 3, 4, 5] # 访问元素 print(arr[0]) # 输出：1 # 插入元素 arr.append(6) # 删除元素 del arr[2] # 查找元素 if 3 in arr: print("Element found") 2. 链表（Linked List） 解释： 链表是一种线性数据结构，由一系列节点组成，每个节点包含数据和指向下一个节点的引用。 基本操作： 插入、删除、查找。 示例代码（Python）： # 定义节点 class Node: def __init__(self, data): self.data = data self.next = None # 创建链表 class LinkedList: def __init__(self): self.head = None # 在链表末尾插入节点 def append(self, data): new_node = Node(data) if self.head is None: self.head = new_node return last_node = self.head while last_node.next: last_node = last_node.next last_node.next = new_node # 在链表中删除节点 def delete(self, key): temp = self.head if temp is not None: if temp.data == key: self.head = temp.next temp = None return while temp is not None: if temp.data == key: break prev = temp temp = temp.next if temp == None: return prev.next = temp.next temp = None 栈 笔记：栈（Stack）是一种线性数据结构，具有后进先出（Last In, First Out，LIFO）的特性，即最后进入栈的元素最先被访问或移出。栈通常具有以下基本操作： 压入（Push）：将元素添加到栈的顶部。 弹出（Pop）：从栈顶移除元素。 查看栈顶元素（Peek）：获取栈顶的元素值，但不对栈进行修改。 判空（isEmpty）：判断栈是否为空。 获取栈的大小（getSize）：获取栈中元素的数量。 笔记：栈可以通过数组或链表实现。 栈的应用： 函数调用栈：在编程中，函数调用时使用栈来保存函数的局部变量和返回地址。 表达式求值：如中缀表达式转换为后缀表达式并求值。 内存管理：栈用于跟踪内存中变量的分配和释放。 浏览器历史记录：浏览器使用栈来实现“后退”和“前进”按钮的功能。 撤销操作：许多应用程序使用栈来实现撤销操作。 栈的示例代码（Python）： class Stack: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def push(self, item): self.items.append(item) def pop(self): if not self.isEmpty(): return self.items.pop() else: return "Stack is empty" def peek(self): if not self.isEmpty(): return self.items[-1] else: return "Stack is empty" def getSize(self): return len(self.items) # 示例 stack = Stack() stack.push(1) stack.push(2) stack.push(3) print("Stack peek:", stack.peek()) # 输出：3 print("Stack size:", stack.getSize()) # 输出：3 print("Popped item:", stack.pop()) # 输出：3 笔记：栈是一种简单而强大的数据结构，常用于许多编程场景中。理解栈的原理和应用有助于提高编程效率和解决问题的能力。 队列 笔记：队列（Queue）是一种线性数据结构，具有先进先出（First In, First Out，FIFO）的特性，即最先进入队列的元素最先被访问或移出。队列通常具有以下基本操作： 入队（Enqueue）：将元素添加到队列的尾部。 出队（Dequeue）：从队列的头部移除元素。 查看队首元素（Peek）：获取队列头部的元素值，但不对队列进行修改。 判空（isEmpty）：判断队列是否为空。 获取队列的大小（getSize）：获取队列中元素的数量。 笔记：队列可以通过数组或链表实现。 队列的应用： 任务调度：操作系统中进程的调度使用队列来实现先来先服务（FCFS）或其他调度算法。 消息传递：在计算机网络和消息队列系统中，队列用于传递和处理消息。 广度优先搜索（BFS）：在图的搜索算法中，BFS使用队列来保存遍历的顶点。 缓存：在计算机系统中，队列用于实现缓存淘汰策略，如最近最少使用（LRU）。 打印队列：打印机使用队列来管理打印作业的顺序。 队列的示例代码（Python）： class Queue: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): self.items.append(item) def dequeue(self): if not self.isEmpty(): return self.items.pop(0) else: return "Queue is empty" def peek(self): if not self.isEmpty(): return self.items[0] else: return "Queue is empty" def getSize(self): return len(self.items) # 示例 queue = Queue() queue.enqueue(1) queue.enqueue(2) queue.enqueue(3) print("Queue peek:", queue.peek()) # 输出：1 print("Queue size:", queue.getSize()) # 输出：3 print("Dequeued item:", queue.dequeue()) # 输出：1 笔记：队列是一种常用的数据结构，在许多领域都有广泛的应用。理解队列的原理和使用方法有助于提高编程的效率和解决问题的能力。 笔记：以下是C++代码示例，涵盖了数组、链表、队列、树、图、集合和映射的基本实现，并附有简要解释： 数组（Array）： #include &lt;iostream&gt; using namespace std; int main() { int arr[5] = {1, 2, 3, 4, 5}; for (int i = 0; i &lt; 5; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 数组是一种用于存储相同类型元素的线性数据结构。在这个例子中，我们创建了一个包含五个整数的数组，并通过循环遍历打印数组中的元素。 链表（Linked List）： #include &lt;iostream&gt; using namespace std; struct Node { int data; Node* next; }; int main() { Node* head = new Node(); head-&gt;data = 1; head-&gt;next = nullptr; Node* second = new Node(); second-&gt;data = 2; second-&gt;next = nullptr; head-&gt;next = second; return 0; } 链表是一种由节点组成的线性数据结构，每个节点包含数据和指向下一个节点的指针。在这个例子中，我们创建了两个节点，并使用指针连接它们，形成一个简单的链表。 队列（Queue）： #include &lt;iostream&gt; #include &lt;queue&gt; using namespace std; int main() { queue&lt;int&gt; q; q.push(1); q.push(2); q.push(3); while (!q.empty()) { cout &lt;&lt; q.front() &lt;&lt; " "; q.pop(); } return 0; } 队列是一种先进先出（FIFO）的线性数据结构，支持在队尾插入元素，队头删除元素。在这个例子中，我们使用标准库中的队列来演示队列的基本操作。 树（Tree）： #include &lt;iostream&gt; using namespace std; struct TreeNode { int data; TreeNode* left; TreeNode* right; }; int main() { TreeNode* root = new TreeNode(); root-&gt;data = 1; root-&gt;left = new TreeNode(); root-&gt;left-&gt;data = 2; root-&gt;right = new TreeNode(); root-&gt;right-&gt;data = 3; return 0; } 树是一种非线性数据结构，由节点组成，每个节点有一个父节点和零个或多个子节点。在这个例子中，我们创建了一个简单的二叉树，并分配了节点的数据和连接关系。 图（Graph）： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; int main() { vector&lt;vector&lt;int&gt;&gt; graph = { {0, 1, 0, 0}, {1, 0, 1, 1}, {0, 1, 0, 1}, {0, 1, 1, 0} }; // 可以根据需要对图进行进一步的操作 return 0; } 图是由节点和边组成的非线性数据结构。在这个例子中，我们使用邻接矩阵表示图的连接关系。 集合（Set）： #include &lt;iostream&gt; #include &lt;set&gt; using namespace std; int main() { set&lt;int&gt; s; s.insert(1); s.insert(2); s.insert(3); for (auto it = s.begin(); it != s.end(); ++it) { cout &lt;&lt; *it &lt;&lt; " "; } return 0; } 集合是一种不重复元素的数据结构。在这个例子中，我们使用集合来存储整数，并通过迭代器遍历集合中的元素。 映射（Map）： #include &lt;iostream&gt; #include &lt;map&gt; using namespace std; int main() { map&lt;string, int&gt; m; m["one"] = 1; m["two"] = 2; m["three"] = 3; for (auto it = m.begin(); it != m.end(); ++it) { cout &lt;&lt; it-&gt;first &lt;&lt; ": " &lt;&lt; it-&gt;second &lt;&lt; endl; } return 0; } 映射是一种键值对的数据结构。在这个例子中，我们使用映射来存储字符串和对应的整数，并通过迭代器遍历映射中的键值对。 笔记：这些示例展示了 C++ 中基本数据结构的简单实现，帮助理解它们的基本概念和用法。 笔记：以下是C代码示例，涵盖了数组、链表、队列、树、图、集合和映射的基本实现，并附有简要解释： 数组（Array）： #include &lt;stdio.h&gt; int main() { int arr[5] = {1, 2, 3, 4, 5}; for (int i = 0; i &lt; 5; ++i) { printf("%d ", arr[i]); } return 0; } 数组是一种用于存储相同类型元素的线性数据结构。在这个例子中，我们创建了一个包含五个整数的数组，并通过循环遍历打印数组中的元素。 链表（Linked List）： #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; struct Node { int data; struct Node* next; }; int main() { struct Node* head = (struct Node*)malloc(sizeof(struct Node)); head-&gt;data = 1; head-&gt;next = NULL; struct Node* second = (struct Node*)malloc(sizeof(struct Node)); second-&gt;data = 2; second-&gt;next = NULL; head-&gt;next = second; return 0; } 链表是一种由节点组成的线性数据结构，每个节点包含数据和指向下一个节点的指针。在这个例子中，我们创建了两个节点，并使用指针连接它们，形成一个简单的链表。 队列（Queue）： #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; struct Queue { int* items; int front; int rear; int capacity; }; int main() { struct Queue q; q.capacity = 5; q.front = 0; q.rear = -1; q.items = (int*)malloc(q.capacity * sizeof(int)); q.items[++q.rear] = 1; q.items[++q.rear] = 2; q.items[++q.rear] = 3; while (q.front &lt;= q.rear) { printf("%d ", q.items[q.front++]); } free(q.items); return 0; } 队列是一种先进先出（FIFO）的线性数据结构，支持在队尾插入元素，队头删除元素。在这个例子中，我们使用数组实现了一个简单的队列。 树（Tree）： #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; struct TreeNode { int data; struct TreeNode* left; struct TreeNode* right; }; int main() { struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root-&gt;data = 1; root-&gt;left = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root-&gt;left-&gt;data = 2; root-&gt;left-&gt;left = NULL; root-&gt;left-&gt;right = NULL; root-&gt;right = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root-&gt;right-&gt;data = 3; root-&gt;right-&gt;left = NULL; root-&gt;right-&gt;right = NULL; return 0; } 树是一种非线性数据结构，由节点组成，每个节点有一个父节点和零个或多个子节点。在这个例子中，我们创建了一个简单的二叉树，并分配了节点的数据和连接关系。 图（Graph）： #include &lt;stdio.h&gt; int main() { int graph[4][4] = { {0, 1, 0, 0}, {1, 0, 1, 1}, {0, 1, 0, 1}, {0, 1, 1, 0} }; // 可以根据需要对图进行进一步的操作 return 0; } 图是由节点和边组成的非线性数据结构。在这个例子中，我们使用邻接矩阵表示图的连接关系。 集合（Set）： #include &lt;stdio.h&gt; #include &lt;stdbool.h&gt; #define SET_SIZE 5 int main() { int set[SET_SIZE] = {1, 2, 3, 4, 5}; for (int i = 0; i &lt; SET_SIZE; ++i) { printf("%d ", set[i]); } return 0; } 集合是一种不重复元素的数据结构。在这个例子中，我们创建了一个整数集合并打印了集合中的元素。 映射（Map）： #include &lt;stdio.h&gt; int main() { struct Map { char key; int value; }; struct Map map[3] = { {'a', 1}, {'b', 2}, {'c', 3} }; for (int i = 0; i &lt; 3; ++i) { printf("%c: %d\n", map[i].key, map[i].value); } return 0; } 映射是一种键值对的数据结构。在这个例子中，我们使用结构体数组实现了一个简单的映射，并打印了映射中的键值对。 笔记：这些示例展示了 C 中基本数据结构的简单实现，帮助理解它们的基本概念和用法。 C语言实现： 平衡树（Balanced Tree）： 笔记：平衡树是一种树形数据结构，确保在插入或删除元素时树的高度保持较小的增量，从而保持树的平衡性。常见的平衡树包括AVL树、红黑树等。 堆（Heap）： 笔记：堆是一种特殊的树形数据结构，通常是一个数组对象，用于表示完全二叉树。堆的性质是父节点的键值总是保持固定的序关系，如小顶堆中父节点的值小于或等于子节点的值，大顶堆则相反。 哈希表（Hash Table）： 笔记：哈希表是一种数据结构，用于存储键值对。哈希表通过将键映射到表中的一个位置来加快查找速度。在哈希表中，键的值经过哈希函数计算后得到一个索引，然后将值存储在对应的索引位置。 图算法（Graph Algorithms）： 笔记：图算法是针对图数据结构的算法，用于解决图中的各种问题，如最短路径、最小生成树、图的遍历等。常见的图算法包括深度优先搜索（DFS）、广度优先搜索（BFS）、Dijkstra算法、Prim算法等。 C++语言实现： 平衡树（Balanced Tree）： 笔记：C++中可以使用STL提供的set和map来实现平衡树，set基于红黑树实现，map是基于红黑树实现的关联容器，确保元素有序。 #include &lt;set&gt; #include &lt;map&gt; using namespace std; int main() { // 使用set实现平衡树 set&lt;int&gt; balancedTree; balancedTree.insert(3); balancedTree.insert(1); balancedTree.insert(5); // 使用map实现平衡树 map&lt;char, int&gt; balancedMap; balancedMap['a'] = 1; balancedMap['b'] = 2; balancedMap['c'] = 3; return 0; } 堆（Heap）： 笔记：C++中可以使用STL提供的priority_queue来实现堆，它是一个基于堆的优先队列容器，支持在队列的头部进行快速插入和删除操作。 #include &lt;queue&gt; using namespace std; int main() { // 最小堆 priority_queue&lt;int, vector&lt;int&gt;, greater&lt;int&gt;&gt; minHeap; minHeap.push(3); minHeap.push(1); minHeap.push(5); // 最大堆 priority_queue&lt;int&gt; maxHeap; maxHeap.push(3); maxHeap.push(1); maxHeap.push(5); return 0; } 哈希表（Hash Table）： 笔记：C++中可以使用STL提供的unordered_map来实现哈希表，它是一个基于哈希函数的关联容器，支持在常数时间内进行插入、删除和查找操作。 #include &lt;unordered_map&gt; using namespace std; int main() { unordered_map&lt;string, int&gt; hashTable; hashTable["apple"] = 10; hashTable["banana"] = 5; hashTable["orange"] = 15; return 0; } 图算法（Graph Algorithms）： 笔记：C++中可以使用图算法库Boost Graph Library（BGL）来实现各种图算法，包括最短路径、最小生成树、图的遍历等。 #include &lt;boost/graph/adjacency_list.hpp&gt; #include &lt;boost/graph/dijkstra_shortest_paths.hpp&gt; #include &lt;boost/graph/kruskal_min_spanning_tree.hpp&gt; using namespace boost; int main() { typedef adjacency_list&lt;vecS, vecS, undirectedS, no_property, property&lt;edge_weight_t, int&gt;&gt; Graph; Graph g(4); add_edge(0, 1, 2, g); add_edge(1, 2, 3, g); add_edge(2, 3, 1, g); // 最短路径 vector&lt;int&gt; distances(num_vertices(g)); dijkstra_shortest_paths(g, 0, distance_map(&amp;distances[0])); // 最小生成树 vector&lt;Graph::edge_descriptor&gt; spanning_tree; kruskal_minimum_spanning_tree(g, back_in 遍历（Traversal）： 笔记：遍历是指访问数据结构中的所有元素的过程。常见的数据结构包括数组、链表、树和图。以下是C++中常见数据结构的遍历方法： 数组遍历： #include &lt;iostream&gt; using namespace std; int main() { int arr[] = {1, 2, 3, 4, 5}; int n = sizeof(arr) / sizeof(arr[0]); for (int i = 0; i &lt; n; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 数组遍历是通过循环逐个访问数组中的元素。 链表遍历： #include &lt;iostream&gt; using namespace std; struct Node { int data; Node* next; }; int main() { Node* head = new Node(); head-&gt;data = 1; head-&gt;next = NULL; Node* current = head; while (current != NULL) { cout &lt;&lt; current-&gt;data &lt;&lt; " "; current = current-&gt;next; } return 0; } 链表遍历是通过指针依次访问链表中的节点。 树的遍历： #include &lt;iostream&gt; using namespace std; struct TreeNode { int data; TreeNode* left; TreeNode* right; }; void inorderTraversal(TreeNode* root) { if (root == NULL) return; inorderTraversal(root-&gt;left); cout &lt;&lt; root-&gt;data &lt;&lt; " "; inorderTraversal(root-&gt;right); } int main() { TreeNode* root = new TreeNode(); root-&gt;data = 1; root-&gt;left = NULL; root-&gt;right = NULL; inorderTraversal(root); return 0; } 树的中序遍历是先访问左子树，然后访问根节点，最后访问右子树。 图的遍历： 笔记：对于图的遍历，通常使用深度优先搜索（DFS）或广度优先搜索（BFS）。 排序（Sorting）： 笔记：排序是将一组数据按照一定的规则重新排列的过程，常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。 #include &lt;iostream&gt; #include &lt;algorithm&gt; using namespace std; int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); sort(arr, arr + n); for (int i = 0; i &lt; n; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 以上是C++中使用STL的sort函数对数组进行排序的示例。 搜索（Searching）： 笔记：搜索是在数据集合中查找特定元素的过程。常见的搜索算法包括线性搜索、二分搜索等。 #include &lt;iostream&gt; using namespace std; int linearSearch(int arr[], int n, int target) { for (int i = 0; i &lt; n; ++i) { if (arr[i] == target) { return i; } } return -1; } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); int target = 4; int index = linearSearch(arr, n, target); if (index != -1) { cout &lt;&lt; "Element found at index: " &lt;&lt; index &lt;&lt; endl; } else { cout &lt;&lt; "Element not found" &lt;&lt; endl; } return 0; } 以上是C++中线性搜索的示例。 排序（Sorting）： 笔记：排序是将一组数据按照一定的规则重新排列的过程，常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。 冒泡排序（Bubble Sort）： #include &lt;iostream&gt; using namespace std; void bubbleSort(int arr[], int n) { for (int i = 0; i &lt; n - 1; ++i) { for (int j = 0; j &lt; n - i - 1; ++j) { if (arr[j] &gt; arr[j + 1]) { swap(arr[j], arr[j + 1]); } } } } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); bubbleSort(arr, n); for (int i = 0; i &lt; n; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 冒泡排序是一种基本的排序算法，它重复地走访过要排序的元素列，依次比较相邻的两个元素，如果顺序不对则交换。 搜索（Searching）： 笔记：搜索是在数据集合中查找特定元素的过程。常见的搜索算法包括线性搜索、二分搜索等。 二分搜索（Binary Search）： #include &lt;iostream&gt; using namespace std; int binarySearch(int arr[], int left, int right, int target) { while (left &lt;= right) { int mid = left + (right - left) / 2; if (arr[mid] == target) { return mid; } if (arr[mid] &lt; target) { left = mid + 1; } else { right = mid - 1; } } return -1; } int main() { int arr[] = {1, 2, 3, 4, 5}; int n = sizeof(arr) / sizeof(arr[0]); int target = 4; int index = binarySearch(arr, 0, n - 1, target); if (index != -1) { cout &lt;&lt; "Element found at index: " &lt;&lt; index &lt;&lt; endl; } else { cout &lt;&lt; "Element not found" &lt;&lt; endl; } return 0; } 二分搜索是一种在有序数组中查找特定元素的搜索算法，它通过将目标值与数组中间元素比较来决定下一步搜索的方向。 排序（Sorting）： 选择排序（Selection Sort）： #include &lt;iostream&gt; using namespace std; void selectionSort(int arr[], int n) { for (int i = 0; i &lt; n - 1; ++i) { int minIndex = i; for (int j = i + 1; j &lt; n; ++j) { if (arr[j] &lt; arr[minIndex]) { minIndex = j; } } swap(arr[i], arr[minIndex]); } } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); selectionSort(arr, n); for (int i = 0; i &lt; n; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 选择排序是一种简单直观的排序算法，它的基本思想是每一次从待排序的数据元素中选出最小（或最大）的一个元素，存放在序列的起始位置。 插入排序（Insertion Sort）： #include &lt;iostream&gt; using namespace std; void insertionSort(int arr[], int n) { for (int i = 1; i &lt; n; ++i) { int key = arr[i]; int j = i - 1; while (j &gt;= 0 &amp;&amp; arr[j] &gt; key) { arr[j + 1] = arr[j]; j = j - 1; } arr[j + 1] = key; } } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); insertionSort(arr, n); for (int i = 0; i &lt; n; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 插入排序是一种简单直观的排序算法，它的基本思想是每次将一个待排序的元素，按其关键字的大小插入到已经排好序的一组元素的适当位置上。 搜索（Searching）： 线性搜索（Linear Search）： #include &lt;iostream&gt; using namespace std; int linearSearch(int arr[], int n, int target) { for (int i = 0; i &lt; n; ++i) { if (arr[i] == target) { return i; } } return -1; } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); int target = 4; int index = linearSearch(arr, n, target); if (index != -1) { cout &lt;&lt; "Element found at index: " &lt;&lt; index &lt;&lt; endl; } else { cout &lt;&lt; "Element not found" &lt;&lt; endl; } return 0; } 线性搜索是一种基础的搜索算法，它逐个地检查数据结构中的每个元素，直到找到目标元素或搜索到数据结构的末尾。 排序（Sorting）： 快速排序（Quick Sort）： #include &lt;iostream&gt; using namespace std; void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j &lt;= high - 1; j++) { if (arr[j] &lt; pivot) { i++; swap(&amp;arr[i], &amp;arr[j]); } } swap(&amp;arr[i + 1], &amp;arr[high]); return i + 1; } void quickSort(int arr[], int low, int high) { if (low &lt; high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n - 1); for (int i = 0; i &lt; n; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 快速排序是一种高效的排序算法，它采用了分治的思想，通过选择一个基准元素，将数据分割成两个子数组，小于基准的元素放在左边，大于基准的元素放在右边，然后对子数组进行递归排序。 归并排序（Merge Sort）： #include &lt;iostream&gt; using namespace std; void merge(int arr[], int l, int m, int r) { int n1 = m - l + 1; int n2 = r - m; int L[n1], R[n2]; for (int i = 0; i &lt; n1; i++) L[i] = arr[l + i]; for (int j = 0; j &lt; n2; j++) R[j] = arr[m + 1 + j]; int i = 0; int j = 0; int k = l; while (i &lt; n1 &amp;&amp; j &lt; n2) { if (L[i] &lt;= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } while (i &lt; n1) { arr[k] = L[i]; i++; k++; } while (j &lt; n2) { arr[k] = R[j]; j++; k++; } } void mergeSort(int arr[], int l, int r) { if (l &gt;= r) { return; } int m = l + (r - l) / 2; mergeSort(arr, l, m); mergeSort(arr, m + 1, r); merge(arr, l, m, r); } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(arr[0]); mergeSort(arr, 0, n - 1); for (int i = 0; i &lt; n; ++i) { cout &lt;&lt; arr[i] &lt;&lt; " "; } return 0; } 归并排序是一种稳定的排序算法，它将数据分成两个子序列，分别进行递归排序，然后合并两个有序子序列。 搜索（Searching）： 二分搜索（Binary Search）： #include &lt;iostream&gt; using namespace std; int binarySearch(int arr[], int left, int right, int target) { while (left &lt;= right) { int mid = left + (right - left) / 2; if (arr[mid] == target) { return mid; } if (arr[mid] &lt; target) { left = mid + 1; } else { right = mid - 1; } } return -1; } int main() { int arr[] = {1, 2, 3, 4, 5}; int n = sizeof(arr) / sizeof(arr[0]); int target = 4; int index = binarySearch(arr, 0, n - 1, target); if (index != -1) { cout &lt;&lt; "Element found at index: " &lt;&lt; index &lt;&lt; endl; } else { cout &lt;&lt; "Element not found" &lt;&lt; endl; } return 0; } 二分搜索是一种高效的搜索算法，但它要求数据必须是有序的。它通过反复将查找范围划分为两半并比较中间元素来减少需要检查的元素数量。 深度优先搜索（Depth First Search，DFS）： #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;stack&gt; using namespace std; void dfs(vector&lt;vector&lt;int&gt;&gt;&amp; graph, int start) { int n = graph.size(); vector&lt;bool&gt; visited(n, false); stack&lt;int&gt; s; s.push(start); visited[start] = true; cout &lt;&lt; "DFS Traversal: "; while (!s.empty()) { int node = s.top(); s.pop(); cout &lt;&lt; node &lt;&lt; " "; for (int neighbor : graph[node]) { if (!visited[neighbor]) { s.push(neighbor); visited[neighbor] = true; } } } cout &lt;&lt; endl; } int main() { vector&lt;vector&lt;int&gt;&gt; graph = { {1, 2}, {0, 3, 4}, {0, 5, 6}, {1}, {1}, {2}, {2} }; int start = 0; dfs(graph, start); return 0; } 深度优先搜索是一种图遍历算法，它沿着图的深度遍历图的节点，尽可能深地搜索图的分支。DFS 使用栈来实现，它从起始节点开始，沿着一条路径一直到达最深的节点，然后回溯，继续搜索下一条分支。 笔记：以上是一些常见的排序和搜索算法的C++实现，它们在实际的编程中具有广泛的应用场景。 BFS 笔记：以下是广度优先搜索（Breadth First Search，BFS）的C++实现示例： #include &lt;iostream&gt; #include &lt;queue&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; using namespace std; void bfs(vector&lt;vector&lt;int&gt;&gt;&amp; graph, int start) { int n = graph.size(); vector&lt;bool&gt; visited(n, false); queue&lt;int&gt; q; q.push(start); visited[start] = true; cout &lt;&lt; "BFS Traversal: "; while (!q.empty()) { int node = q.front(); q.pop(); cout &lt;&lt; node &lt;&lt; " "; for (int neighbor : graph[node]) { if (!visited[neighbor]) { q.push(neighbor); visited[neighbor] = true; } } } cout &lt;&lt; endl; } int main() { vector&lt;vector&lt;int&gt;&gt; graph = { {1, 2}, {0, 3, 4}, {0, 5, 6}, {1}, {1}, {2}, {2} }; int start = 0; bfs(graph, start); return 0; } 广度优先搜索是一种图遍历算法，它从图的某个顶点开始，先访问其所有的相邻节点，然后再依次访问相邻节点的相邻节点，以此类推。BFS使用队列来实现，从起始节点开始，将其加入队列，然后按层级依次访问节点，直到队列为空为止。 笔记：快速幂（Fast Exponentiation）是一种用于计算幂运算的算法，它可以在较短的时间内计算出大整数的幂，时间复杂度为 O(logN)。快速幂算法的基本思想是利用指数的二进制表示来减少乘法的次数。 笔记：以下是快速幂的C++实现示例： #include &lt;iostream&gt; using namespace std; long long fastPower(long long base, long long exponent) { long long result = 1; while (exponent &gt; 0) { if (exponent % 2 == 1) { result *= base; } base *= base; exponent /= 2; } return result; } int main() { long long base = 2; long long exponent = 10; long long result = fastPower(base, exponent); cout &lt;&lt; base &lt;&lt; " raised to the power of " &lt;&lt; exponent &lt;&lt; " is: " &lt;&lt; result &lt;&lt; endl; return 0; } 笔记：在这个示例中，fastPower函数接受两个参数：底数（base）和指数（exponent），并返回底数的指数次幂。在函数内部，我们使用了一个 while 循环来迭代计算结果。在每次迭代中，我们检查指数的最低位（exponent % 2）是否为1，如果是，则将当前的底数乘到结果中。然后，将底数自乘以进行下一次迭代，并将指数除以2以向右移动到下一个二进制位。 笔记：通过这种方式，我们可以在 O(logN) 的时间复杂度内计算出给定底数和指数的幂运算结果。 笔记：矩阵快速幂是快速幂算法的一种扩展，用于高效地计算矩阵的幂。它在计算矩阵的幂时，利用了矩阵乘法的性质，并通过将指数表示为二进制来减少乘法的次数，从而降低了时间复杂度。 笔记：以下是矩阵快速幂的C++实现示例： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; typedef vector&lt;vector&lt;int&gt;&gt; Matrix; Matrix multiply(Matrix &amp;A, Matrix &amp;B) { int n = A.size(); int m = B[0].size(); int p = B.size(); Matrix C(n, vector&lt;int&gt;(m, 0)); for (int i = 0; i &lt; n; ++i) { // for (int j = 0; j &lt; m; ++j) {// for (int k = 0; k &lt; p; ++k) { C[i][j] += A[i][k] * B[k][j]; } } } return C; } Matrix matrixPower(Matrix &amp;A, int exponent) { //A int n = A.size(); Matrix result(n, vector&lt;int&gt;(n, 0)); for (int i = 0; i &lt; n; ++i) {// result[i][i] = 1; // 单位矩阵 } while (exponent &gt; 0) { // if (exponent % 2 == 1) { // result = multiply(result, A); } A = multiply(A, A); // 矩阵平方 exponent /= 2; } return result; } int main() {// Matrix A = {/**/{1, 1}, {1, 0}/**/}; // 斐波那契矩阵 int exponent = 5; // 指数 Matrix result = matrixPower(A, exponent); cout &lt;&lt; "Resulting matrix after raising to the power of " &lt;&lt; exponent &lt;&lt; ":" &lt;&lt; endl; for (int i = 0; i &lt; result.size(); ++i) { for (int j = 0; j &lt; result[0].size(); ++j) { cout &lt;&lt; result[i][j] &lt;&lt; " "; } cout &lt;&lt; endl; } return 0; } 笔记：在这个示例中，我们定义了两个函数，multiply函数用于计算两个矩阵的乘积，matrixPower函数用于计算矩阵的指数次幂。在 matrixPower 函数中，我们首先初始化一个单位矩阵作为结果矩阵，然后利用循环和矩阵乘法进行幂运算的计算。通过这种方式，我们可以高效地计算矩阵的幂运算结果。 笔记：动态规划（Dynamic Programming，DP）是一种通过将复杂问题分解成更小的子问题来解决的优化技术。它通常用于优化递归算法，避免重复计算子问题。 笔记：以下是动态规划的一般步骤： 定义子问题：将原始问题分解为更小的子问题。 找出状态转移方程：确定子问题之间的关系，即如何将更大的问题的解构建为更小问题的解。 确定初始条件：确定最小子问题的解，通常是基本情况的解。 自底向上求解：根据状态转移方程，从最小的子问题开始，依次解决更大的问题，直到达到原始问题的解。 笔记：动态规划常用于解决一些优化问题，如最长公共子序列、背包问题、最短路径问题等。 笔记：下面是一个动态规划的示例，解决了斐波那契数列问题： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; int fibonacci(int n) { if (n &lt;= 1) { return n; } vector&lt;int&gt; dp(n + 1); dp[0] = 0; dp[1] = 1; for (int i = 2; i &lt;= n; ++i) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } int main() { int n = 10; cout &lt;&lt; "Fibonacci number at position " &lt;&lt; n &lt;&lt; " is: " &lt;&lt; fibonacci(n) &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们利用动态规划的思想解决了斐波那契数列问题。我们定义了一个长度为 n+1 的动态规划数组 dp，其中 dp[i] 表示斐波那契数列中第 i 个数的值。然后我们使用迭代的方式，根据状态转移方程 dp[i] = dp[i-1] + dp[i-2] 依次求解 dp 数组的值，最终返回 dp[n] 即可得到斐波那契数列第 n 个数的值。 笔记：贪心算法（Greedy Algorithm）是一种在每一步选择中都采取在当前状态下最好或最优（即局部最优解）的选择，从而希望能够导致全局最优解的算法策略。贪心算法通常不会回溯，因为它一旦做出选择就不会改变。 笔记：贪心算法适用于满足以下两个条件的问题： 最优子结构：问题的最优解包含了子问题的最优解。 贪心选择性质：通过局部最优选择，能够得到全局最优解。 笔记：贪心算法的优点在于简单、高效，容易实现。然而，它并不是所有问题都适用，因为它可能会产生局部最优解但不一定能得到全局最优解。 笔记：以下是一个简单的贪心算法示例，解决了活动选择问题（Activity Selection Problem）： #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; using namespace std; struct Activity { int start; int finish; }; bool compare(Activity a, Activity b) { return a.finish &lt; b.finish; } void selectActivities(vector&lt;Activity&gt;&amp; activities) { sort(activities.begin(), activities.end(), compare); cout &lt;&lt; "Selected activities: "; int n = activities.size(); cout &lt;&lt; "(" &lt;&lt; activities[0].start &lt;&lt; ", " &lt;&lt; activities[0].finish &lt;&lt; ") "; int prev_finish = activities[0].finish; for (int i = 1; i &lt; n; ++i) { if (activities[i].start &gt;= prev_finish) { cout &lt;&lt; "(" &lt;&lt; activities[i].start &lt;&lt; ", " &lt;&lt; activities[i].finish &lt;&lt; ") "; prev_finish = activities[i].finish; } } cout &lt;&lt; endl; } int main() { vector&lt;Activity&gt; activities = {/**/{1, 4}, {3, 5}, {0, 6}, {5, 7}, {3, 9}, {5, 9}, {6, 10}, {8, 11}, {8, 12}, {2, 14}, {12, 16}}; selectActivities(activities); return 0; } 笔记：在这个示例中，我们定义了一个活动结构体，包含了每个活动的开始时间和结束时间。然后我们按照活动的结束时间对活动进行排序，然后从排好序的活动中选择最早结束的活动，并确保选中的活动与已选中的活动不重叠。这样，我们就可以通过贪心算法求解出最大的可选活动数量。 笔记：以下是贪心算法的另一个示例，解决了找零钱问题（Coin Change Problem）： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; vector&lt;int&gt; makeChange(vector&lt;int&gt;&amp; coins, int amount) { vector&lt;int&gt; result; for (int i = coins.size() - 1; i &gt;= 0; --i) { while (amount &gt;= coins[i]) { amount -= coins[i]; result.push_back(coins[i]); } } return result; } int main() { vector&lt;int&gt; coins = {1, 5, 10, 25}; // 美分硬币面额 int amount = 99; // 找零的金额 vector&lt;int&gt; change = makeChange(coins, amount); cout &lt;&lt; "Change for " &lt;&lt; amount &lt;&lt; " cents: "; for (int coin : change) { cout &lt;&lt; coin &lt;&lt; " "; } cout &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们有一组美分硬币的面额，以及一个需要找零的金额。我们按照硬币面额从大到小的顺序进行贪心选择，每次尽量选择面额最大的硬币。通过循环遍历硬币面额，我们不断地将最大面额的硬币加入找零列表中，直到达到需要找零的金额。最终返回的找零列表即为贪心算法所得到的结果。 笔记：需要注意的是，贪心算法并不一定能够得到最优解，它只能得到局部最优解。在找零钱的问题中，如果硬币面额不是常见的面额组合（如1、5、10、25美分），贪心算法可能无法得到最小数量的硬币找零方案。 笔记：二分答案是一种常用的优化技巧，通常用于解决满足某个条件的最优解问题。它的基本思想是，在一个有序的解空间中，利用二分查找的思想来快速地确定满足条件的解的范围。 笔记：下面是一个简单的示例，演示了如何使用二分答案来解决一个简单的问题： 笔记：假设有一个升序排列的数组 nums，我们要找到数组中第一个大于等于目标值 target 的元素的下标。 #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; int binarySearch(vector&lt;int&gt;&amp; nums, int target) { int left = 0; int right = nums.size() - 1; while (left &lt;= right) { int mid = left + (right - left) / 2; if (nums[mid] &gt;= target) { right = mid - 1; } else { left = mid + 1; } } return left &lt; nums.size() ? left : -1; // 返回找到的元素的下标，如果找不到则返回 -1 } int main() { vector&lt;int&gt; nums = {1, 3, 5, 7, 9}; int target = 6; int index = binarySearch(nums, target); if (index != -1) { cout &lt;&lt; "The index of the first element greater than or equal to " &lt;&lt; target &lt;&lt; " is: " &lt;&lt; index &lt;&lt; endl; } else { cout &lt;&lt; "No such element found." &lt;&lt; endl; } return 0; } 笔记：在这个示例中，我们使用了二分答案的思想。我们首先设定一个有序的解空间，在这个示例中，解空间即为数组 nums 的索引范围。然后我们通过不断地调整左右边界来缩小解空间，最终找到满足条件的最优解。 笔记：二分答案是一种非常高效的优化技巧，在解决一些需要在有序解空间中查找满足条件的最优解的问题时非常有用。 笔记：二分答案的思想还可以应用于更复杂的问题，例如求解满足某种条件的最优解，或者在一个有序的范围内查找满足某种条件的解的位置。 笔记：下面是一个更复杂的示例，演示了如何使用二分答案来解决一个数值范围内的问题： 笔记：假设有一个函数 bool isValid(int x)，可以用来判断一个整数 x 是否满足某种条件。现在要在一个给定的区间 [left, right] 中找到满足条件的最小整数。 #include &lt;iostream&gt; using namespace std; bool isValid(int x) { // 假设这里是一个条件判断函数，用于判断整数 x 是否满足某种条件 return x &gt;= 10; } int binarySearch(int left, int right) { while (left &lt; right) { int mid = left + (right - left) / 2; if (isValid(mid)) { right = mid; } else { left = mid + 1; } } return left; } int main() { int left = 0; int right = 20; int result = binarySearch(left, right); cout &lt;&lt; "The smallest integer that satisfies the condition is: " &lt;&lt; result &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们通过二分答案的思想，在给定的区间 [left, right] 中查找满足条件的最小整数。我们首先设定了一个有序的解空间，然后不断地调整左右边界来缩小解空间，直到找到满足条件的最小整数。 笔记：二分答案的思想可以应用于各种各样的问题，它是一种非常高效且常用的算法优化技巧。 笔记：前缀和（Prefix Sum）是一种常用的技巧，用于高效地计算数组或序列的区间和。它的基本思想是预处理数组，将数组中每个位置的前缀和存储起来，然后利用前缀和的性质来快速计算任意区间的和。 笔记：以下是一个简单的示例，演示了如何使用前缀和来计算数组的区间和： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; vector&lt;int&gt; calculatePrefixSum(vector&lt;int&gt;&amp; nums) { int n = nums.size(); vector&lt;int&gt; prefixSum(n + 1, 0); // 初始化前缀和数组，多出的一个位置用于处理边界情况 for (int i = 0; i &lt; n; ++i) { prefixSum[i + 1] = prefixSum[i] + nums[i]; // 计算前缀和 } return prefixSum; } int rangeSum(vector&lt;int&gt;&amp; prefixSum, int left, int right) { return prefixSum[right + 1] - prefixSum[left]; // 利用前缀和计算区间和 } int main() { vector&lt;int&gt; nums = {1, 2, 3, 4, 5}; vector&lt;int&gt; prefixSum = calculatePrefixSum(nums); int left = 1, right = 3; // 求区间 [1, 3] 的和 int sum = rangeSum(prefixSum, left, right); cout &lt;&lt; "The sum of elements in the range [" &lt;&lt; left &lt;&lt; ", " &lt;&lt; right &lt;&lt; "] is: " &lt;&lt; sum &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们首先计算了数组 nums 的前缀和，然后通过前缀和数组可以快速地计算任意区间的和。利用前缀和的性质，区间 [left, right] 的和等于前缀和数组中右边界 right+1 对应的值减去左边界 left 对应的值。 笔记：前缀和的优势在于在预处理阶段计算了所有可能的区间和，使得在查询阶段可以快速地得到结果，时间复杂度为 O(1)。这使得前缀和成为了解决涉及区间和的问题时一个非常高效的技巧。 笔记：除了用于计算数组的区间和，前缀和还可以应用于解决其他类型的问题，比如查找数组中的连续子数组，使得子数组的和满足特定条件。 笔记：以下是一个示例，演示了如何使用前缀和来解决一个查找数组中满足特定条件的连续子数组的问题： 笔记：假设给定一个整数数组 nums，我们要找到一个连续的子数组，使得子数组的和等于目标值 target。 #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;unordered_map&gt; using namespace std; int subarraySum(vector&lt;int&gt;&amp; nums, int target) { int count = 0; int sum = 0; unordered_map&lt;int, int&gt; prefixSumCount; // 前缀和及其出现次数的哈希表 prefixSumCount[0] = 1; // 初始化前缀和为0的出现次数为1 for (int num : nums) { sum += num; if (prefixSumCount.find(sum - target) != prefixSumCount.end()) { count += prefixSumCount[sum - target]; // 如果存在前缀和为 sum - target 的子数组，则增加计数 } prefixSumCount[sum]++; // 更新前缀和出现次数 } return count; } int main() { vector&lt;int&gt; nums = {1, 1, 1}; int target = 2; int count = subarraySum(nums, target); cout &lt;&lt; "Number of subarrays with sum equal to " &lt;&lt; target &lt;&lt; " is: " &lt;&lt; count &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们使用了一个哈希表 prefixSumCount 来存储前缀和及其出现次数。我们从左到右遍历数组 nums，在遍历的过程中，计算当前位置的前缀和，并检查是否存在前缀和为 sum - target 的子数组。如果存在，则增加计数器。 笔记：利用前缀和的思想，我们可以在线性时间内解决这个问题，而不需要通过枚举所有可能的子数组来寻找满足条件的解。这种方法在解决数组和子数组相关的问题时非常高效。 笔记：容斥原理（Inclusion-Exclusion Principle）是组合数学中的一种重要原理，用于计算多个集合的并集、交集和补集等操作的元素个数。它是一种通过排除重复计数来计算所需结果的方法。 笔记：容斥原理的基本形式是：如果有若干个集合，要求它们的并集中的元素个数，可以通过依次加上每个集合的元素个数，然后减去每两个集合的交集的元素个数，再加上每三个集合的交集的元素个数，依次类推，直到最后加上或减去所有集合的交集的元素个数。 笔记：以下是一个简单的示例，演示了如何使用容斥原理计算多个集合的并集中的元素个数： 笔记：假设有三个集合 A、B、C，我们要求它们的并集中的元素个数。 #include &lt;iostream&gt; #include &lt;set&gt; using namespace std; int inclusionExclusion(set&lt;int&gt;&amp; A, set&lt;int&gt;&amp; B, set&lt;int&gt;&amp; C) { int totalElements = A.size() + B.size() + C.size(); int intersectionAB = 0, intersectionAC = 0, intersectionBC = 0, intersectionABC = 0; for (int x : A) { if (B.count(x) &gt; 0) intersectionAB++; if (C.count(x) &gt; 0) intersectionAC++; if (B.count(x) &gt; 0 &amp;&amp; C.count(x) &gt; 0) intersectionABC++; } for (int x : B) { if (C.count(x) &gt; 0) intersectionBC++; } int result = totalElements - intersectionAB - intersectionAC - intersectionBC + intersectionABC; return result; } int main() { set&lt;int&gt; A = {1, 2, 3}; set&lt;int&gt; B = {3, 4, 5}; set&lt;int&gt; C = {5, 6, 7}; int count = inclusionExclusion(A, B, C); cout &lt;&lt; "Number of elements in the union of sets A, B, C is: " &lt;&lt; count &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们首先计算了三个集合的元素个数，并分别计算了它们之间的交集元素个数。然后根据容斥原理的公式，依次减去交集的元素个数，再加上交集的交集的元素个数，得到最终的结果。 笔记：二维前缀和是一种用于高效计算二维数组区域和的技巧。它类似于一维前缀和，通过预处理的方式，将原始二维数组转换为一个对应的二维前缀和数组，以便快速计算任意二维区域的和。 笔记：以下是一个简单的示例，演示了如何使用二维前缀和来计算二维数组区域和： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; vector&lt;vector&lt;int&gt;&gt; calculatePrefixSum(vector&lt;vector&lt;int&gt;&gt;&amp; matrix) { int m = matrix.size(); int n = matrix[0].size(); vector&lt;vector&lt;int&gt;&gt; prefixSum(m + 1, vector&lt;int&gt;(n + 1, 0)); for (int i = 1; i &lt;= m; ++i) { for (int j = 1; j &lt;= n; ++j) { prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1] + matrix[i - 1][j - 1]; } } return prefixSum; } int rangeSum(vector&lt;vector&lt;int&gt;&gt;&amp; prefixSum, int row1, int col1, int row2, int col2) { return prefixSum[row2 + 1][col2 + 1] - prefixSum[row1][col2 + 1] - prefixSum[row2 + 1][col1] + prefixSum[row1][col1]; } int main() { vector&lt;vector&lt;int&gt;&gt; matrix = {/**/{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; vector&lt;vector&lt;int&gt;&gt; prefixSum = calculatePrefixSum(matrix); int row1 = 1, col1 = 1, row2 = 2, col2 = 2; // 计算二维区域和的左上角和右下角坐标 int sum = rangeSum(prefixSum, row1, col1, row2, col2); cout &lt;&lt; "Sum of elements in the range [" &lt;&lt; row1 &lt;&lt; ", " &lt;&lt; col1 &lt;&lt; "] to [" &lt;&lt; row2 &lt;&lt; ", " &lt;&lt; col2 &lt;&lt; "] is: " &lt;&lt; sum &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们首先计算了二维数组的前缀和数组。然后，通过利用前缀和数组的性质，可以在常量时间内计算任意二维区域的和，这种方法的时间复杂度为 O(1)。 笔记：高精度（High Precision）计算是指对于超出常规数据类型表示范围的数字进行精确计算。在计算机科学中，常见的数据类型（如int、float、double）有其表示范围和精度限制，无法精确表示超出其范围的大整数或小数。 笔记：在处理需要高精度计算的问题时，一种常见的方法是使用字符串来表示数字，然后模拟手工计算的方式进行运算。这种方法可以有效地处理大整数或精确小数，但通常会牺牲计算速度。 笔记：以下是一个简单的示例，演示了如何使用字符串来实现高精度加法： #include &lt;iostream&gt; #include &lt;string&gt; using namespace std; string addStrings(string num1, string num2) { string result = ""; int carry = 0; int i = num1.size() - 1; int j = num2.size() - 1; while (i &gt;= 0 || j &gt;= 0 || carry &gt; 0) { int digit1 = i &gt;= 0 ? num1[i] - '0' : 0; int digit2 = j &gt;= 0 ? num2[j] - '0' : 0; int sum = digit1 + digit2 + carry; result = to_string(sum % 10) + result; carry = sum / 10; i--; j--; } return result; } int main() { string num1 = "123456789"; string num2 = "987654321"; string sum = addStrings(num1, num2); cout &lt;&lt; "Sum of " &lt;&lt; num1 &lt;&lt; " and " &lt;&lt; num2 &lt;&lt; " is: " &lt;&lt; sum &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们通过模拟手工加法的方式，从字符串的最后一位（个位）开始，依次相加，同时考虑进位。最终得到两个大整数的和。 笔记：对于高精度计算，除了加法，还可以实现减法、乘法、除法等运算，以及其他复杂的数学运算。这种方法虽然可能比较慢，但可以保证计算的精确性，适用于需要精确计算的场景。 笔记：模拟是一种常用的算法技巧，通常用于模拟实际问题的解决过程。它的基本思想是通过编写代码模拟实际问题的操作步骤，逐步推进问题的解决。 笔记：模拟常常用于解决一些具体的问题，比如游戏、仿真、物理系统等。在算法竞赛中，模拟也是常见的题型之一，题目可能涉及到模拟人物移动、模拟交通流量、模拟系统状态变化等。 笔记：以下是一个简单的示例，演示了如何使用模拟技巧解决一个问题： 笔记：假设有一个游戏中的小人，初始位置在原点 (0, 0)，根据输入的指令（方向和步数），移动小人的位置，并输出最终位置。 #include &lt;iostream&gt; #include &lt;string&gt; using namespace std; void movePerson(int&amp; x, int&amp; y, char direction, int steps) { if (direction == 'U') { y += steps; } else if (direction == 'D') { y -= steps; } else if (direction == 'L') { x -= steps; } else if (direction == 'R') { x += steps; } } int main() { string instructions = "UDLR"; // 指令串，U表示向上移动，D表示向下移动，L表示向左移动，R表示向右移动 int x = 0, y = 0; // 初始位置 int steps = 1; // 每次移动的步数 for (char direction : instructions) { movePerson(x, y, direction, steps); } cout &lt;&lt; "Final position of the person: (" &lt;&lt; x &lt;&lt; ", " &lt;&lt; y &lt;&lt; ")" &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们定义了一个模拟移动小人的函数 movePerson()，根据输入的指令来移动小人的位置。然后我们通过遍历输入的指令串，依次执行移动操作，最终得到小人的最终位置。 笔记：模拟是一种非常灵活的算法技巧，可以根据具体问题的特点来编写相应的模拟代码。通过模拟，我们可以更好地理解问题的本质，并且能够解决一些复杂的实际问题。 笔记：并查集（Disjoint Set Union，DSU），又称为不相交集合数据结构，是一种用于处理集合合并与查询的数据结构。它主要用于解决集合的合并、查询等问题，常被应用于图论、网络连接问题、最小生成树算法（如Kruskal算法）等领域。 笔记：并查集的基本操作包括： MakeSet(x)：创建一个新的集合，其中包含元素x。 Find(x)：查找元素x所在的集合（根结点）。 Union(x, y)：将包含元素x和元素y的两个集合合并为一个集合。 笔记：以下是一个简单的并查集的实现示例： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; class DisjointSet { private: vector&lt;int&gt; parent; public: DisjointSet(int n) { parent.resize(n); for (int i = 0; i &lt; n; ++i) { parent[i] = i; // 初始时每个元素都是独立的集合，其父结点为自身 } } int Find(int x) { if (parent[x] != x) { parent[x] = Find(parent[x]); // 路径压缩，将x的父结点设为根结点 } return parent[x]; } void Union(int x, int y) { int rootX = Find(x); int rootY = Find(y); if (rootX != rootY) { parent[rootY] = rootX; // 将y的根结点指向x的根结点，完成合并操作 } } }; int main() { int n = 5; DisjointSet dsu(n); dsu.Union(0, 1); dsu.Union(2, 3); dsu.Union(0, 4); cout &lt;&lt; "Find(1): " &lt;&lt; dsu.Find(1) &lt;&lt; endl; cout &lt;&lt; "Find(3): " &lt;&lt; dsu.Find(3) &lt;&lt; endl; cout &lt;&lt; "Find(4): " &lt;&lt; dsu.Find(4) &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们首先创建了一个大小为n的并查集，然后通过Union操作将不同的元素合并到同一个集合中，并通过Find操作查找元素所在的集合（根结点）。 笔记：并查集的优化还有路径压缩、按秩合并等，可以进一步提高效率，特别是在大规模应用中。 笔记：在并查集的基本实现之上，有几种优化策略可以进一步提高效率： 路径压缩（Path Compression）：在Find操作中，将节点的父节点设置为根节点，以减少下次查找的时间。这样，路径上的所有节点都直接连接到根节点，减少了树的高度。 按秩合并（Union by Rank）：在Union操作中，将具有较小秩的树的根节点连接到具有较大秩的树的根节点上。秩可以理解为树的高度的上界，树的高度越低，操作效率越高。 笔记：下面是一个并查集的优化实现示例，结合了路径压缩和按秩合并： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; class DisjointSet { private: vector&lt;int&gt; parent; vector&lt;int&gt; rank; public: DisjointSet(int n) { parent.resize(n); rank.resize(n, 0); for (int i = 0; i &lt; n; ++i) { parent[i] = i; // 初始时每个元素都是独立的集合，其父结点为自身 } } int Find(int x) { if (parent[x] != x) { parent[x] = Find(parent[x]); // 路径压缩，将x的父结点设为根结点 } return parent[x]; } void Union(int x, int y) { int rootX = Find(x); int rootY = Find(y); if (rootX != rootY) { if (rank[rootX] &lt; rank[rootY]) { parent[rootX] = rootY; // 将x的根结点连接到y的根结点上 } else if (rank[rootX] &gt; rank[rootY]) { parent[rootY] = rootX; // 将y的根结点连接到x的根结点上 } else { parent[rootY] = rootX; rank[rootX]++; // 如果秩相同，则任意选择一个作为根结点，并增加秩 } } } }; int main() { int n = 5; DisjointSet dsu(n); dsu.Union(0, 1); dsu.Union(2, 3); dsu.Union(0, 4); cout &lt;&lt; "Find(1): " &lt;&lt; dsu.Find(1) &lt;&lt; endl; cout &lt;&lt; "Find(3): " &lt;&lt; dsu.Find(3) &lt;&lt; endl; cout &lt;&lt; "Find(4): " &lt;&lt; dsu.Find(4) &lt;&lt; endl; return 0; } 笔记：这个示例中的并查集实现结合了路径压缩和按秩合并两种优化策略，可以在保持算法正确性的同时提高效率，特别是在大规模应用中。 笔记：在并查集的基本实现和优化之上，还可以应用一些高级技巧来解决特定类型的问题，例如路径压缩优化的启发式合并（Path Compression with Heuristic Union）。 笔记：启发式合并是一种在进行Union操作时，根据某种启发式规则决定将哪个集合合并到另一个集合中的策略。这种策略可以根据具体的应用场景来选择，以最大程度地提高并查集的效率。 笔记：以下是一个简单的示例，演示了如何在并查集中应用路径压缩优化的启发式合并策略： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; class DisjointSet { private: vector&lt;int&gt; parent; vector&lt;int&gt; rank; public: DisjointSet(int n) { parent.resize(n); rank.resize(n, 0); for (int i = 0; i &lt; n; ++i) { parent[i] = i; // 初始时每个元素都是独立的集合，其父结点为自身 } } int Find(int x) { if (parent[x] != x) { parent[x] = Find(parent[x]); // 路径压缩，将x的父结点设为根结点 } return parent[x]; } void Union(int x, int y) { int rootX = Find(x); int rootY = Find(y); if (rootX != rootY) { if (rank[rootX] &lt; rank[rootY]) { parent[rootX] = rootY; // 将x的根结点连接到y的根结点上 } else { parent[rootY] = rootX; // 将y的根结点连接到x的根结点上 if (rank[rootX] == rank[rootY]) { rank[rootX]++; // 如果秩相同，则任意选择一个作为根结点，并增加秩 } } } } }; int main() { int n = 5; DisjointSet dsu(n); dsu.Union(0, 1); dsu.Union(2, 3); dsu.Union(0, 4); cout &lt;&lt; "Find(1): " &lt;&lt; dsu.Find(1) &lt;&lt; endl; cout &lt;&lt; "Find(3): " &lt;&lt; dsu.Find(3) &lt;&lt; endl; cout &lt;&lt; "Find(4): " &lt;&lt; dsu.Find(4) &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们在进行Union操作时，根据两个集合的秩（rank）来决定哪个集合合并到另一个集合中。这种启发式策略可以有效地保持并查集的平衡性，从而提高整体效率。 笔记：通过合理选择并实现合适的启发式策略，可以使并查集在解决各种实际问题时更加高效。 笔记：在继续讨论并查集的应用之前，我们可以进一步探讨一些常见的应用场景和问题，这些问题可以通过并查集高效地解决。 笔记：一些常见的并查集应用包括： 连通性问题：并查集最常见的应用之一是解决连通性问题，比如判断图中的节点是否连通，或者在网络中查找是否存在通路。通过将具有相同根节点的节点视为同一个集合，可以快速判断两个节点是否连通。 最小生成树算法（Minimum Spanning Tree，MST）：Kruskal算法是一种基于并查集的最小生成树算法，它通过对边进行排序，然后依次添加边到最小生成树中，同时保证不形成环路，直到所有节点都连接在一起。 区域合并问题：在二维网格中，区域合并问题涉及将相邻的相同区域合并在一起。这可以通过并查集来实现，每个单元格对应一个节点，通过合并相邻的单元格来合并区域。 社交网络中的关系处理：在社交网络中，可以使用并查集来处理关系，比如判断两个人是否属于同一个朋友圈、组织或团体。 图的连通性问题：在图论中，可以使用并查集来判断图的连通性，或者判断是否存在环路等。 笔记：这些是并查集的一些常见应用场景，它在解决这些问题时能够提供高效的算法和数据结构支持。在实际应用中，我们可以根据具体问题的特点，灵活运用并查集算法来解决各种连通性和合并性问题。 笔记：带权并查集（Weighted Union-Find Disjoint Set）是对普通的并查集进行了扩展，使其支持在合并操作时维护集合的权值或秩信息。这种扩展使得在某些应用场景下能更加灵活地处理问题，特别是涉及到集合合并时需要考虑权值或秩的情况。 笔记：在普通的并查集中，每个集合的权值或秩信息通常是相等的，但在带权并查集中，每个节点都可以携带不同的权值或秩信息。 笔记：以下是带权并查集的基本实现示例： #include &lt;iostream&gt; #include &lt;vector&gt; using namespace std; class WeightedUnionFind { private: vector&lt;int&gt; parent; vector&lt;int&gt; rank; vector&lt;int&gt; weight; public: WeightedUnionFind(int n) { parent.resize(n); rank.resize(n, 0); weight.resize(n, 0); for (int i = 0; i &lt; n; ++i) { parent[i] = i; // 初始时每个元素都是独立的集合，其父结点为自身 } } int Find(int x) { if (parent[x] != x) { int root = Find(parent[x]); weight[x] += weight[parent[x]]; // 路径压缩，累加权值信息 parent[x] = root; } return parent[x]; } void Union(int x, int y, int w) { int rootX = Find(x); int rootY = Find(y); if (rootX != rootY) { if (rank[rootX] &lt; rank[rootY]) { parent[rootX] = rootY; weight[rootX] = w - weight[x] + weight[y]; // 更新权值信息 } else { parent[rootY] = rootX; weight[rootY] = weight[x] - weight[y] + w; // 更新权值信息 if (rank[rootX] == rank[rootY]) { rank[rootX]++; // 如果秩相同，则任意选择一个作为根结点，并增加秩 } } } } bool Same(int x, int y) { return Find(x) == Find(y); } int Diff(int x, int y) { if (!Same(x, y)) { return -1; // 如果不属于同一个集合，返回-1 } return weight[y] - weight[x]; // 返回y的权值减去x的权值 } }; int main() { int n = 5; WeightedUnionFind wuf(n); wuf.Union(0, 1, 2); wuf.Union(1, 2, 3); wuf.Union(3, 4, 5); cout &lt;&lt; "Diff(0, 2): " &lt;&lt; wuf.Diff(0, 2) &lt;&lt; endl; // 5 - 2 = 3 cout &lt;&lt; "Diff(1, 3): " &lt;&lt; wuf.Diff(1, 3) &lt;&lt; endl; // 5 - 2 = 3 return 0; } 笔记：在带权并查集中，除了维护每个节点的父节点和秩信息外，还需要维护每个节点的权值信息。在合并操作时，需要根据节点的权值信息来更新合并后集合的权值信息。同时，在Find操作中，需要更新路径上每个节点的权值信息，以保证正确的权值计算。通过带权并查集，我们可以更灵活地处理一些具有权值信息的合并问题。 笔记：带权并查集主要用于处理一些需要考虑权值信息的合并和查询问题，常见的应用场景包括： 最小生成树算法（Minimum Spanning Tree，MST）：在Kruskal算法中，需要判断加入一条边后是否会形成环路，并且在形成最小生成树时，要选择权值最小的边。带权并查集可以用于判断两个节点是否在同一个连通分量中，并且可以快速获取连通分量中的最小权值。 网络连接问题：在网络连接问题中，节点表示网络设备或者计算机，边表示网络连接。带权并查集可以用来判断两个节点是否在同一个网络中，同时可以用来查找网络中的最小权值连接。 区域合并问题：在二维网格中，带权并查集可以用来合并相邻的相同区域，并且可以根据合并后的区域的权值信息来进行判断和处理。 优先级合并问题：在一些优先级合并的场景中，带权并查集可以用来维护节点之间的优先级关系，同时可以根据节点的权值信息进行合适的合并操作。 社交网络中的关系处理：在社交网络中，可以使用带权并查集来处理关系，比如判断两个人是否属于同一个朋友圈、组织或团体，并且可以根据节点的权值信息来进行合适的处理和操作。 笔记：这些应用场景是带权并查集在实际问题中的一些常见应用，它能够帮助我们高效地处理具有权值信息的合并和查询问题，并且可以应用于各种领域的算法和数据结构中。 最小生成树 笔记：最小生成树（Minimum Spanning Tree，MST）是一个无向图的生成树，它包含图中的所有顶点，并且具有最小总权值的所有边。最小生成树在许多应用中都有重要的作用，比如网络设计、电力传输、通信网络等领域。 笔记：最小生成树算法有多种实现方式，其中最常见的算法包括： Kruskal算法：Kruskal算法是一种贪心算法，它通过不断地选择具有最小权值的边，且不会形成环路，从而构建最小生成树。Kruskal算法通常基于并查集数据结构实现，用于判断边的两个顶点是否在同一个连通分量中。 Prim算法：Prim算法是一种基于顶点的贪心算法，它从一个初始顶点开始，逐步添加新的顶点，直到生成最小生成树。Prim算法通常基于优先队列（最小堆）实现，用于选择具有最小权值的边。 笔记：下面是Kruskal算法的基本实现示例： #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; using namespace std; struct Edge { int u, v, weight; Edge(int _u, int _v, int _weight) : u(_u), v(_v), weight(_weight) {} }; class DisjointSet { private: vector&lt;int&gt; parent; vector&lt;int&gt; rank; public: DisjointSet(int n) { parent.resize(n); rank.resize(n, 0); for (int i = 0; i &lt; n; ++i) { parent[i] = i; // 初始时每个元素都是独立的集合，其父结点为自身 } } int Find(int x) { if (parent[x] != x) { parent[x] = Find(parent[x]); // 路径压缩，将x的父结点设为根结点 } return parent[x]; } void Union(int x, int y) { int rootX = Find(x); int rootY = Find(y); if (rootX != rootY) { if (rank[rootX] &lt; rank[rootY]) { parent[rootX] = rootY; // 将x的根结点连接到y的根结点上 } else { parent[rootY] = rootX; // 将y的根结点连接到x的根结点上 if (rank[rootX] == rank[rootY]) { rank[rootX]++; // 如果秩相同，则任意选择一个作为根结点，并增加秩 } } } } }; int kruskalMST(vector&lt;Edge&gt;&amp; edges, int n) { sort(edges.begin(), edges.end(), [](const Edge&amp; a, const Edge&amp; b) { return a.weight &lt; b.weight; // 按边的权值升序排序 }); DisjointSet dsu(n); int minCost = 0; for (const Edge&amp; edge : edges) { if (dsu.Find(edge.u) != dsu.Find(edge.v)) { dsu.Union(edge.u, edge.v); minCost += edge.weight; } } return minCost; } int main() { int n = 4; vector&lt;Edge&gt; edges = {/**/{0, 1, 10}, {0, 2, 6}, {0, 3, 5}, {1, 3, 15}, {2, 3, 4}}; int minCost = kruskalMST(edges, n); cout &lt;&lt; "Minimum Cost of Spanning Tree: " &lt;&lt; minCost &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们使用Kruskal算法来计算图的最小生成树的总权值。首先将边按照权值升序排序，然后依次选择边，如果边的两个顶点不在同一个连通分量中，就将它们合并，并将边的权值加到总权值中。最终得到的总权值即为最小生成树的总权值。 笔记：Prim算法是另一种常用的最小生成树算法，它基于顶点的贪心策略，在构建最小生成树的过程中，每次选择与当前树连接的顶点中权值最小的边，将其加入最小生成树的集合中。Prim算法通常使用优先队列（最小堆）来选择下一个顶点，以保证每次选择的边权值最小。 笔记：以下是Prim算法的基本实现示例： #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;queue&gt; #include &lt;climits&gt; using namespace std; struct Edge { int to; int weight; Edge(int _to, int _weight) : to(_to), weight(_weight) {} }; class Graph { private: int V; // 顶点数 vector&lt;vector&lt;Edge&gt;&gt; adj; // 邻接表表示的图 public: Graph(int V) : V(V) { adj.resize(V); } void addEdge(int u, int v, int weight) { adj[u].push_back(Edge(v, weight)); adj[v].push_back(Edge(u, weight)); // 无向图，双向连接 } int primMST() { vector&lt;int&gt; key(V, INT_MAX); // 存储顶点到最小生成树的最小权值 vector&lt;bool&gt; inMST(V, false); // 记录顶点是否已经加入最小生成树 int minCost = 0; // 最小生成树的总权值 // 创建一个优先队列，按边的权值进行排序 priority_queue&lt;pair&lt;int, int&gt;, vector&lt;pair&lt;int, int&gt;&gt;, greater&lt;pair&lt;int, int&gt;&gt;&gt; pq; // 选择任意一个顶点作为起始点 int src = 0; key[src] = 0; // 将起始点的权值设为0 pq.push(make_pair(0, src)); while (!pq.empty()) { int u = pq.top().second; // 选择当前最小权值的顶点 pq.pop(); if (inMST[u]) continue; // 如果顶点已经在最小生成树中，跳过 inMST[u] = true; // 将顶点加入最小生成树 // 遍历与当前顶点相邻的边 for (const Edge&amp; edge : adj[u]) { int v = edge.to; int weight = edge.weight; if (!inMST[v] &amp;&amp; weight &lt; key[v]) { key[v] = weight; // 更新顶点到最小生成树的最小权值 pq.push(make_pair(key[v], v)); // 将顶点加入优先队列中 } } } // 计算最小生成树的总权值 for (int i = 0; i &lt; V; ++i) { minCost += key[i]; } return minCost; } }; int main() { int V = 5; Graph graph(V); // 添加图的边 graph.addEdge(0, 1, 2); graph.addEdge(0, 3, 6); graph.addEdge(1, 2, 3); graph.addEdge(1, 3, 8); graph.addEdge(1, 4, 5); graph.addEdge(2, 4, 7); graph.addEdge(3, 4, 9); // 计算最小生成树的总权值 int minCost = graph.primMST(); cout &lt;&lt; "Minimum Cost of Spanning Tree: " &lt;&lt; minCost &lt;&lt; endl; return 0; } 笔记：在Prim算法的实现中，我们使用了优先队列来存储待选的边，并通过不断地选择权值最小的边来构建最小生成树。该算法的时间复杂度为 O(ElogV)，其中 E 是边的数量，V 是顶点的数量。 STL 笔记：STL（Standard Template Library）是C++标准库的一部分，提供了许多常用的数据结构和算法实现。STL包括多个组件，其中一些主要的组件有： 容器（Containers）：STL提供了多种容器，包括向量（vector）、列表（list）、双端队列（deque）、集合（set）、映射（map）等。这些容器提供了不同的数据组织方式，以满足不同的需求。 迭代器（Iterators）：迭代器是STL中用于遍历容器元素的抽象概念，它提供了统一的访问容器元素的接口。STL中的算法通常接受迭代器作为参数，以便对容器中的元素进行操作。 算法（Algorithms）：STL提供了大量的算法，涵盖了排序、搜索、复制、删除、变换等各种常见操作。这些算法通常定义在头文件中，可以直接使用。 函数对象（Function Objects）：STL中的函数对象是一种可调用对象，它可以像函数一样被调用，但可以保持状态。函数对象在STL中被广泛用于算法的参数。 适配器（Adapters）：STL提供了一些适配器，用于将一个容器或迭代器接口转换成另一个容器或迭代器接口。常见的适配器包括堆栈（stack）、队列（queue）、优先队列（priority_queue）等。 笔记：下面是一个简单的示例，演示了STL中向量容器、迭代器和算法的使用： #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; using namespace std; int main() { // 创建一个向量容器并初始化 vector&lt;int&gt; vec = {4, 2, 6, 1, 8, 3}; // 使用迭代器遍历并输出向量中的元素 cout &lt;&lt; "Original vector: "; for (auto it = vec.begin(); it != vec.end(); ++it) { cout &lt;&lt; *it &lt;&lt; " "; } cout &lt;&lt; endl; // 使用STL中的算法对向量进行排序 sort(vec.begin(), vec.end()); // 使用迭代器遍历并输出排序后的向量 cout &lt;&lt; "Sorted vector: "; for (auto it = vec.begin(); it != vec.end(); ++it) { cout &lt;&lt; *it &lt;&lt; " "; } cout &lt;&lt; endl; // 使用STL中的算法查找向量中是否存在元素值为6的元素 auto it = find(vec.begin(), vec.end(), 6); if (it != vec.end()) { cout &lt;&lt; "Element 6 found at position: " &lt;&lt; distance(vec.begin(), it) &lt;&lt; endl; } else { cout &lt;&lt; "Element 6 not found in vector." &lt;&lt; endl; } return 0; } 笔记：这个示例演示了如何使用STL中的向量容器、迭代器和算法。通过STL提供的丰富工具，我们可以更加方便地处理数据结构和算法问题，提高代码的效率和可读性。 vector 笔记：std::vector 是 C++ 标准库中最常用的动态数组容器。它提供了动态大小的数组功能，可以在运行时根据需要动态增加或减少元素的个数。以下是关于 std::vector 的一些重要特性和用法： 特性： 动态大小： std::vector 可以动态增长或缩小，根据需要自动调整内部存储空间。 随机访问： 可以通过索引直接访问 std::vector 中的元素，时间复杂度为 O(1)。 连续存储： std::vector 中的元素在内存中是连续存储的，这使得访问元素的速度更快。 自动管理内存： std::vector 自动处理内存的分配和释放，使得使用更加方便。 用法示例： #include &lt;iostream&gt; #include &lt;vector&gt; int main() { // 创建一个空的 vector std::vector&lt;int&gt; vec; // 添加元素到 vector vec.push_back(1); vec.push_back(2); vec.push_back(3); // 使用迭代器遍历 vector std::cout &lt;&lt; "Vector elements: "; for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout &lt;&lt; *it &lt;&lt; " "; } std::cout &lt;&lt; std::endl; // 访问 vector 中的元素 std::cout &lt;&lt; "First element: " &lt;&lt; vec[0] &lt;&lt; std::endl; std::cout &lt;&lt; "Second element: " &lt;&lt; vec.at(1) &lt;&lt; std::endl; // 修改 vector 中的元素 vec[0] = 4; // 删除 vector 中的元素 vec.pop_back(); // 获取 vector 的大小和容量 std::cout &lt;&lt; "Size of vector: " &lt;&lt; vec.size() &lt;&lt; std::endl; std::cout &lt;&lt; "Capacity of vector: " &lt;&lt; vec.capacity() &lt;&lt; std::endl; // 清空 vector vec.clear(); // 检查 vector 是否为空 if (vec.empty()) { std::cout &lt;&lt; "Vector is empty" &lt;&lt; std::endl; } return 0; } 笔记：在这个示例中，我们演示了如何使用 std::vector 创建动态数组，添加、访问、修改和删除元素，以及获取其大小、容量，并清空向量。std::vector 提供了简单而强大的动态数组功能，在许多场景下都是首选的容器类型。 背包问题 笔记：背包问题是一个经典的组合优化问题，在计算机科学和组合数学中都有重要的应用。背包问题通常包括一个背包容量限制以及一组物品，每个物品都有自己的重量和价值。目标是在不超过背包容量的情况下，选择合适的物品放入背包，使得背包中物品的总价值最大。 笔记：背包问题通常分为两种类型： 0-1背包问题（0-1 Knapsack Problem）： 每个物品要么全部装入背包，要么不装入，不能选择部分装入物品。这意味着每种物品只有两种状态：选中或不选中。 分数背包问题（Fractional Knapsack Problem）： 每个物品可以被分割成更小的部分放入背包，所以可以选择部分装入物品。这样，每种物品就有更多的状态，可以是部分选中。 笔记：以下是两种背包问题的基本介绍和解决方法： 0-1背包问题： 解决方法： 动态规划（Dynamic Programming）： 使用动态规划算法可以有效地解决0-1背包问题。定义一个二维数组 dp[i][j]，表示在前 i 个物品中，背包容量为 j 时可以获得的最大价值。然后根据递推关系进行状态转移，最终得到 dp[n][W] 就是所求的最大价值，其中 n 表示物品数量，W 表示背包容量。 回溯法（Backtracking）： 可以使用回溯法穷举所有可能的选择方案，然后选择价值最大的方案作为最优解。但是由于背包问题的指数级复杂度，回溯法不适合处理大规模的背包问题。 分数背包问题： 解决方法： 贪心算法（Greedy Algorithm）： 对于分数背包问题，贪心算法是一个常用的解决方法。贪心算法根据每种物品的单位重量价值来进行选择，优先选择单位重量价值最高的物品放入背包。这种方法可以得到一个近似最优解，但不一定能够保证获得最优解。 笔记：背包问题是一个经典的组合优化问题，对于0-1背包问题，动态规划是最常用的解决方法，而对于分数背包问题，贪心算法通常是一个简单而有效的解决方案。 笔记：在继续讨论背包问题之前，我们可以详细了解一下0-1背包问题和分数背包问题的解决方法，以及它们的特点和应用场景。 0-1背包问题（0-1 Knapsack Problem）： 特点： 每种物品只有两种状态：选中或不选中。 物品不可分割，要么全部装入背包，要么不装入。 解决方法： 动态规划（Dynamic Programming）： 使用动态规划算法来解决0-1背包问题，通常需要构建一个二维数组 dp[i][j]，表示在前 i 个物品中，背包容量为 j 时可以获得的最大价值。然后根据递推关系进行状态转移，最终得到 dp[n][W] 就是所求的最大价值，其中 n 表示物品数量，W 表示背包容量。 分数背包问题（Fractional Knapsack Problem）： 特点： 每种物品可以被分割成更小的部分放入背包。 物品可以选择部分装入背包。 解决方法： 贪心算法（Greedy Algorithm）： 对于分数背包问题，贪心算法是一个常用的解决方法。贪心算法根据每种物品的单位重量价值来进行选择，优先选择单位重量价值最高的物品放入背包。这种方法可以得到一个近似最优解，但不一定能够保证获得最优解。 应用场景： 背包问题在资源分配和优化领域有着广泛的应用，比如货物装载、资源分配、投资组合优化等。 0-1背包问题常见于资源有限、决策离散的场景，如物品装载、任务调度等。 分数背包问题常见于资源可以分割、决策连续的场景，如化工原料混合、机器加工等。 笔记：以上是关于背包问题的一些基本概念、解决方法和应用场景。在实际问题中，根据具体的情况和要求，选择合适的背包问题类型和解决方法来解决问题是非常重要的。 笔记：多重背包问题是背包问题的一个变种，与0-1背包问题和分数背包问题不同，多重背包问题中每种物品都有限定的数量可供选择，即每种物品都有多个相同的物品可供放入背包。与普通的背包问题相比，多重背包问题增加了对物品数量的限制，这使得问题更加复杂。 解决方法： 二进制拆分法： 将多重背包问题转化为0-1背包问题。对于每种物品，根据其数量进行二进制拆分，将每种物品拆分成若干个数量为 1 的物品和数量为 2 的物品，然后使用0-1背包问题的动态规划算法进行求解。 多重背包问题优化： 在动态规划算法中，可以对多重背包问题进行优化。对于数量较大的物品，可以考虑采用优化策略，比如分组思想、二进制优化等方法，以减少时间和空间复杂度。 应用场景： 多重背包问题常见于需要考虑资源数量限制的场景，如货物运输、物资调配等。 在实际问题中，有些物品可能存在多个相同的副本，需要根据具体的资源分配情况进行合理的选择和分配。 笔记：下面是一个简单的示例，演示了如何使用动态规划算法解决多重背包问题： #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; using namespace std; int multipleKnapsack(int N, int W, vector&lt;int&gt;&amp; weight, vector&lt;int&gt;&amp; value, vector&lt;int&gt;&amp; quantity) { vector&lt;int&gt; dp(W + 1, 0); for (int i = 0; i &lt; N; ++i) { for (int j = W; j &gt;= weight[i]; --j) { for (int k = 1; k &lt;= quantity[i] &amp;&amp; k * weight[i] &lt;= j; ++k) { dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]); } } } return dp[W]; } int main() { int N = 3; // 物品种类数 int W = 10; // 背包容量 vector&lt;int&gt; weight = {3, 4, 5}; // 每种物品的重量 vector&lt;int&gt; value = {4, 5, 6}; // 每种物品的价值 vector&lt;int&gt; quantity = {2, 3, 1}; // 每种物品的数量 int maxValue = multipleKnapsack(N, W, weight, value, quantity); cout &lt;&lt; "Maximum value that can be obtained: " &lt;&lt; maxValue &lt;&lt; endl; return 0; } 笔记：在这个示例中，我们使用动态规划算法解决了一个多重背包问题。通过状态转移方程，我们可以有效地计算出背包容量为W时可以获得的最大价值。 笔记：完全背包问题和混合背包问题是背包问题的两个变种，它们分别考虑了不同的限制条件和特性。 完全背包问题（Unbounded Knapsack Problem）： 笔记：完全背包问题是背包问题的一个变种，与0-1背包问题不同，完全背包问题中每种物品的数量是无限的，即可以选择多次放入同一种物品。因此，完全背包问题通常更加复杂，需要使用不同的解决方法。 解决方法： 动态规划： 使用动态规划算法可以有效地解决完全背包问题。与0-1背包问题类似，定义一个二维数组 dp[i][j]，表示在前 i 个物品中，背包容量为 j 时可以获得的最大价值。然后根据递推关系进行状态转移，最终得到 dp[n][W] 就是所求的最大价值，其中 n 表示物品数量，W 表示背包容量。 混合背包问题（Mixed Knapsack Problem）： 笔记：混合背包问题是背包问题的另一个变种，它将0-1背包问题、完全背包问题和多重背包问题组合在一起，每种物品可以根据情况选择放入背包、不放入背包或者放入有限的数量。混合背包问题考虑了更复杂的资源分配情况，因此需要更灵活的解决方法。 解决方法： 动态规划： 可以将混合背包问题转化为0-1背包问题、完全背包问题和多重背包问题的组合，然后使用动态规划算法进行求解。根据每种物品的限制条件和背包容量，分别求解最优解，并将结果合并得到最终的解决方案。 笔记：混合背包问题的解决方法通常需要根据具体的限制条件和资源分配情况进行灵活的选择和组合。在实际应用中，根据问题的具体要求和限制条件，选择合适的解决方法是非常重要的。]]></summary></entry><entry><title type="html">LaTex渲染的说明和测试</title><link href="https://right202209.github.io/blog/math-test/" rel="alternate" type="text/html" title="LaTex渲染的说明和测试" /><published>2019-07-24T00:00:00+00:00</published><updated>2019-07-24T00:00:00+00:00</updated><id>https://right202209.github.io/blog/math-test</id><content type="html" xml:base="https://right202209.github.io/blog/math-test/"><![CDATA[<p>LaTeX渲染已经在全站头部文件引入，可以直接使用，公式块上下使用<code class="language-plaintext highlighter-rouge">$$</code>标明，内联公式则用<code class="language-plaintext highlighter-rouge">$</code>.</p>

<p>最好不要让公式出现在文章摘要里。</p>

<p>Jekyll的默认文章摘要是第一段，但是我在使用中发现它选取摘要不是很稳定，因此加入了手动摘要分割线，默认为<code class="language-plaintext highlighter-rouge">&lt;!-- more --&gt;</code>，并且加入了首页摘要的字符数限制。</p>

<p>因此有特殊符号、内容的文章，建议将这些内容折叠在摘要以下。例如本文</p>

<!-- more -->

<p>Block math test</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$$
\begin{align*}
y = y(x,t) &amp;= A e^{i\theta} \\
&amp;= A (\cos \theta + i \sin \theta) \\
&amp;= A (\cos(kx - \omega t) + i \sin(kx - \omega t)) \\
&amp;= A\cos(kx - \omega t) + i A\sin(kx - \omega t)  \\
&amp;= A\cos \Big(\frac{2\pi}{\lambda}x - \frac{2\pi v}{\lambda} t \Big) + i A\sin \Big(\frac{2\pi}{\lambda}x - \frac{2\pi v}{\lambda} t \Big)  \\
&amp;= A\cos \frac{2\pi}{\lambda} (x - v t) + i A\sin \frac{2\pi}{\lambda} (x - v t)
\end{align*}
$$

</code></pre></div></div>

\[\begin{align*}
y = y(x,t) &amp;= A e^{i\theta} \\
&amp;= A (\cos \theta + i \sin \theta) \\
&amp;= A (\cos(kx - \omega t) + i \sin(kx - \omega t)) \\
&amp;= A\cos(kx - \omega t) + i A\sin(kx - \omega t)  \\
&amp;= A\cos \Big(\frac{2\pi}{\lambda}x - \frac{2\pi v}{\lambda} t \Big) + i A\sin \Big(\frac{2\pi}{\lambda}x - \frac{2\pi v}{\lambda} t \Big)  \\
&amp;= A\cos \frac{2\pi}{\lambda} (x - v t) + i A\sin \frac{2\pi}{\lambda} (x - v t)
\end{align*}\]

<p>Inline math test <code class="language-plaintext highlighter-rouge">$\lim_{x \to \infty} \exp(-x) = 0$</code>, 
$\lim_{x \to \infty} \exp(-x) = 0$</p>]]></content><author><name></name></author><category term="sample" /><category term="document" /><summary type="html"><![CDATA[LaTeX渲染已经在全站头部文件引入，可以直接使用，公式块上下使用$$标明，内联公式则用$. 最好不要让公式出现在文章摘要里。 Jekyll的默认文章摘要是第一段，但是我在使用中发现它选取摘要不是很稳定，因此加入了手动摘要分割线，默认为`]]></summary></entry><entry><title type="html">LOFFER使用基础教程</title><link href="https://right202209.github.io/blog/document/" rel="alternate" type="text/html" title="LOFFER使用基础教程" /><published>2013-08-02T00:00:00+00:00</published><updated>2013-08-02T00:00:00+00:00</updated><id>https://right202209.github.io/blog/document</id><content type="html" xml:base="https://right202209.github.io/blog/document/"><![CDATA[<p>LOFFER是个可以帮助你get off from LOFTER的软件（我知道这个pun很烂）。</p>

<p>这是一个可以直接发布在GitHub page的Jekyll博客，你不需要编写代码或使用命令行即可配置属于你的LOFFER。</p>

<p>本文为针对完全没有代码基础的朋友的基础教程。</p>

<h2 id="注意">注意</h2>

<p>LOFFER是一个<strong>博客模板</strong>。</p>

<p>虽然意图有针对lofter用户，但是我个人狠不赞同纯外链停车操作，你整整齐齐打理个自由自在没有敏感词的个人博客有啥不好。</p>

<p><strong>不要用我的Discus账户，请配置你自己的，本文档中有教程</strong></p>

<p>如有疑问，请阅读<a href="https://pages.github.com/">GitHub Pages官方说明</a>。</p>

<h2 id="图文教程">图文教程</h2>

<p>注意以下需要上电脑操作。</p>

<h3 id="第一步-使用这个template">第一步 使用这个template</h3>

<p>请点击<a href="https://github.com/">GitHub</a>，注册一个GitHub账户，这是完全免费的，只要提供邮箱即可。</p>

<p>现在你看到的LOFFER，是作为一个GitHub上的Repository（代码库）存在的，我将之设为可以作为template（模板），你可以用这个模板来生成一份自己的LOFFER。</p>

<p>点击<a href="https://github.com/FromEndWorld/LOFFER">LOFFER</a>，进入LOFFER的GitHub Repository页面，然后点<strong>Use this template</strong>，如图所示。</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/usetemplate.png" alt="img" /></p>

<p>你会进入如下页面，请给你的博客起个名字，这里只能用字母和少数特殊字符，没有关系，这个名称并不影响你的博客页面显示。</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/nameyourbolg.png" alt="img" /></p>

<p>点击<strong>Create repository from template</strong>，你很快就会看到如下页面，GitHub已经将LOFFER中所有的文件复制到你的新代码库中。</p>

<p>下一步，点击Settings，进入相关设置。</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/Settings.png" alt="img" /></p>

<p>向下拉页面，你会看到“GitHub Pages”，这是GitHub内置的网站host服务，选择master，如图所示：</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/pages.png" alt="img" /></p>

<p>在几秒钟后，刷新此页面，你通常会看到这个绿色的东西（如果没看到，多等一会），你的网站已经发布成功，点击这个链接，即可查看：</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/published.png" alt="img" /></p>

<p>你可能会看到网站长得很丑，这是因为样式表尚未从正确的地址加载，没关系，请继续下一步。</p>

<h3 id="第二步-设置站点信息">第二步 设置站点信息</h3>

<p>在你的博客的GitHub代码库页面里，选择Code，文件列表里选择_config.yml，点击打开，然后点击右上角笔形图标修改文档。</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/config.png" alt="img" /></p>

<p>关于如何修改站点信息，在文件内有文档说明。</p>

<p>修改完成后，点击<strong>Commit changes</strong>（提交修改）。每次修改过代码库并且提交后，GitHub Pages都会自动重新发布网站，只要等上几分钟，再次刷新你的博客页面，就会看到你的修改了。这一修改完成后，你的博客站应该可以正常显示了。</p>

<p>如果刷新看不到效果，请使用“强刷新”，一般来说按ctrl+R。</p>

<p>还有一点，<strong>LOFFER使用的是MIT协议，大意就是全部开源随意使用，如果你要保留自己博文的权利，请编辑LICENSE文件，写上类似“博文作者保留权利”这样的内容。</strong></p>

<h3 id="第三步-发布博文">第三步 发布博文</h3>

<p>在你的博客的GitHub代码库页面里，点开_posts文件夹，这里面就是你的博客文章。</p>

<p>这些文章使用的格式是Markdown，文件后缀名是md，这是一种非常简单易用的有格式文本标记语言，你应该已经注意到，在LOFFER自带的示例性博文中有一篇中文的<a href="https://fromendworld.github.io/LOFFER/chinese-markdown-cheatsheet/">Markdown语法介绍</a>。</p>

<p>更简单的办法是使用<a href="https://typora.io/">Typora</a>，这是一个全图形化界面，全实时预览的Markdown写作软件，非常轻量，而且免费。</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/Typora.png" alt="img" /></p>

<p>在发布博文前，你需要在文章的头部添加这样的内容，包括你的文章标题，发布日期，作者名，和tag等。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
layout: post
title: LOFFER文档
date: 2019-06-02
Author: 来自中世界
categories: 
tags: [sample, document]
comments: true
--- 
</code></pre></div></div>

<p>完成后，保存为.md文件，文件名是date-标题，例如 2019-06-02-document.md (注意这里的标题会成为这篇博文的链接，所以请使用字母而非中文，它不影响页面上显示的标题)，然后上传到_posts文件夹，再提交修改，很快就可以在博客上看到新文章了。</p>

<h3 id="可选图片怎么办">可选：图片怎么办？</h3>

<p>少量图片可以上传到images文件夹，然后在博文中添加。</p>

<p>但是GitHub用来当做图床有滥用之嫌，如果你的博客以图片为主，建议选择外链图床，例如<a href="https://sm.ms/">sm.ms</a>就是和很好的选择。</p>

<p>要寻找更适合自己的图床，敬请搜索一下。</p>

<p>在博文中添加图片的Markdown语法是：<code class="language-plaintext highlighter-rouge">![图片名](URL)</code></p>

<h3 id="可选添加评论区">可选：添加评论区</h3>

<h4 id="disqus">Disqus</h4>

<p>LOFFER支持Disqus评论，虽然Disqus很丑，但是它是免费的，设置起来又方便，因此大家也就不要嫌弃它。</p>

<p><strong>注意：目前有一些LOFFER使用者没有修改示例站现有的Disqus配置，那么你用的就是我的Disqus站点，这样不好，不好……</strong></p>

<p><strong>请根据一下教程配置你自己的站点。</strong></p>

<p>首先，注册一个<a href="https://disqus.com/">Disqus</a>账户，我们可以选择这个免费方案：</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/Disqus-plan.png" alt="img" /></p>

<p>注册成功后，新建一个站点（site），以LOFFER为例设置步骤如下：</p>

<p>首先站点名LOFFER，生成了shortname是loffer，类型可以随便选。</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/Disqus-1.png" alt="img" /></p>

<p>安装时选择Jekyll。</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/Disqus-2.png" alt="img" /></p>

<p>最后填入你的博客地址，语言可以选中文，点Complete，即可！</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/Disqus-3.png" alt="img" /></p>

<p>然后需要回到你的博客，修改_config.yml文件，在disqus字段填上你的shortname，commit，完成！</p>

<h4 id="gitalk">Gitalk</h4>

<p>LOFFER 0.2.0版本支持Gitalk评论区（在LOFFER示例站中仍然是Disqus，可以在<a href="https://himring.top/gitalk/">我的博客</a>查看Gitalk的demo），设置方法如下：</p>

<p>首先，创建一个<a href="https://github.com/settings/applications/new">OAuth application</a>, 设置如图：</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/application_settings.png" alt="img" /></p>

<p>点Register后就会看到你所需要的两个值，clientID和clientSecret，把它们复制到你的_config.yml文件中相应的字段：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gitalk:
  clientID: &lt;你的clientID&gt;
  clientSecret: &lt;你的clientSecret&gt;
  repo: &lt;你的repository名称&gt;
  owner: &lt;你的GitHub用户名&gt;
  proxy: &lt;代理地址&gt;
</code></pre></div></div>

<p>然后commit，你的Gitalk评论区就会出现了。第一次使用的时候，需要你来进入文章页，来初始化评论区，这一操作会在你的repository上创建一个Issue，此后的评论就是对这个Issue的回复。</p>

<p>你可以进入你的repository的Issue页面，点<strong>Unsubscribe</strong>来避免收到大量相关邮件。</p>

<p>注意：出于很明显的原因，最好不要同时添加Disqus和Gitalk评论区。</p>

<h3 id="导入lofter的内容">导入LOFTER的内容</h3>

<p>这部分由于LOFTER的导出文件十分<del>优秀</del>，需要另外解决。</p>

<p>诸位可以使用我修改的脚本<a href="https://github.com/FromEndWorld/lofter2Jekyll">lofter2Jekyll</a>，功能为将lofter导出的文件转换成可用于Jekyll的MD文档，还可以将图片批量下载到本地。</p>

<p>也可以使用<a href="http://underdream.lofter.com/post/38ea7d_1c5d8a983">墨问非名太太的脚本</a>，其中选择Jekyll输出即可。</p>

<h2 id="致谢">致谢</h2>

<ul>
  <li><a href="https://github.com/jekyll/jekyll">Jekyll</a> - 这是本站存在的根基</li>
  <li><a href="https://github.com/aweekj/kiko-now">Kiko-now</a> - 我首先是fork这个主题，然后再其上进行修改汉化，才有了LOFFER</li>
  <li><a href="https://fontawesome.com/">Font Awesome</a> - 社交网络图标来自FontAwesome的免费开源内容</li>
</ul>

<h2 id="帮助这个项目">帮助这个项目</h2>

<p>介绍更多人来使用它，摆脱lofter自由飞翔！</p>

<p>当然如果单说写同人的话，我还是建议大家都去AO3，但是自家博客自己架也很酷炫，你还可以选择很多其他的Jeykll主题，GitHub上有很多，或者试试其他博客架设工具，例如Hexo，与代码斗其乐无穷。</p>

<p>最后，回到<a href="https://github.com/FromEndWorld/LOFFER">LOFFER</a>，给我点一个☆吧！</p>

<p><img src="https://raw.githubusercontent.com/FromEndWorld/LOFFER/master/images/givemefive.png" alt="img" /></p>]]></content><author><name>来自中世界</name></author><category term="sample" /><category term="document" /><summary type="html"><![CDATA[LOFFER是个可以帮助你get off from LOFTER的软件（我知道这个pun很烂）。 这是一个可以直接发布在GitHub page的Jekyll博客，你不需要编写代码或使用命令行即可配置属于你的LOFFER。 本文为针对完全没有代码基础的朋友的基础教程。 注意 LOFFER是一个博客模板。 虽然意图有针对lofter用户，但是我个人狠不赞同纯外链停车操作，你整整齐齐打理个自由自在没有敏感词的个人博客有啥不好。 不要用我的Discus账户，请配置你自己的，本文档中有教程 如有疑问，请阅读GitHub Pages官方说明。 图文教程 注意以下需要上电脑操作。 第一步 使用这个template 请点击GitHub，注册一个GitHub账户，这是完全免费的，只要提供邮箱即可。 现在你看到的LOFFER，是作为一个GitHub上的Repository（代码库）存在的，我将之设为可以作为template（模板），你可以用这个模板来生成一份自己的LOFFER。 点击LOFFER，进入LOFFER的GitHub Repository页面，然后点Use this template，如图所示。 你会进入如下页面，请给你的博客起个名字，这里只能用字母和少数特殊字符，没有关系，这个名称并不影响你的博客页面显示。 点击Create repository from template，你很快就会看到如下页面，GitHub已经将LOFFER中所有的文件复制到你的新代码库中。 下一步，点击Settings，进入相关设置。 向下拉页面，你会看到“GitHub Pages”，这是GitHub内置的网站host服务，选择master，如图所示： 在几秒钟后，刷新此页面，你通常会看到这个绿色的东西（如果没看到，多等一会），你的网站已经发布成功，点击这个链接，即可查看： 你可能会看到网站长得很丑，这是因为样式表尚未从正确的地址加载，没关系，请继续下一步。 第二步 设置站点信息 在你的博客的GitHub代码库页面里，选择Code，文件列表里选择_config.yml，点击打开，然后点击右上角笔形图标修改文档。 关于如何修改站点信息，在文件内有文档说明。 修改完成后，点击Commit changes（提交修改）。每次修改过代码库并且提交后，GitHub Pages都会自动重新发布网站，只要等上几分钟，再次刷新你的博客页面，就会看到你的修改了。这一修改完成后，你的博客站应该可以正常显示了。 如果刷新看不到效果，请使用“强刷新”，一般来说按ctrl+R。 还有一点，LOFFER使用的是MIT协议，大意就是全部开源随意使用，如果你要保留自己博文的权利，请编辑LICENSE文件，写上类似“博文作者保留权利”这样的内容。 第三步 发布博文 在你的博客的GitHub代码库页面里，点开_posts文件夹，这里面就是你的博客文章。 这些文章使用的格式是Markdown，文件后缀名是md，这是一种非常简单易用的有格式文本标记语言，你应该已经注意到，在LOFFER自带的示例性博文中有一篇中文的Markdown语法介绍。 更简单的办法是使用Typora，这是一个全图形化界面，全实时预览的Markdown写作软件，非常轻量，而且免费。 在发布博文前，你需要在文章的头部添加这样的内容，包括你的文章标题，发布日期，作者名，和tag等。 --- layout: post title: LOFFER文档 date: 2019-06-02 Author: 来自中世界 categories: tags: [sample, document] comments: true --- 完成后，保存为.md文件，文件名是date-标题，例如 2019-06-02-document.md (注意这里的标题会成为这篇博文的链接，所以请使用字母而非中文，它不影响页面上显示的标题)，然后上传到_posts文件夹，再提交修改，很快就可以在博客上看到新文章了。 可选：图片怎么办？ 少量图片可以上传到images文件夹，然后在博文中添加。 但是GitHub用来当做图床有滥用之嫌，如果你的博客以图片为主，建议选择外链图床，例如sm.ms就是和很好的选择。 要寻找更适合自己的图床，敬请搜索一下。 在博文中添加图片的Markdown语法是：![图片名](URL) 可选：添加评论区 Disqus LOFFER支持Disqus评论，虽然Disqus很丑，但是它是免费的，设置起来又方便，因此大家也就不要嫌弃它。 注意：目前有一些LOFFER使用者没有修改示例站现有的Disqus配置，那么你用的就是我的Disqus站点，这样不好，不好…… 请根据一下教程配置你自己的站点。 首先，注册一个Disqus账户，我们可以选择这个免费方案： 注册成功后，新建一个站点（site），以LOFFER为例设置步骤如下： 首先站点名LOFFER，生成了shortname是loffer，类型可以随便选。 安装时选择Jekyll。 最后填入你的博客地址，语言可以选中文，点Complete，即可！ 然后需要回到你的博客，修改_config.yml文件，在disqus字段填上你的shortname，commit，完成！ Gitalk LOFFER 0.2.0版本支持Gitalk评论区（在LOFFER示例站中仍然是Disqus，可以在我的博客查看Gitalk的demo），设置方法如下： 首先，创建一个OAuth application, 设置如图： 点Register后就会看到你所需要的两个值，clientID和clientSecret，把它们复制到你的_config.yml文件中相应的字段： gitalk: clientID: &lt;你的clientID&gt; clientSecret: &lt;你的clientSecret&gt; repo: &lt;你的repository名称&gt; owner: &lt;你的GitHub用户名&gt; proxy: &lt;代理地址&gt; 然后commit，你的Gitalk评论区就会出现了。第一次使用的时候，需要你来进入文章页，来初始化评论区，这一操作会在你的repository上创建一个Issue，此后的评论就是对这个Issue的回复。 你可以进入你的repository的Issue页面，点Unsubscribe来避免收到大量相关邮件。 注意：出于很明显的原因，最好不要同时添加Disqus和Gitalk评论区。 导入LOFTER的内容 这部分由于LOFTER的导出文件十分优秀，需要另外解决。 诸位可以使用我修改的脚本lofter2Jekyll，功能为将lofter导出的文件转换成可用于Jekyll的MD文档，还可以将图片批量下载到本地。 也可以使用墨问非名太太的脚本，其中选择Jekyll输出即可。 致谢 Jekyll - 这是本站存在的根基 Kiko-now - 我首先是fork这个主题，然后再其上进行修改汉化，才有了LOFFER Font Awesome - 社交网络图标来自FontAwesome的免费开源内容 帮助这个项目 介绍更多人来使用它，摆脱lofter自由飞翔！ 当然如果单说写同人的话，我还是建议大家都去AO3，但是自家博客自己架也很酷炫，你还可以选择很多其他的Jeykll主题，GitHub上有很多，或者试试其他博客架设工具，例如Hexo，与代码斗其乐无穷。 最后，回到LOFFER，给我点一个☆吧！]]></summary></entry><entry><title type="html">Markdown语法简介</title><link href="https://right202209.github.io/blog/chinese-markdown-cheatsheet/" rel="alternate" type="text/html" title="Markdown语法简介" /><published>2013-07-16T00:00:00+00:00</published><updated>2013-07-16T00:00:00+00:00</updated><id>https://right202209.github.io/blog/chinese-markdown-cheatsheet</id><content type="html" xml:base="https://right202209.github.io/blog/chinese-markdown-cheatsheet/"><![CDATA[<p>本中文版Markdown语法简介来自博客 <a href="https://blog.shengbin.me/posts/markdown-syntax">https://blog.shengbin.me/posts/markdown-syntax</a>，并由我完成了汉化。其中的站位文字来自<a href="https://suulnnka.github.io/BullshitGenerator/index.html">狗屁不通文章生成器</a>。</p>

<p><a href="http://daringfireball.net/projects/markdown/syntax">Markdown语法的完整文档在这里</a>。下面整理的这些为了方便写博客时参考。</p>

<h2 id="分段与分行">分段与分行</h2>

<p>以一个或多个空行来隔开段落；以两个或多个空格来段内换行。</p>

<h2 id="标题">标题</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>这是一级标题
=============

这是二级标题
-------------

# 一级标题

##  二级标题

######  六级标题

</code></pre></div></div>

<h2 id="引用">引用</h2>

<p>在每一行前面写一个<code class="language-plaintext highlighter-rouge">&gt;</code>：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; 这是一个引用段落。
&gt; 一般来讲，我们都必须务必慎重的考虑考虑。 了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。 
&gt; 一般来说， 莎士比亚曾经说过，抛弃时间的人，时间也抛弃他。这似乎解答了我的疑惑。 
&gt;
&gt; 笛卡儿曾经提到过，读一切好书，就是和许多高尚的人谈话。带着这句话，我们还要更加慎重的审视这个问题： 
&gt; 现在，解决标记语言的问题，是非常非常重要的。 

</code></pre></div></div>

<p>效果：</p>

<blockquote>
  <p>这是一个引用段落。
一般来讲，我们都必须务必慎重的考虑考虑。 了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。 
一般来说， 莎士比亚曾经说过，抛弃时间的人，时间也抛弃他。这似乎解答了我的疑惑。</p>

  <p>笛卡儿曾经提到过，读一切好书，就是和许多高尚的人谈话。带着这句话，我们还要更加慎重的审视这个问题： 
现在，解决标记语言的问题，是非常非常重要的。</p>
</blockquote>

<p>或者在每一段前面写一个<code class="language-plaintext highlighter-rouge">&gt;</code>：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; 这是一个引用段落。一般来讲，我们都必须务必慎重的考虑考虑。 了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。 一般来说， 莎士比亚曾经说过，抛弃时间的人，时间也抛弃他。这似乎解答了我的疑惑。

&gt; 笛卡儿曾经提到过，读一切好书，就是和许多高尚的人谈话。带着这句话，我们还要更加慎重的审视这个问题： 现在，解决标记语言的问题，是非常非常重要的。 
</code></pre></div></div>

<h2 id="多重引用">多重引用</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; 这是第一层引用
&gt;
&gt; &gt; 这是第二层引用
&gt;
&gt; 回到第一层

</code></pre></div></div>

<p>效果：</p>

<blockquote>
  <p>这是第一层引用</p>

  <blockquote>
    <p>这是第二层引用</p>
  </blockquote>

  <p>回到第一层</p>
</blockquote>

<h2 id="列表">列表</h2>

<p>列表项占一行，以*、+、-开头即可：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*   甲子
*   乙丑
*   丙寅

</code></pre></div></div>

<p>效果：</p>

<ul>
  <li>甲子</li>
  <li>乙丑</li>
  <li>丙寅</li>
</ul>

<p>有序列表只需要将上述标记符换成数字加句点。而且顺序由书写顺序决定，与数字无关，但数字需要从1开始。例如：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1.  天
3.  地
2.  人

</code></pre></div></div>

<p>效果：</p>

<ol>
  <li>天</li>
  <li>地</li>
  <li>人</li>
</ol>

<p>每一个列表项可以多行：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*  而这些并不是完全重要，更加重要的问题是，可是，即使是这样，标记语言的出现仍然代表了一定的意义。叔本华说过一句富有哲理的话，意志是一个强壮的盲人，倚靠在明眼的跛子肩上。这启发了我，要想清楚，标记语言，到底是一种怎么样的存在。
*   伏尔泰说过一句富有哲理的话，坚持意志伟大的事业需要始终不渝的精神。这启发了我，本人也是经过了深思熟虑，在每个日日夜夜思考这个问题。那么，标记语言因何而发生？了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。而这些并不是完全重要，更加重要的问题是，就我个人来说，标记语言对我的意义，不能不说非常重大。就我个人来说，标记语言对我的意义，不能不说非常重大。我们不得不面对一个非常尴尬的事实，那就是，总结的来说，标记语言因何而发生？

</code></pre></div></div>

<p>效果：</p>

<ul>
  <li>而这些并不是完全重要，更加重要的问题是，可是，即使是这样，标记语言的出现仍然代表了一定的意义。叔本华说过一句富有哲理的话，意志是一个强壮的盲人，倚靠在明眼的跛子肩上。这启发了我，要想清楚，标记语言，到底是一种怎么样的存在。</li>
  <li>伏尔泰说过一句富有哲理的话，坚持意志伟大的事业需要始终不渝的精神。这启发了我，本人也是经过了深思熟虑，在每个日日夜夜思考这个问题。那么，标记语言因何而发生？了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。而这些并不是完全重要，更加重要的问题是，就我个人来说，标记语言对我的意义，不能不说非常重大。就我个人来说，标记语言对我的意义，不能不说非常重大。我们不得不面对一个非常尴尬的事实，那就是，总结的来说，标记语言因何而发生？</li>
</ul>

<h2 id="代码块">代码块</h2>

<p>每一行前面缩进四个或以上个空格，就认为是开始了一段代码块。代码块内原样输出。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>这是一个普通段落

    这是一个代码块

</code></pre></div></div>

<p>效果：</p>

<p>这是一个普通段落</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>这是一个代码块
</code></pre></div></div>

<h2 id="横线">横线</h2>

<p>三个或更多个<code class="language-plaintext highlighter-rouge">*</code>、<code class="language-plaintext highlighter-rouge">-</code>（它们之间可以有空格）会产生横线：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>* * *

</code></pre></div></div>

<p>效果：</p>

<hr />

<h2 id="链接">链接</h2>

<p>内嵌链接：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[链接文字](链接地址 "链接描述") 
例如 [Google](http://google.com/ "Google")，[Yahoo](http://search.yahoo.com/ "Yahoo Search")，[MSN](http://search.msn.com/ "MSN Search").

</code></pre></div></div>

<p>效果：</p>

<p><a href="链接地址" title="链接描述">链接文字</a> 
例如 <a href="http://google.com/" title="Google">Google</a>，<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>，<a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>

<p>如果直接以链接地址作为链接文本，可以用如下快捷写法：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;http://www.shengbin.me&gt; 效果：

</code></pre></div></div>

<p><a href="http://www.shengbin.me">http://www.shengbin.me</a></p>

<h2 id="强调">强调</h2>

<p>单个<code class="language-plaintext highlighter-rouge">*</code>或<code class="language-plaintext highlighter-rouge">_</code>产生斜体，两个（<code class="language-plaintext highlighter-rouge">**</code>、<code class="language-plaintext highlighter-rouge">__</code>）则产生粗体。例如：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*斜体* _斜体_

**粗体** **粗体**

***又粗又斜*** ___又粗又斜___

</code></pre></div></div>

<p>效果：</p>

<p><em>斜体</em> <em>斜体</em></p>

<p><strong>粗体</strong> <strong>粗体</strong></p>

<p><strong><em>又粗又斜</em></strong> <strong><em>又粗又斜</em></strong></p>

<h2 id="内嵌代码">内嵌代码</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>内嵌代码 `天地玄黄`

</code></pre></div></div>

<p>效果：</p>

<p>内嵌代码 <code class="language-plaintext highlighter-rouge">天地玄黄</code></p>

<h2 id="图片">图片</h2>

<p>语法和链接相似，只是前面多个“!”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>![替代文字](图片url "图片说明")
</code></pre></div></div>

<h2 id="转义字符">转义字符</h2>

<p>如果需要使用以上标记字符而不被Markdown理解为格式标记，需要用<code class="language-plaintext highlighter-rouge">\</code>转义：例如<code class="language-plaintext highlighter-rouge">\\</code>，效果为\。</p>]]></content><author><name></name></author><category term="sample" /><category term="markdown" /><summary type="html"><![CDATA[本中文版Markdown语法简介来自博客 https://blog.shengbin.me/posts/markdown-syntax，并由我完成了汉化。其中的站位文字来自狗屁不通文章生成器。 Markdown语法的完整文档在这里。下面整理的这些为了方便写博客时参考。 分段与分行 以一个或多个空行来隔开段落；以两个或多个空格来段内换行。 标题 这是一级标题 ============= 这是二级标题 ------------- # 一级标题 ## 二级标题 ###### 六级标题 引用 在每一行前面写一个&gt;： &gt; 这是一个引用段落。 &gt; 一般来讲，我们都必须务必慎重的考虑考虑。 了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。 &gt; 一般来说， 莎士比亚曾经说过，抛弃时间的人，时间也抛弃他。这似乎解答了我的疑惑。 &gt; &gt; 笛卡儿曾经提到过，读一切好书，就是和许多高尚的人谈话。带着这句话，我们还要更加慎重的审视这个问题： &gt; 现在，解决标记语言的问题，是非常非常重要的。 效果： 这是一个引用段落。 一般来讲，我们都必须务必慎重的考虑考虑。 了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。 一般来说， 莎士比亚曾经说过，抛弃时间的人，时间也抛弃他。这似乎解答了我的疑惑。 笛卡儿曾经提到过，读一切好书，就是和许多高尚的人谈话。带着这句话，我们还要更加慎重的审视这个问题： 现在，解决标记语言的问题，是非常非常重要的。 或者在每一段前面写一个&gt;： &gt; 这是一个引用段落。一般来讲，我们都必须务必慎重的考虑考虑。 了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。 一般来说， 莎士比亚曾经说过，抛弃时间的人，时间也抛弃他。这似乎解答了我的疑惑。 &gt; 笛卡儿曾经提到过，读一切好书，就是和许多高尚的人谈话。带着这句话，我们还要更加慎重的审视这个问题： 现在，解决标记语言的问题，是非常非常重要的。 多重引用 &gt; 这是第一层引用 &gt; &gt; &gt; 这是第二层引用 &gt; &gt; 回到第一层 效果： 这是第一层引用 这是第二层引用 回到第一层 列表 列表项占一行，以*、+、-开头即可： * 甲子 * 乙丑 * 丙寅 效果： 甲子 乙丑 丙寅 有序列表只需要将上述标记符换成数字加句点。而且顺序由书写顺序决定，与数字无关，但数字需要从1开始。例如： 1. 天 3. 地 2. 人 效果： 天 地 人 每一个列表项可以多行： * 而这些并不是完全重要，更加重要的问题是，可是，即使是这样，标记语言的出现仍然代表了一定的意义。叔本华说过一句富有哲理的话，意志是一个强壮的盲人，倚靠在明眼的跛子肩上。这启发了我，要想清楚，标记语言，到底是一种怎么样的存在。 * 伏尔泰说过一句富有哲理的话，坚持意志伟大的事业需要始终不渝的精神。这启发了我，本人也是经过了深思熟虑，在每个日日夜夜思考这个问题。那么，标记语言因何而发生？了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。而这些并不是完全重要，更加重要的问题是，就我个人来说，标记语言对我的意义，不能不说非常重大。就我个人来说，标记语言对我的意义，不能不说非常重大。我们不得不面对一个非常尴尬的事实，那就是，总结的来说，标记语言因何而发生？ 效果： 而这些并不是完全重要，更加重要的问题是，可是，即使是这样，标记语言的出现仍然代表了一定的意义。叔本华说过一句富有哲理的话，意志是一个强壮的盲人，倚靠在明眼的跛子肩上。这启发了我，要想清楚，标记语言，到底是一种怎么样的存在。 伏尔泰说过一句富有哲理的话，坚持意志伟大的事业需要始终不渝的精神。这启发了我，本人也是经过了深思熟虑，在每个日日夜夜思考这个问题。那么，标记语言因何而发生？了解清楚标记语言到底是一种怎么样的存在，是解决一切问题的关键。而这些并不是完全重要，更加重要的问题是，就我个人来说，标记语言对我的意义，不能不说非常重大。就我个人来说，标记语言对我的意义，不能不说非常重大。我们不得不面对一个非常尴尬的事实，那就是，总结的来说，标记语言因何而发生？ 代码块 每一行前面缩进四个或以上个空格，就认为是开始了一段代码块。代码块内原样输出。 这是一个普通段落 这是一个代码块 效果： 这是一个普通段落 这是一个代码块 横线 三个或更多个*、-（它们之间可以有空格）会产生横线： * * * 效果： 链接 内嵌链接： [链接文字](链接地址 "链接描述") 例如 [Google](http://google.com/ "Google")，[Yahoo](http://search.yahoo.com/ "Yahoo Search")，[MSN](http://search.msn.com/ "MSN Search"). 效果： 链接文字 例如 Google，Yahoo，MSN. 如果直接以链接地址作为链接文本，可以用如下快捷写法： &lt;http://www.shengbin.me&gt; 效果： http://www.shengbin.me 强调 单个*或_产生斜体，两个（**、__）则产生粗体。例如： *斜体* _斜体_ **粗体** **粗体** ***又粗又斜*** ___又粗又斜___ 效果： 斜体 斜体 粗体 粗体 又粗又斜 又粗又斜 内嵌代码 内嵌代码 `天地玄黄` 效果： 内嵌代码 天地玄黄 图片 语法和链接相似，只是前面多个“!” ![替代文字](图片url "图片说明") 转义字符 如果需要使用以上标记字符而不被Markdown理解为格式标记，需要用\转义：例如\\，效果为\。]]></summary></entry></feed>