<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0"><channel><title>Bliner</title><link>https://www.bliner.me</link><atom:link href="https://www.bliner.me/rss.xml" rel="self" type="application/rss+xml"/><description>Bliner</description><generator>Halo v2.25.0</generator><language>zh-cn</language><lastBuildDate>Tue, 18 Aug 2026 08:30:14 GMT</lastBuildDate><item><title><![CDATA[20260818 多 AI  模型协作分享（第一期）]]></title><link>https://www.bliner.me/archives/20260818-duo-ai-mo-xing-xie-zuo-fen-xiang-di-yi-qi</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=20260818%20%E5%A4%9A%20AI%20%20%E6%A8%A1%E5%9E%8B%E5%8D%8F%E4%BD%9C%E5%88%86%E4%BA%AB%EF%BC%88%E7%AC%AC%E4%B8%80%E6%9C%9F%EF%BC%89&amp;url=/archives/20260818-duo-ai-mo-xing-xie-zuo-fen-xiang-di-yi-qi" width="1" height="1" alt="" style="opacity:0;">
<h1 style="" id="%E5%89%8D%E6%8F%90">前提</h1>
<ol>
 <li>
  <p style="">根据各个版本的模型特点，经常换搭配，参考请留意时间和版本</p>
 </li>
 <li>
  <p style="">Grok4.6 和 GPT 不降智为前提</p>
 </li>
</ol>
<p style=""></p>
<h1 style="" id="%E8%B7%A8%E7%AB%AF%E5%A4%A7%E4%BB%BB%E5%8A%A1">跨端大任务</h1>
<ul>
 <li>
  <p style=""><strong>讨论+设计： Opus 5 High / Max （主要是避免 Sol 的雷霆大思考，Opus 目前还是没那么多废话）</strong></p>
 </li>
 <li>
  <p style=""><strong>可行性分析：GPT5.6 Sol High / 看雷达图95以上 （主要是利用 Sol 的雷霆大思考，提前发现计划中可能的问题，又不至于让它太发散）</strong></p>
 </li>
 <li>
  <p style=""><strong>执行：Opus 5 监督 Grok 4.6 （DSF 正式版也行）执行 （体感上就像是着急下班的高级程序员，干活雷厉风行，不过度思考）</strong></p>
 </li>
 <li>
  <p style=""><strong>验收：GPT5.6 Sol 或 GLM 5.3（依然是利用雷霆大思考去发现问题）</strong></p>
 </li>
 <li>
  <p style=""><strong>复工：Opus 5 High / Max 充新做计划 或 监督 Grok 4.6 补充执行</strong></p>
 </li>
</ul>
<p style=""></p>
<h1 style="" id="%E7%9B%AE%E6%A0%87%E6%98%8E%E7%A1%AE%E7%9A%84%E5%B0%8F%E4%BB%BB%E5%8A%A1">目标明确的小任务</h1>
<p style="">定义很简单，知道是哪的问题，也知道错误原因，直接告诉 Agent 问题和怎么改，基本上指哪打哪。</p>
<p style="">这种小任务就不用计划和可行性分析了，直接执行即可。</p>
<p style=""></p>
<ul>
 <li>
  <p style=""><strong>执行：Grok4.6 （DSF 正式版也行） 直接执行，</strong></p>
 </li>
 <li>
  <p style=""><strong>验收：基本上不用验收，因为直接能看到改好了，如果验收可以走 GLM 5.3 或 Kimi-K3</strong></p>
 </li>
</ul>
<p style=""></p>
<p style=""></p>
<h1 style="" id="%E5%A6%82%E6%9E%9C%E4%BD%A0%E5%A5%BD%E5%A5%87%E5%A6%82%E4%BD%95%E8%AE%A9opus5-%E7%9B%91%E7%9D%A3-grok4.6-%E5%B9%B2%E6%B4%BB">如果你好奇如何让Opus5 监督 Grok4.6 干活</h1>
<p style="">我使用的是 Paseo，可以利用 Paseo 的 Skill，从 Claude 中调起一个 Grok 的子 Agent，然后让 Opus5 控制这个子 Agent 即可。</p>]]></description><guid isPermaLink="false">/archives/20260818-duo-ai-mo-xing-xie-zuo-fen-xiang-di-yi-qi</guid><dc:creator>Bliner</dc:creator><category>AI&amp;Agent</category><pubDate>Tue, 18 Aug 2026 04:01:00 GMT</pubDate></item><item><title><![CDATA[DeepSeek V4 Flash 正式版体验]]></title><link>https://www.bliner.me/archives/deepseek-v4-flash-zheng-shi-ban-ti-yan</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=DeepSeek%20V4%20Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%BD%93%E9%AA%8C&amp;url=/archives/deepseek-v4-flash-zheng-shi-ban-ti-yan" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">一句话总结，速度快，价格低，小问题指哪打哪。</p>
</blockquote>
<h1 style="" id="%E4%BB%B7%E6%A0%BC">价格</h1>
<p style="">梁圣之所以是梁圣，还是极致的性价比。但是绝对不会是白菜价，今天也是发出了涨价提示。</p>
<figure style="align-items: start; display: flex; flex-direction: column" data-content-type="image">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage-egl8.png&amp;size=m">
</figure>
<p style=""></p>
<p style="">但是 DeepSeek V4 Flash 依然很能打，最起码不用再去印度薅 Grok 4.5 的羊毛了，能力跟速度都不相上下。</p>
<p style=""></p>
<p style="">当然不能说白菜价，我每天估计会用到 3 块钱左右，按照一月20天算，差不多60块钱。</p>
<p style="">但是如果跟 Grok4.5 的 Coder 能掰手腕，那门槛还是要降低不少的。</p>
<p style=""></p>
<p style=""></p>
<h1 style="" id="%E8%83%BD%E5%8A%9B">能力</h1>
<p style="">在 Pro 没发布前，我不敢说什么，但用 DeepSeek V4 Flash，我个人还是建议走 Grok 的思路，短平快，指哪打哪。</p>
<p style="">不错的 websearch 能力，不错的速度，长超的上下文（1 M），都是优点。</p>
<p style=""></p>
<p style="">但是我绝对不会在跨多端系统、复杂上下文、需要深度理解代码架构和意图的事情上让它来当主力。</p>
<p style=""></p>
<p style="">它可以是一个不错的执行者，小问题的快速修复者，甚至做可行性分析，但绝对不是主力。</p>
<p style="">其实我有点期待 Pro 的表现（AI 平权）。</p>
<p style=""></p>
<p style=""></p>
<h1 style="" id="%E6%8E%A8%E8%8D%90%E5%9C%BA%E6%99%AF">推荐场景</h1>
<p style=""></p>
<ol>
 <li>
  <p style="">作为详细计划的执行者，速度快，能力够，价格实惠。（Luna Max 太慢了）</p>
 </li>
 <li>
  <p style="">作为可行性分析者，能力够，速度快，提出不一样观点的分析。</p>
 </li>
 <li>
  <p style="">作为明确的、小范围问题的直接解决者。</p>
 </li>
 <li>
  <p style="">代码解释，指定一个模块或者工作区的待提交内容，让它给你讲明白</p>
 </li>
</ol>
<p style=""></p>
<h1 style="" id="%E5%A4%87%E6%B3%A8">备注</h1>
<p style="">我主要还是以个人 Coding 为基础有上述看法，必然是偏见的。</p>
<p style="">DeepSeek V4 Flash 目前还缺少多模态，但是在文学创作、世界知识上肯定还有其它不错的表现。</p>
<p style="">本文仅探讨 Coding。</p>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/deepseek-v4-flash-zheng-shi-ban-ti-yan</guid><dc:creator>Bliner</dc:creator><enclosure url="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage-1xgr.png&amp;size=m" type="image/jpeg" length="46710"/><category>AI&amp;Agent</category><pubDate>Thu, 6 Aug 2026 07:31:37 GMT</pubDate></item><item><title><![CDATA[Grok 4.5 的编程使用经验分享，利用速度优势，指哪打哪]]></title><link>https://www.bliner.me/archives/grok-4.5-de-shi-yong-jing-yan-fen-xiang-li-yong-su-du-you-shi-zhi-na-da-na</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=Grok%204.5%20%E7%9A%84%E7%BC%96%E7%A8%8B%E4%BD%BF%E7%94%A8%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB%EF%BC%8C%E5%88%A9%E7%94%A8%E9%80%9F%E5%BA%A6%E4%BC%98%E5%8A%BF%EF%BC%8C%E6%8C%87%E5%93%AA%E6%89%93%E5%93%AA&amp;url=/archives/grok-4.5-de-shi-yong-jing-yan-fen-xiang-li-yong-su-du-you-shi-zhi-na-da-na" width="1" height="1" alt="" style="opacity:0;">
<h1 style="" id="%E5%85%88%E6%8A%9B%E7%BB%93%E8%AE%BA">先抛结论</h1>
<p style=""></p>
<blockquote>
 <p style=""><strong>适合：</strong>用于 <code>明确的小任务</code> 和 <code>复杂任务执行</code> 上</p>
 <p style=""><strong>不适合：</strong>用于整体代码分析和模糊目标上</p>
</blockquote>
<h1 style="" id="grok-4.5%E7%9A%84%E4%BC%98%E7%82%B9%E5%8F%8A%E8%83%BD%E5%8A%9B">Grok 4.5的优点及能力</h1>
<ol>
 <li>
  <p style="">体感上，比 GPT 5.4 要强，但是赶不上5.5 High。</p>
 </li>
 <li>
  <p style="">速度上可以说是一骑绝尘。</p>
 </li>
 <li>
  <p style="">支持多模态，能看图！</p>
 </li>
</ol>
<p style="">了解了能力边界和优势，我们就可以开始利用能力去快速达成我们的目的。</p>
<p style=""></p>
<h1 style="" id="%E6%AF%94-5.4-%E8%A6%81%E5%BC%BA%E7%9A%84%E8%83%BD%E5%8A%9B">比 5.4 要强的能力</h1>
<p style="">这表示着 Grok 4.5 有着不错的能力，一些目标明确，轻量级的任务，只要描述/讨论清楚，即可交给他直接执行，不用再去设计计划和可行性分析，也能保证不错的执行结果。</p>
<p style=""></p>
<blockquote>
 <p style="">对于我：我经常会把一<code>明确问题和文件</code>的事情跟他直接聊，都明确之后，我会直接在 Grok 里执行。</p>
</blockquote>
<p style=""></p>
<h1 style="" id="%E9%80%9F%E5%BA%A6%E5%BF%AB">速度快</h1>
<p style="">5.4的能力加上超快的速度，能在执行小任务的时候更快落实，表现在</p>
<p style=""></p>
<ol>
 <li>
  <p style="">对于已经有计划的任务，快速落实</p>
 </li>
 <li>
  <p style="">对于代码解释等简单任务的快速回答</p>
 </li>
 <li>
  <p style="">对<code>顺手修复</code> 的快速落地</p>
 </li>
</ol>
<p style=""></p>
<blockquote>
 <p style="">对于我：我会在解释代码的时候经常用，因为 GLM5.2和 GPT5.6都太慢了，甚至影响/打断思考流；其次我会将 Sol 设计的计划交给 Grok 4.5 执行，然后让 Opus 4.8 去验收；当然还有一些明确问题的顺手修复。</p>
</blockquote>
<p style=""></p>
<h1 style="" id="%E5%A4%9A%E6%A8%A1%E6%80%81">多模态</h1>
<p style="">这是 GLM 5.2 缺失的，虽然可以用插件/Skill 完善，但是 Grok 自带的多模态更加方便。</p>
<p style="">当有些需求难以用文字描述的时候，一张图片的参考，是非常有用的，特别是对于前端页面的设计。</p>
<p style=""></p>
<blockquote>
 <p style="">对于我：主要用在前端页面的模仿上，我有时可能说不准确，一张图片作为参照，比什么语言都更好的解决问题。</p>
</blockquote>
<p style=""></p>
<h1 style="" id="%E6%80%BB%E7%BB%93">总结</h1>
<p style="">Grok 4.5 真的是以不错的质量，超高的速度在 LLM 的发展史上写下了一笔。</p>
<p style="">了解 Grok 的能力边界和优势，与其它模型配合，才能更好的帮助我们完成任务。</p>
<p style=""></p>
<blockquote>
 <p style="">昨天夜里 kimi-k3 也发布了，<strong>期待。</strong></p>
</blockquote>
<p style=""></p>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/grok-4.5-de-shi-yong-jing-yan-fen-xiang-li-yong-su-du-you-shi-zhi-na-da-na</guid><dc:creator>Bliner</dc:creator><enclosure url="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage-5rzk.png&amp;size=m" type="image/jpeg" length="104556"/><category>AI&amp;Agent</category><pubDate>Fri, 17 Jul 2026 08:03:30 GMT</pubDate></item><item><title><![CDATA[GPT 5.6 模型实际使用参考，及个人主观体验及分享 ]]></title><link>https://www.bliner.me/archives/5.6-shi-ji-xiang-mu-shi-yong-can-kao-ji-ge-ren-zhu-guan-ti-yan-ji-fen-xiang</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=GPT%205.6%20%E6%A8%A1%E5%9E%8B%E5%AE%9E%E9%99%85%E4%BD%BF%E7%94%A8%E5%8F%82%E8%80%83%EF%BC%8C%E5%8F%8A%E4%B8%AA%E4%BA%BA%E4%B8%BB%E8%A7%82%E4%BD%93%E9%AA%8C%E5%8F%8A%E5%88%86%E4%BA%AB%20&amp;url=/archives/5.6-shi-ji-xiang-mu-shi-yong-can-kao-ji-ge-ren-zhu-guan-ti-yan-ji-fen-xiang" width="1" height="1" alt="" style="opacity:0;">
<p style="">我先抛我的场景下 <strong>个人主观感受</strong></p>
<p style=""></p>
<blockquote>
 <p style="">在 <strong>讨论</strong> 阶段：我可能更偏向用 <strong>Terra 极高</strong></p>
 <p style="">在 <strong>计划</strong> 阶段： <strong>简单用 terra 极高，复杂任务用 Sol 高</strong></p>
 <p style="">在 <strong>执行</strong> 阶段：我更偏向用 <strong>Luna 极高</strong></p>
 <p style="">在 <strong>验收</strong> 阶段：我更偏向于 <strong>Terra 极高</strong></p>
</blockquote>
<p style=""></p>
<p style="">我个人 Plus 真实用的话，对比 5.5 跟 5.6</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>Sol 高 &gt; 5.5 xhigh</strong></p>
 <p style=""><strong>Terra 极高 ≈ 5.5 高</strong></p>
 <p style=""><strong>Luna 极高 &gt; 5.4 xhigh</strong></p>
</blockquote>
<p style=""></p>
<hr>
<p style=""></p>
<p style=""><strong>跟 advisor 讨论模糊概念到清晰：</strong></p>
<ul>
 <li>
  <p style="">5.5极高：7～8</p>
 </li>
 <li>
  <p style="">sol 高：8</p>
 </li>
 <li>
  <p style="">额度感觉差不多，但智商高了一个层级，期间 sol 还压缩了一次上下文，sol 这次是我为数不多一路点头同意的</p>
 </li>
 <li>
  <p style="">terra 极高：7</p>
 </li>
 <li>
  <p style="">terra 的讨论不如 sol 高来的深刻，就是..不那么「知心」，我估计之后讨论我会选 sol 高，额度用的都差不多</p>
 </li>
</ul>
<p style=""></p>
<p style=""><strong>根据上面的讨论上下文，设计计划：</strong></p>
<ul>
 <li>
  <p style="">5.5极高：12</p>
 </li>
 <li>
  <p style="">5.5高：7～8</p>
 </li>
 <li>
  <p style="">sol高：22 😭</p>
 </li>
 <li>
  <p style="">sol 给的计划极为详细，感觉给豆包做都能做对那种，大约是之前1.5～1.7倍的长度</p>
 </li>
 <li>
  <p style="">terra 极高：7</p>
 </li>
 <li>
  <p style="">terra 极高的感觉跟5.5的高差不多，计划内容普通，长度正常</p>
 </li>
</ul>
<p style=""></p>
<p style=""><strong>新窗口，执行上面的计划：</strong></p>
<ul>
 <li>
  <p style="">5.4极高：不超过7，一般在5以下</p>
 </li>
</ul>
<ul>
 <li>
  <p style="">luna 极高：4</p>
 </li>
</ul>
<ul>
 <li>
  <p style="">执行的速度要慢一些或者差不多，但是记住了我让他记录的技术债，也追加到对应的 doc 里了，以前很少能记住，执行完的自己验收也比之前要严谨的多。</p>
 </li>
</ul>
<ul>
 <li>
  <p style="">terra 极高：7</p>
 </li>
 <li>
  <p style="">terra 执行速度一般(Gork4.5超级快)，但是执行结果都是没问题的</p>
 </li>
</ul>
<p style=""></p>
<p style=""><strong>新窗口，根据上面的计划和执行报告验收（含数据库MPC检查）：</strong></p>
<ul>
 <li>
  <p style="">5.5高：差不多5～8，不超过12</p>
 </li>
 <li>
  <p style="">sol高：用了17</p>
 </li>
 <li>
  <p style="">Terra 极高：用了 5</p>
 </li>
 <li>
  <p style="">sol确实是比5.5多测试了几项，测试也更深入了，但没想到超额这么多，但是 MCP 查了不少作为辅助确认</p>
 </li>
</ul>
<hr>
<p style=""></p>
<p style=""><strong>尾巴</strong></p>
<p style="">一上午跑了两轮任务测试，几乎花完了所有的 5H 限制</p>
<p style="">不知道是不是第一天的关系，5.6 明显更「知心」，有点肥波5的那个意思了</p>
<p style="">也可能 5.5 最近流口水太多了。</p>
<p style="">Codex / 未开启 x1.5</p>
<p style="">纯个人主观体感，仅供参考。</p>]]></description><guid isPermaLink="false">/archives/5.6-shi-ji-xiang-mu-shi-yong-can-kao-ji-ge-ren-zhu-guan-ti-yan-ji-fen-xiang</guid><dc:creator>Bliner</dc:creator><category>AI&amp;Agent</category><pubDate>Fri, 10 Jul 2026 03:51:19 GMT</pubDate></item><item><title><![CDATA[AI 编程杂谈｜为什么要避免 AI 黑盒带来的失控死循环 - 2]]></title><link>https://www.bliner.me/archives/ai-bian-cheng-za-tan-wei-shi-me-yao-bi-mian-ai-hei-he---2</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=AI%20%E7%BC%96%E7%A8%8B%E6%9D%82%E8%B0%88%EF%BD%9C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E9%81%BF%E5%85%8D%20AI%20%E9%BB%91%E7%9B%92%E5%B8%A6%E6%9D%A5%E7%9A%84%E5%A4%B1%E6%8E%A7%E6%AD%BB%E5%BE%AA%E7%8E%AF%20-%202&amp;url=/archives/ai-bian-cheng-za-tan-wei-shi-me-yao-bi-mian-ai-hei-he---2" width="1" height="1" alt="" style="opacity:0;">
<h1 style="" id="%E5%85%88%E6%8A%9B%E7%BB%93%E8%AE%BA">先抛结论</h1>
<blockquote>
 <p style="">AI 黑盒不只会让代码失控，而且会导致越来越依赖 AI</p>
</blockquote>
<p style=""></p>
<h1 style="" id="%E4%BB%A3%E7%A0%81%E5%A4%B1%E6%8E%A7">代码失控</h1>
<p style="">AI 时代来的轰轰烈烈，传统的程序员难免受到冲击。网络上一些「不用学编程，就能写程序」的口号也层出不穷，AI 确实在某些层面能达到真正的c，真的能用，能达到预期。但是对这些「产物」的掌控力呢？</p>
<p style=""></p>
<blockquote>
 <p style="">AI，省力，但不省功</p>
</blockquote>
<p style="">这些 Vibe Coding 的产物，没有在项目初期就规划软件工程和模式，甚至我还见过在一个 py 文件里写8000行代码的例子。这些「产物」能用吗？当然能用，从一个程序员角度，你能解释其一二吗？不能，因为我只操作 AI，AI 去操作了8000行的 py，解释不了。</p>
<p style="">AI 的黑盒产物，让代码越来越失控，而这种失控，就会导致更严重的问题。</p>
<p style=""></p>
<h1 style="" id="%E6%9B%B4%E5%8A%A0%E4%BE%9D%E8%B5%96ai">更加依赖AI</h1>
<p style="">有人说，代码没有失控啊，我控制AI，AI控制代码而已，最终还是我在主导的。如果这么说也没错，但是对 AI 的依赖就更强了。我不会提那种末日危机的论调，什么之后没有电、没有网怎么办之类的，AI 必然会成为基础设施的一层，去大大提高人类的生产力。</p>
<p style=""></p>
<blockquote>
 <p style="">AI 的能力上去了，而只能依赖 AI 的我们，能下下降了</p>
</blockquote>
<p style="">是我们不想写代码吗？不想「古法编程」了吗？不，而是我们面对代码开<code>无从下手</code> ，为什么？因为 AI 的写作习惯、编程能力都远超我们，他们的设计思路更我们也不相同。我们改不动了！</p>
<p style=""></p>
<h1 style="" id="%E8%B6%8A%E7%9C%81%E5%8A%9B%EF%BC%8C%E8%B6%8A%E8%B4%B9%E5%8A%9F">越省力，越费功</h1>
<p style="">最后就会导致一件事情，越让 AI 写，越费功，费的是我们自己的「武功」。我先抛出这个死循环</p>
<p style=""></p>
<blockquote>
 <p style="">AI 越来越像黑盒 -&gt; 我们越来越无从下手 -&gt; 只能越来越依赖 AI -&gt; AI 越来越像黑盒</p>
</blockquote>
<p style=""></p>
<p style="">这就导致了几个问题</p>
<p style=""></p>
<ol>
 <li>
  <p style="">AI 的「产物」越来越不可控</p>
 </li>
 <li>
  <p style="">我们的能力，越来越差</p>
 </li>
 <li>
  <p style="">「项目」风险越来越高</p>
 </li>
</ol>
<p style=""></p>
<h1 style="" id="%E5%80%A1%E5%AF%BC">倡导</h1>
<p style="">如果你是一个程序员，我还是倡导大家，先设计符合自己水平的设计规范，然后让 AI 严格遵守规范去开发。</p>
<p style="">达到 AI 写出的代码，你随时可以接手，你随时可控。</p>
<p style="">下一篇，我将详细说说理想中的 AI 参与的编程该是什么图景。</p>
<p style=""></p>
<p style=""></p>
<p style=""></p>
<p style=""></p>
<p style=""></p>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/ai-bian-cheng-za-tan-wei-shi-me-yao-bi-mian-ai-hei-he---2</guid><dc:creator>Bliner</dc:creator><enclosure url="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F%25E6%259C%25AA%25E5%2591%25BD%25E5%2590%258D%252015.png&amp;size=m" type="image/jpeg" length="85682"/><category>AI&amp;Agent</category><pubDate>Tue, 7 Jul 2026 02:38:01 GMT</pubDate></item><item><title><![CDATA[AI 编程杂谈｜利用 AI 的模仿能力避免黑盒 - 1]]></title><link>https://www.bliner.me/archives/ai-za-tan-2026nian-ai-bian-cheng-de-neng-li-ti-gan-fen-xiang---1</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=AI%20%E7%BC%96%E7%A8%8B%E6%9D%82%E8%B0%88%EF%BD%9C%E5%88%A9%E7%94%A8%20AI%20%E7%9A%84%E6%A8%A1%E4%BB%BF%E8%83%BD%E5%8A%9B%E9%81%BF%E5%85%8D%E9%BB%91%E7%9B%92%20-%201&amp;url=/archives/ai-za-tan-2026nian-ai-bian-cheng-de-neng-li-ti-gan-fen-xiang---1" width="1" height="1" alt="" style="opacity:0;">
<h1 style="" id="ai-%E7%BC%96%E7%A8%8B%E6%9D%82%E8%B0%88%E5%BC%80%E7%AF%87">AI 编程杂谈开篇</h1>
<p style="">开启一个新的系列文章，分享我在使用 AI 时的一些主观感受，主要聚焦在编程方面。</p>
<p style="">这是开篇，我不想写太长，只想一次一个主题地分享我的使用体会，也算是跟大家交流经验。毕竟 AI 从 2025 年开始就发展飞快，无论是 Seedance 的视频生成、Image 2 的图片生成，还是 DeepSeek V4、GLM 5.2、GPT-5.5 和 Fable 5 的出现，都大大提升了人们的效率。</p>
<p style="">说不准这杂谈，在几年后就变成了考古文物——古法 AI 记录。</p>
<p style=""></p>
<h1 style="" id="ai-%E7%9A%84%E6%A8%A1%E4%BB%BF%E8%83%BD%E5%8A%9B">AI 的模仿能力</h1>
<p style="">我想分享一个核心观点：<strong>AI 的模仿能力</strong>。</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>优先利用 AI 的模仿能力，再让其进行创造。</strong></p>
</blockquote>
<p style="">为什么我会这么说？因为我最近发现，如果你直接抛出一个需求给 AI，从 AI 的视角来看，可能有无数的解法——有高级/低级之分，有从架构考虑的，也有从快速迭代考虑的。它该以哪个为基准？如果用户没有明确的指示，AI 就会自己提炼和体会。小项目它可能不会用复杂的解法，但这样就难以控制，逐渐地，代码会变成黑盒。</p>
<p style=""></p>
<h1 style="" id="%E5%88%A9%E7%94%A8%E6%A8%A1%E4%BB%BF%E8%83%BD%E5%8A%9B">利用模仿能力</h1>
<p style="">我先抛出观点：如果 AI 的能力足够强，那它就能完全理解你写的代码是什么水平、项目是什么层次、你的写作特点和习惯是什么。</p>
<p style="">所以，我们就要借此利用它的模仿能力，即——</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>根据现有项目，去总结习惯。</strong></p>
</blockquote>
<p style=""></p>
<p style="">也就是先提供自己的真实项目，让 AI 自己去理解和抽象出你的代码习惯、写作特点，然后让 AI 以此为基准，进行后续开发。</p>
<p style=""></p>
<h1 style="" id="%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%88%A9%E7%94%A8%E6%A8%A1%E4%BB%BF%E8%83%BD%E5%8A%9B">为什么要利用模仿能力</h1>
<p style="">理由很简单：<strong>避免黑盒</strong>。如果你还想让代码有长久的生命力，而不是一堆屎山，那就一定要避免黑盒。</p>
<p style="">这里的黑盒不一定是所谓的复杂，它包括——</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>你看不懂的思路、你不常用的语法、你不熟悉的领域。</strong></p>
</blockquote>
<p style=""></p>
<p style="">这些其实都是黑盒，它们会让你失去对代码的掌控，让代码失去生命力。</p>
<p style=""></p>
<h1 style="" id="%E6%80%BB%E7%BB%93">总结</h1>
<p style="">2026 年，我发现 AI 的能力已经很强，对代码的理解非常到位。所以我提出：</p>
<p style=""></p>
<ol>
 <li>
  <p style=""><strong>要利用这种理解能力</strong></p>
 </li>
 <li>
  <p style=""><strong>抽象出自己的设计风格</strong></p>
 </li>
 <li>
  <p style=""><strong>在自己风格的基础上让 AI 进行开发</strong></p>
 </li>
 <li>
  <p style=""><strong>从而避免黑盒的出现。</strong></p>
 </li>
</ol>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/ai-za-tan-2026nian-ai-bian-cheng-de-neng-li-ti-gan-fen-xiang---1</guid><dc:creator>Bliner</dc:creator><enclosure url="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F%25E6%259C%25AA%25E5%2591%25BD%25E5%2590%258D%252015.png&amp;size=m" type="image/jpeg" length="85682"/><category>AI&amp;Agent</category><pubDate>Thu, 2 Jul 2026 05:57:03 GMT</pubDate></item><item><title><![CDATA[深度睡眠的体感分享]]></title><link>https://www.bliner.me/archives/shen-du-shui-mian-de-ti-gan-fen-xiang</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%B7%B1%E5%BA%A6%E7%9D%A1%E7%9C%A0%E7%9A%84%E4%BD%93%E6%84%9F%E5%88%86%E4%BA%AB&amp;url=/archives/shen-du-shui-mian-de-ti-gan-fen-xiang" width="1" height="1" alt="" style="opacity:0;">
<h1 style="" id="%E6%9C%80%E8%BF%91%E7%9D%A1%E7%9C%A0">最近睡眠</h1>
<p style="">最近睡得时间很短（6小时），但是深度睡眠非常足，每天都是60～90分钟，快速眼动30～50分钟</p>
<p style=""></p>
<h1 style="" id="%E6%B7%B1%E5%BA%A6%E7%9D%A1%E7%9C%A0">深度睡眠</h1>
<p style="">深度睡眠充足之后的感觉是</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>精力十足、注意力集中</strong></p>
</blockquote>
<p style="">特别是解决复杂的代码问题，能更多的专注在多个上下文思维链里面</p>
<p style=""></p>
<h1 style="" id="%E5%BF%AB%E9%80%9F%E5%8A%A8%E7%9C%BC">快速动眼</h1>
<p style="">快速动眼睡眠充足之后</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>对前一天的复杂逻辑的理解突然深入了、开窍了</strong></p>
</blockquote>
<p style=""></p>
<h1 style="" id="ai%E5%88%86%E6%9E%90">AI分析</h1>
<p style="">其实 AI 也给了我差不多的解释</p>
<p style=""></p>
<figure style="align-items: center; display: flex; flex-direction: column" data-content-type="image">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F7b93cdd54a4a0a55f2465e2e9ef927fd.jpg&amp;size=m" width="652px">
</figure>
<p style=""></p>
<p style=""></p>
<h1 style="" id="%E6%80%9D%E8%80%83">思考</h1>
<p style="">其实最近睡得总时长不是很够，当然我也知道8小时睡眠不是针对所有人，但是针对我的平均时长来说，不是很足，不过我的精神状态依旧很好，原因归结于深度睡眠和快速动眼睡眠的高质量。</p>
<p style=""></p>
<blockquote>
 <p style="">下一步我可能会进一步总结经验，看看该如何保持高质量的睡眠，而不是高时长的睡眠。</p>
</blockquote>
<p style=""></p>
<p style="">与大家分享。</p>]]></description><guid isPermaLink="false">/archives/shen-du-shui-mian-de-ti-gan-fen-xiang</guid><dc:creator>Bliner</dc:creator><category>运动&amp;健康</category><pubDate>Wed, 24 Jun 2026 02:11:30 GMT</pubDate></item><item><title><![CDATA[正在让 AI 帮我批量删除之前 Coding 的复杂泛型，保留一些自主权 ]]></title><link>https://www.bliner.me/archives/zheng-zai-rang-ai-bang-wo-pi-liang-shan-chu-zhi-qian-coding-de-fu-za-fan-xing-bao-liu-yi-xie-zi-zhu-quan</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%AD%A3%E5%9C%A8%E8%AE%A9%20AI%20%E5%B8%AE%E6%88%91%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4%E4%B9%8B%E5%89%8D%20Coding%20%E7%9A%84%E5%A4%8D%E6%9D%82%E6%B3%9B%E5%9E%8B%EF%BC%8C%E4%BF%9D%E7%95%99%E4%B8%80%E4%BA%9B%E8%87%AA%E4%B8%BB%E6%9D%83%20&amp;url=/archives/zheng-zai-rang-ai-bang-wo-pi-liang-shan-chu-zhi-qian-coding-de-fu-za-fan-xing-bao-liu-yi-xie-zi-zhu-quan" width="1" height="1" alt="" style="opacity:0;">
<p style="">之前设计的“太好了”...AI 写了一堆复杂泛型，我看起来头都疼。</p>
<p style="">又不是服务端，所以前端只留了一些基础类型，不想搞得太复杂。</p>
<figure data-content-type="image" style="display: flex; flex-direction: column;">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fcdn3.ldstatic.com%2Foriginal%2F4X%2F1%2Fa%2F4%2F1a4e90188b2ba8665b1e044731cb34e1b33b3025.png&amp;size=m" width="512px">
</figure>
<p style="">我个人还是想对代码保留一些自主权，不能搞到最后，自己不写代码，也看不懂代码...</p>
<p style="">我还是偏向于设计一些设计规范，然后让 AI 在规范内编码。</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>最起码我自己还能找到某一部分代码在哪，要不然纯黑盒了...</strong></p>
</blockquote>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/zheng-zai-rang-ai-bang-wo-pi-liang-shan-chu-zhi-qian-coding-de-fu-za-fan-xing-bao-liu-yi-xie-zi-zhu-quan</guid><dc:creator>Bliner</dc:creator><category>软件&amp;技术</category><pubDate>Sun, 21 Jun 2026 09:29:24 GMT</pubDate></item><item><title><![CDATA[Mac 上 Codex App 点击 Pet 返回窗口，输入框无法重新聚焦的问题与暂时解法]]></title><link>https://www.bliner.me/archives/mac-shang-codex-app-dian-ji-pet-fan-hui-chuang-kou-shu-ru-kuang-wu-fa-chong-xin-ju-jiao-de-wen-ti-yu-zan-shi-jie-fa</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=Mac%20%E4%B8%8A%20Codex%20App%20%E7%82%B9%E5%87%BB%20Pet%20%E8%BF%94%E5%9B%9E%E7%AA%97%E5%8F%A3%EF%BC%8C%E8%BE%93%E5%85%A5%E6%A1%86%E6%97%A0%E6%B3%95%E9%87%8D%E6%96%B0%E8%81%9A%E7%84%A6%E7%9A%84%E9%97%AE%E9%A2%98%E4%B8%8E%E6%9A%82%E6%97%B6%E8%A7%A3%E6%B3%95&amp;url=/archives/mac-shang-codex-app-dian-ji-pet-fan-hui-chuang-kou-shu-ru-kuang-wu-fa-chong-xin-ju-jiao-de-wen-ti-yu-zan-shi-jie-fa" width="1" height="1" alt="" style="opacity:0;">
<p style="">我经常跟 AI 聊完之后，就 水一下论坛 或者 切换到 IDE 去 Review。</p>
<p style="">Pet 能一直置顶挺不错的，我就偶尔扫一眼状态。</p>
<p style="">当 Pet 那显示绿色对号了，我就点 Pet 返回 CodexApp 窗口。</p>
<p style=""><strong>但是输入框的光标（闪动竖线）不显示，有时候无法输入文字，只能重启。</strong></p>
<p style=""></p>
<blockquote>
 <p style="">最近发现在 Codex 界面，<strong>再点一下 Pet，就能恢复正常，</strong> 光标能正常显示。</p>
</blockquote>
<p style="">就是水论坛切换窗口时，发现的小问题与临时解决方案，供大家分享。</p>
<figure data-content-type="image" style="display: flex; flex-direction: column;">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage-erch.png&amp;size=m" alt="image-erch.png" width="1672px">
</figure>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/mac-shang-codex-app-dian-ji-pet-fan-hui-chuang-kou-shu-ru-kuang-wu-fa-chong-xin-ju-jiao-de-wen-ti-yu-zan-shi-jie-fa</guid><dc:creator>Bliner</dc:creator><category>软件&amp;技术</category><pubDate>Sat, 20 Jun 2026 15:01:35 GMT</pubDate></item><item><title><![CDATA[从等红灯到关于感恩的领悟]]></title><link>https://www.bliner.me/archives/guan-yu-gan-en-de-li-jie</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E4%BB%8E%E7%AD%89%E7%BA%A2%E7%81%AF%E5%88%B0%E5%85%B3%E4%BA%8E%E6%84%9F%E6%81%A9%E7%9A%84%E9%A2%86%E6%82%9F&amp;url=/archives/guan-yu-gan-en-de-li-jie" width="1" height="1" alt="" style="opacity:0;">
<h1 style="" id="%E4%BB%A5%E5%89%8D%E7%9A%84%E7%90%86%E8%A7%A3">以前的理解</h1>
<p style="">以前对感恩的理解还比较肤浅，就是你对我好，我也对你好。是对别人给予的帮助的一种回应，再说说直白一点，就是表达自己的感谢之情，心里少一些亏欠（因为别人帮助了自己嘛）。也可以说是感激之情。</p>
<p style=""></p>
<h1 style="" id="%E4%B8%80%E6%AC%A1%E6%84%9F%E6%82%9F">一次感悟</h1>
<p style="">最近突<code>悟出</code>一些东西，是在我开车等红灯的时候。家附近的一家商场，出了停车场就是红绿灯，经常会遇到红灯的情况，比较烦躁。感觉10次得有8次都是红灯，每次等红灯的时候脑子只会蹦出一个句<code>怎么总是红灯</code>🔴。</p>
<p style="">突然有一次，我开车出来，下着小雨，我又着急回家。发现是绿灯🟢，开心之情难以言表。</p>
<p style="">回去的路上我突然有所感悟，路口还是那个路口，红绿灯的规律也没有变化，为什么今天难得的开心？</p>
<p style="">是单纯的因为着急回去，结果是绿灯而开心吗？好像并单纯是这样。</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>我发现： </strong>每次在那个路口，我都在强化自己的默认行为网络，加深对这个红绿灯的讨厌，不停的在心里说<code>一到这里就红灯</code> ！！！</p>
</blockquote>
<p style=""></p>
<p style="">我想打破这个默认行为，所以在这一次🌧️着急回家却遇到绿灯时，我告诉自己<code>这次真幸运</code> ，加深遇到绿灯时的记忆和印象。</p>
<p style=""></p>
<h1 style="" id="%E4%B9%8B%E5%90%8E">之后</h1>
<p style="">那个路口的红灯🔴还是很多，但是我的心态不一样了，从之前<code>怎么又是红灯？</code> 到现在<code>之前好几次是绿灯</code> 甚至我现在到这个路口已经什么都不想了，就是一个普通的路口而已。</p>
<p style=""></p>
<p style="">我认为唯一的变化是我主动打破了那个默认行为，不再重复的加深印象，反而在每次绿灯的时候，加深印象<code>对绿灯表示感恩。</code></p>
<p style=""></p>
<h1 style="" id="%E6%84%9F%E6%81%A9">感恩</h1>
<p style="">我突然意识到，这次不单单是打破一个负反馈的认知，而是发现了感恩这件事，你越去感恩一些平凡的小事，你就会打破之前糟糕的认识。世界还是这个世界，人还是那些人，但是主动的去感恩，重复加深对美好的印象，心情或者说心境，真的变了。</p>
<p style=""></p>
<blockquote>
 <p style="">感恩一切遇到的好事，不管是大事还是小情。</p>
</blockquote>
<p style=""></p>
<p style="">与大家分享。</p>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/guan-yu-gan-en-de-li-jie</guid><dc:creator>Bliner</dc:creator><enclosure url="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fganen.png&amp;size=m" type="image/jpeg" length="102070"/><category>成长&amp;感悟</category><pubDate>Wed, 17 Jun 2026 06:44:14 GMT</pubDate></item><item><title><![CDATA[Halo 离线安装升级指南]]></title><link>https://www.bliner.me/archives/halo-chi-xian-an-zhuang-sheng-ji-zhi-nan</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=Halo%20%E7%A6%BB%E7%BA%BF%E5%AE%89%E8%A3%85%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97&amp;url=/archives/halo-chi-xian-an-zhuang-sheng-ji-zhi-nan" width="1" height="1" alt="" style="opacity:0;">
<h1 style="" id="%E6%83%85%E5%86%B5">情况</h1>
<p style="">根据<a href="https://docs.halo.run/getting-started/install/offline">官方教程</a>，使用离线安装脚本进行安装。</p>
<p style="">安装后实际上在 <code>/opt/halo</code> 下运行的一个 Docker 的实例，实际是从 Nginx 反向代理出去的。</p>
<p style="">如果你和我的情况，那么就可以往后看（我使用的是 linux 系统）</p>
<p style=""></p>
<h1 style="" id="%E6%8B%89%E5%8F%96%E6%9C%80%E6%96%B0%E7%9A%84-halo-%E5%BA%94%E7%94%A8">拉取最新的 halo 应用</h1>
<pre><code class="language-shell">docker pull registry.fit2cloud.com/halo/halo-pro:2.24.2</code></pre>
<p style="">这里的版本号是从下面的网址获取的，包括仓库地址</p>
<p style=""><a href="https://releases.halo.run/releases/">https://releases.halo.run/releases/</a></p>
<figure style="align-items: start; display: flex; flex-direction: column" data-content-type="image">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage.png&amp;size=m" width="1278px">
</figure>
<p style="text-align: center">如图所示，就是最新的镜像地址</p>
<p style="text-align: center"></p>
<figure style="align-items: center; display: flex; flex-direction: column" data-content-type="image">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage-ceax.png&amp;size=m" width="1196px">
</figure>
<p style="text-align: center">拉取成功后如上图所示</p>
<h1 style="" id="%E4%BF%AE%E6%94%B9%E6%9C%AC%E5%9C%B0docker-compose.yaml">修改本地docker-compose.yaml</h1>
<p style="">进入/opt/halo 目录，如果你是别的目录就进入你自定义的目录</p>
<p style="">大概率会看到一个Data 目录，一个install.log 还有一个docker-compose.yaml</p>
<p style="">我们主要改这个docker-compose.yaml</p>
<p style="">首先把我们docker-compose.yaml的第一个 image 改成上面那个 Docker 地址，即你 pull 的地址</p>
<p style=""></p>
<pre><code class="language-yaml">services:
  halo:
    image: registry.fit2cloud.com/halo/halo-pro:${HALO_VERSION}</code></pre>
<p style="">改成下面的，注意跟上面拉取的仓库路径是否相同</p>
<pre><code class="language-shell">services:
  halo:
    image: registry.fit2cloud.com/halo/halo-pro:2.24.2</code></pre>
<p style=""></p>
<p style="">上面的 2.24.2 就是版本号</p>
<p style=""></p>
<blockquote>
 <p style="">${HALO_VERSION} 不用管，这个对应的是隐藏文件<code>.env</code> 的版本号，有能力的直接改 env 文件，切记要检查你的registry 仓库是否一样。</p>
</blockquote>
<p style=""></p>
<h1 style="" id="%E5%81%9C%E6%AD%A2%E5%B9%B6%E6%9B%B4%E6%96%B0">停止并更新</h1>
<p style="">停止当前运行的 Halo 实例</p>
<pre><code class="language-docker"> 先 cd 切换到 docker-compose.yaml 所在的目录

 先查看当前运行的实例列表
 docker ps
 然后记住 CONTAINER ID 

 然后停止即可
 docker stop 753cf24e3e12

 然后更新并开启容器
 docker-compose up -d</code></pre>
<p style=""></p>
<p style="">正常会看到下图所示，我是 PG 数据库，所以显示 pg，如果你是 mysql，则显示 mysql，启动后直接刷新博客即可</p>
<figure style="align-items: start; display: flex; flex-direction: column" data-content-type="image">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage-bho6.png&amp;size=m" width="1264px">
</figure>
<p style=""></p>
<h1 style="" id="%E6%A3%80%E6%9F%A5">检查</h1>
<figure style="align-items: start; display: flex; flex-direction: column" data-content-type="image">
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2Fimage-hrng.png&amp;size=m" width="1042px">
</figure>
<p style="">进入 console/overview 查看概览，即可看到已经升级到最新的 2.24.2 系统了</p>
<p style=""></p>
<blockquote>
 <p style=""><strong>难点</strong></p>
 <ol>
  <li>
   <p style="">要先拉取官方提供的 Halo 的 docker image</p>
  </li>
  <li>
   <p style="">然后修改 docker-compose.yaml 文件中的 image 与拉取的相同</p>
  </li>
  <li>
   <p style="">进入 halo 目录，先停止，再<code>docker-compose up -d</code>即可</p>
  </li>
 </ol>
</blockquote>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/halo-chi-xian-an-zhuang-sheng-ji-zhi-nan</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Thu, 11 Jun 2026 15:11:56 GMT</pubDate></item><item><title><![CDATA[AI ｜ 代码 Review 变高级了？还是难以理解]]></title><link>https://www.bliner.me/archives/ai-dai-ma-review-bian-gao-ji-liao-huan-shi-nan-yi-li-jie</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=AI%20%EF%BD%9C%20%E4%BB%A3%E7%A0%81%20Review%20%E5%8F%98%E9%AB%98%E7%BA%A7%E4%BA%86%EF%BC%9F%E8%BF%98%E6%98%AF%E9%9A%BE%E4%BB%A5%E7%90%86%E8%A7%A3&amp;url=/archives/ai-dai-ma-review-bian-gao-ji-liao-huan-shi-nan-yi-li-jie" width="1" height="1" alt="" style="opacity:0;">
<p style="">最近用 AI 来改造代码和框架，我在 Review 的时候，发现自己<code>屎山</code>变高级了，或者说<code>屎山</code>上多了一块扎眼的金子。</p>
<p style=""></p>
<p style="">本来是非常简单、没有太多复用、只有一两个页面在用的逻辑，现在不光要写Schema 配置、设计字典、抽离业务函数、还要有一个函数做校验、解析字典并吐出最终规则。</p>
<p style=""></p>
<p style="">在 Review 的时候看的云里雾里，<strong>写的真好，</strong>但好像不适合我，把清爽的屎山镀上了金，即不清爽了但却还是屎山。</p>
<p style=""></p>
<blockquote>
 <p style="">我在 Review 的时候就在想，是变高级了？还是更难以理解了。看来在初期让 AI 充分的理解项目风格、包括自己的代码习惯都需要严格的写到 MD 里面去，否则真的会跑偏。</p>
</blockquote>
<p style=""></p>]]></description><guid isPermaLink="false">/archives/ai-dai-ma-review-bian-gao-ji-liao-huan-shi-nan-yi-li-jie</guid><dc:creator>Bliner</dc:creator><enclosure url="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F%25E6%259C%25AA%25E5%2591%25BD%25E5%2590%258D%252014-zbh5.png&amp;size=m" type="image/jpeg" length="349377"/><category>开发&amp;调优</category><pubDate>Thu, 11 Jun 2026 08:17:54 GMT</pubDate></item><item><title><![CDATA[2026年， Halo 新的开始]]></title><link>https://www.bliner.me/archives/2026nian-xin-de-kai-shi</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=2026%E5%B9%B4%EF%BC%8C%20Halo%20%E6%96%B0%E7%9A%84%E5%BC%80%E5%A7%8B&amp;url=/archives/2026nian-xin-de-kai-shi" width="1" height="1" alt="" style="opacity:0;">
<p style="">从上次写博客到现在好久了，Hexo 博客系统好像也不这么流行了，其实主要是没有写作后台，2026年在 AI 的帮助下，从新迁移这套主题到更流行的 Halo 博客系统，希望能够继续博客的写作。</p>
<p style=""></p>
<p style="">不过从今年起，这个博客可能不只有精雕细琢的大作，也有一些碎碎念、吐槽以及个人观点。先记录下来，比什么都重要。18年到26年，转瞬即逝...</p>
<p style=""></p>
<p style="">岁月不饶人，我也没过饶岁月。2026 加油 💪 ！</p>]]></description><guid isPermaLink="false">/archives/2026nian-xin-de-kai-shi</guid><dc:creator>Bliner</dc:creator><enclosure url="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F4A8D3B00-A250-489A-81AC-4AB3C9779C75.jpg&amp;size=m" type="image/jpeg" length="54801"/><category>成长&amp;感悟</category><pubDate>Thu, 11 Jun 2026 02:59:00 GMT</pubDate></item><item><title><![CDATA[数据结构之图-创建邻接矩阵图结构-学习笔记-65]]></title><link>https://www.bliner.me/archives/Data_structure_course_065_graph_create_graph</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E5%9B%BE-%E5%88%9B%E5%BB%BA%E9%82%BB%E6%8E%A5%E7%9F%A9%E9%98%B5%E5%9B%BE%E7%BB%93%E6%9E%84-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-65&amp;url=/archives/Data_structure_course_065_graph_create_graph" width="1" height="1" alt="" style="opacity:0;">
<h1 id="%E5%BC%95%E5%85%A5">引入</h1>
<p>我们知道如何构建一个图的数据结构，那么现在，我们看看如何根据一棵图的图形，创建一张图到内存中去。</p>
<h1 id="%E5%88%9B%E5%BB%BA%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84">创建数据结构</h1>
<pre><code class="hljs language-c"><span class="hljs-meta">#<span class="hljs-keyword">define</span> MAX_VEX_NUM 50  <span class="hljs-comment">//最大的容量暂定为50</span></span>
<span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> {</span>DG, UDG} GraphType;  <span class="hljs-comment">//选择有向图还是无向图</span>
<span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> {</span>
    <span class="hljs-type">char</span> vexs[MAX_VEX_NUM];  <span class="hljs-comment">//一维数组存储顶点</span>
    <span class="hljs-type">int</span> arcs[MAX_VEX_NUM][MAX_VEX_NUM];   <span class="hljs-comment">//二维数组（邻接矩阵）存储边</span>
    <span class="hljs-type">int</span> vexnum, arcnum;  <span class="hljs-comment">//记录顶点的数量和边的数量，等下用作循环判断条件</span>
    GraphType type;  <span class="hljs-comment">//记录图得类型</span>
} MGraph;
</code></pre>
<p>数据结构中</p>
<ul>
 <li>记录顶点的数量和边的数量，等下用作循环判断条件</li>
 <li>记录图得类型，等下用于写入矩阵</li>
</ul>
<!-- more -->
<h2 id="%E8%8E%B7%E5%8F%96%E6%95%B0%E6%8D%AE">获取数据</h2>
<pre><code class="hljs language-c"><span class="hljs-type">void</span> <span class="hljs-title function_">create_MG</span><span class="hljs-params">(MGraph *MG)</span>
{
    
    <span class="hljs-type">int</span> type;  <span class="hljs-comment">//存储图得类型</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入图的类型，有向图（输入0）无向图（输入1） :"</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%d"</span>, &amp;type);
    <span class="hljs-comment">//如果是0，那就是有向图，如果是1那就是无向图</span>
    <span class="hljs-keyword">if</span> (type == <span class="hljs-number">0</span>)
        MG-&gt;type = DG;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == <span class="hljs-number">1</span>)
        MG-&gt;type = UDG;
    <span class="hljs-keyword">else</span>
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入正确的图类型，有向图（输入0）无向图（输入1）"</span>);
        <span class="hljs-keyword">return</span>;
    }
    
    <span class="hljs-comment">//获取数值</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入顶点个数:"</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%d"</span>, &amp;MG-&gt;vexnum);  <span class="hljs-comment">//数值赋值给 MG 的 vexnum</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入边个数："</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%d"</span>, &amp;MG-&gt;arcnum);
    getchar();  <span class="hljs-comment">//接收最后那个回车</span>
    
    <span class="hljs-type">int</span> i;
    <span class="hljs-type">int</span> v1, v2;
    <span class="hljs-comment">//有多少个顶点，就输入多少次</span>
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>; i &lt;= MG-&gt;vexnum; i++)
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入第%d个顶点的值:"</span>, i);
        <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%c"</span>, &amp;MG-&gt;vexs[i]);
        getchar();
    }
    <span class="hljs-comment">//以上就完成了所有信息的获取</span>
</code></pre>
<p>我们一部分一部分的讲</p>
<ul>
 <li>先输入1或0判断图类型，然后存到结构体中</li>
 <li>然后输入顶点数和边树，方便下面判断循环次数</li>
 <li>接着根据顶点数，接收每个顶点得值</li>
 <li>所有数据获取完毕</li>
</ul>
<h2 id="%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9F%A9%E9%98%B5">初始化矩阵</h2>
<pre><code class="hljs language-c"><span class="hljs-comment">//初始化邻接矩阵，双层循环将二维数组都填充为0</span>
   <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>; i &lt;= MG-&gt;vexnum; i++)
   {
       <span class="hljs-keyword">for</span> (j = <span class="hljs-number">1</span>; j &lt;= MG-&gt;vexnum; j++)
       {
           MG-&gt;arcs[i][j] = <span class="hljs-number">0</span>;
       }
   }
</code></pre>
<p>这里我们先把矩阵创建出来</p>
<ul>
 <li>判断条件就是顶点的个数，有多少顶点创建多大的矩阵</li>
 <li>矩阵中默认的值为0</li>
</ul>
<h2 id="%E5%9C%A8%E7%9F%A9%E9%98%B5%E4%B8%AD%E5%AE%9A%E4%BD%8D">在矩阵中定位</h2>
<pre><code class="hljs language-c"><span class="hljs-comment">//定位</span>
<span class="hljs-comment">// 输入矩阵指针和顶点得值，判断在一维数组中这是第几号，并返回</span>
<span class="hljs-type">int</span> <span class="hljs-title function_">getIndexOfVexs</span><span class="hljs-params">(<span class="hljs-type">char</span> vex, MGraph *MG)</span>
{
    <span class="hljs-type">int</span> i;
    <span class="hljs-comment">//有多少结点循环多少次</span>
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>; i &lt;= MG-&gt;vexnum; i++)
    {
    <span class="hljs-comment">//如果值等于输入的值，那么就把在一维数组中的位置返回</span>
        <span class="hljs-keyword">if</span> (MG-&gt;vexs[i] == vex)
        {
            <span class="hljs-keyword">return</span> i;
        }
    }
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>这个定位的函数，主要是</p>
<ul>
 <li>将用户输入的值，在一维数组中找到它的位置</li>
 <li>然后将这个位置返回</li>
 <li>我们就能通过这个位置在矩阵中定位到它了</li>
</ul>
<h2 id="%E5%A4%84%E7%90%86%E8%BE%B9%E7%9A%84%E4%BF%A1%E6%81%AF">处理边的信息</h2>
<pre><code class="hljs language-c"><span class="hljs-comment">//输入边的信息，建立邻接矩阵，有多少边执行多少次</span>
   <span class="hljs-type">char</span> c1, c2;
   <span class="hljs-type">int</span> j, k;
   <span class="hljs-keyword">for</span> (k = <span class="hljs-number">1</span>; k &lt;= MG-&gt;arcnum; k++) {
       <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入第%d个边: "</span>, k);
       <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%c %c"</span>, &amp;c1, &amp;c2);
       <span class="hljs-comment">//利用上面的定位函数，找到输入的顶点在一维数组中的位置</span>
       v1 = getIndexOfVexs(c1, MG);
       v2 = getIndexOfVexs(c2, MG);
       
       <span class="hljs-keyword">if</span> (MG-&gt;type == <span class="hljs-number">1</span>)  <span class="hljs-comment">//如果是y无向图，则对称矩阵，把对称位置上的值同时赋值为1</span>
           MG-&gt;arcs[v1][v2] = MG-&gt;arcs[v2][v1] = <span class="hljs-number">1</span>;
       <span class="hljs-keyword">else</span>  <span class="hljs-comment">//如果是有向图，则只在指定位置赋值。</span>
           MG-&gt;arcs[v1][v2] = <span class="hljs-number">1</span>;
       getchar();
   }
</code></pre>
<p>有多少个顶点就循环多少次</p>
<ul>
 <li>接收到构成边的两个顶点</li>
 <li>然后利用上面的定位函数，返回在一维数组中的位置</li>
 <li>接着判断图得类型</li>
 <li>无向图，那么矩阵对称，则在对称位置同时赋值 1</li>
 <li>有向图，矩阵不对称，所以只在对应位置赋值 1</li>
</ul>
<h1 id="%E6%80%BB%E4%BB%A3%E7%A0%81">总代码</h1>
<pre><code class="hljs language-c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;stdlib.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-keyword">define</span> MAX 50</span>

<span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">enum</span>{</span>DG,UDG} GraphType;

<span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> {</span>
    <span class="hljs-type">char</span> vex[MAX];  <span class="hljs-comment">//定义一维数组存储顶点</span>
    <span class="hljs-type">int</span> arcs[MAX][MAX];  <span class="hljs-comment">//定义二维数组存储边</span>
    <span class="hljs-type">int</span> vexnum,arcnum;  <span class="hljs-comment">//存储顶点和边的数量</span>
    GraphType type;  <span class="hljs-comment">//存储图的类型</span>
}Graph;

<span class="hljs-type">int</span> <span class="hljs-title function_">position</span><span class="hljs-params">(<span class="hljs-type">char</span> c , Graph *G)</span>{
    <span class="hljs-type">int</span> i;
    <span class="hljs-keyword">for</span>(i=<span class="hljs-number">1</span>;i&lt;=G-&gt;vexnum;i++){
        <span class="hljs-keyword">if</span>(G-&gt;vex[i]==c){
            <span class="hljs-keyword">return</span> i;
        }
    }
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}

<span class="hljs-type">void</span> <span class="hljs-title function_">Create</span><span class="hljs-params">(Graph * G)</span>{
    <span class="hljs-comment">//获取图的类型</span>
    <span class="hljs-type">int</span> type;
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入图的类型，有向图输入1，无向图输入0:"</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%d"</span>,&amp;type);
    <span class="hljs-keyword">if</span>(type==<span class="hljs-number">1</span>){
        G-&gt;type=DG;
    }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(type==<span class="hljs-number">0</span>){
        G-&gt;type=UDG;
    }<span class="hljs-keyword">else</span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"输入的类型不正确！\n"</span>);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-comment">//获取图得顶点数和边数</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"图有几个顶点:"</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%d"</span>,&amp;G-&gt;vexnum);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"图有几条边:"</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%d"</span>,&amp;G-&gt;arcnum);
    getchar();
    <span class="hljs-comment">//获得每个顶点得值</span>
    
    <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> k=<span class="hljs-number">1</span>;k&lt;=G-&gt;vexnum;k++){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入第%d个结点的值："</span>,k);
        <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%s"</span>,&amp;G-&gt;vex[k]);
        getchar();
    }
    <span class="hljs-comment">//值全部获得完毕</span>
    
    <span class="hljs-comment">//矩阵初始化</span>
    <span class="hljs-type">int</span> i,j;
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>; i &lt;= G-&gt;vexnum; i++)
    {
        <span class="hljs-keyword">for</span> (j = <span class="hljs-number">1</span>; j &lt;= G-&gt;vexnum; j++)
        {
            G-&gt;arcs[i][j] = <span class="hljs-number">0</span>;
        }
    }
    <span class="hljs-comment">//有多少个结点循环多少次</span>
    <span class="hljs-type">char</span> V1,V2;
    <span class="hljs-type">int</span> V1p,V2p;
    <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> l=<span class="hljs-number">1</span>;l&lt;=G-&gt;arcnum;l++){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输第%d个边的信息："</span>,l);
        <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%c %c"</span>,&amp;V1,&amp;V2);
        V1p=position(V1,G);
        V2p=position(V2,G);
        
        <span class="hljs-keyword">if</span>(G-&gt;type==UDG){
            G-&gt;arcs[V1p][V2p]=G-&gt;arcs[V2p][V1p]=<span class="hljs-number">1</span>;
        }<span class="hljs-keyword">else</span>{
            G-&gt;arcs[V1p][V2p]=<span class="hljs-number">1</span>;
        }
        getchar();
    }
}

<span class="hljs-type">void</span> <span class="hljs-title function_">print_MG</span><span class="hljs-params">(Graph MG)</span>{
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"-------------------------------\n"</span>);
    <span class="hljs-type">int</span> i, j;
    <span class="hljs-keyword">if</span>(MG.type == DG)
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"图类型 : 有向图\n"</span>);
    }
    <span class="hljs-keyword">else</span>
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"图类型：无向图\n"</span>);
    }
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"图中的顶点有: %d 个\n"</span>,MG.vexnum);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"图中的边/弧有: %d 个\n"</span>,MG.arcnum);
    
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"顶点的集合:"</span>);
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>; i &lt;= MG.vexnum; i++){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%c "</span>, MG.vex[i]);
    }
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"\n"</span>);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"邻接矩阵:\n"</span>);
    
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>; i &lt;= MG.vexnum; i++)
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%c "</span>, MG.vex[i]);
        j = <span class="hljs-number">1</span>;
        <span class="hljs-keyword">for</span> (; j &lt; MG.vexnum; j++)
        {
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d "</span>, MG.arcs[i][j]);
        }
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d "</span>, MG.arcs[i][j]);
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"\n"</span>);
    }
}
<span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">()</span>
{
    Graph MG;
    Create(&amp;MG);
    print_MG(MG);
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-14-15447540206199.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<table>
 <thead>
  <tr>
   <th></th>
   <th>V0</th>
   <th>V1</th>
   <th>v2</th>
   <th>v3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>0</td>
   <td>1</td>
   <td>1</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
  <tr>
   <td>V2</td>
   <td>1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V3</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
 </tbody>
</table>
<p>我们将上面的图输入程序，我们用 a、b、c、d 代替v1、v2、v3、v4</p>
<blockquote>
 <p><strong>运行结果</strong>
  <br>
  请输入图的类型，有向图输入1，无向图输入0:0
  <br>
  图有几个顶点:4
  <br>
  图有几条边:5
  <br>
  请输入第1个结点的值：a
  <br>
  请输入第2个结点的值：b
  <br>
  请输入第3个结点的值：c
  <br>
  请输入第4个结点的值：d
  <br>
  请输第1个边的信息：a b
  <br>
  请输第2个边的信息：b c
  <br>
  请输第3个边的信息：c d
  <br>
  请输第4个边的信息：d a</p>
 <h2 id="%E8%AF%B7%E8%BE%93%E7%AC%AC5%E4%B8%AA%E8%BE%B9%E7%9A%84%E4%BF%A1%E6%81%AF%EF%BC%9Aa-c">请输第5个边的信息：a c</h2>
 <p>图类型：无向图
  <br>
  图中的顶点有: 4 个
  <br>
  图中的边/弧有: 5 个
  <br>
  顶点的集合:a b c d
  <br>
  邻接矩阵:
  <br>
  a 0 1 1 1
  <br>
  b 1 0 1 0
  <br>
  c 1 1 0 1
  <br>
  d 1 0 1 0</p>
</blockquote>
<p>运行结果同矩阵相同，成功！</p>
<h1 id="%E5%B0%BE%E5%B7%B4">尾巴</h1>
<p>这是我的个人学习笔记，主要是应付考研复习使用，充斥着一些吐槽和个人观点，并不严谨，欢迎大家参考、指正。</p>]]></description><guid isPermaLink="false">/archives/Data_structure_course_065_graph_create_graph</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Fri, 14 Dec 2018 08:25:39 GMT</pubDate></item><item><title><![CDATA[数据结构之图-图的存储结构-学习笔记-64]]></title><link>https://www.bliner.me/archives/Data_structure_course_064_graph_graph_storage_structure</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E5%9B%BE-%E5%9B%BE%E7%9A%84%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-64&amp;url=/archives/Data_structure_course_064_graph_graph_storage_structure" width="1" height="1" alt="" style="opacity:0;">
<h1 id="%E5%BC%95%E5%85%A5">引入</h1>
<p>学了那么多图的知识，是时候动手设计一下图的存储结构了，图跟线性表、树有那么大得差别，所以图的数据结构要复杂很多。</p>
<h1 id="%E6%80%9D%E8%80%83">思考</h1>
<p>我们先回忆一下线性表和树得存储结构</p>
<ul>
 <li>**线性表：**一对一的关系，用数组和链表就能很好的表示。</li>
 <li>**树：**一对多得关系，用数组和链表得特性结合在一起就可以很好的表示。</li>
</ul>
<p>那么图呢？</p>
<ul>
 <li>图上的任意一个顶点都可以是第一个顶点，谁开始都行。</li>
 <li>任意一个顶点的邻接点也不存在次序关系，多对多，大家都一样。</li>
</ul>
<p>我们观察下面的四张图
 <br>
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-14-15447533743006.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<!-- more -->
<p>这四张图形态各异，但是</p>
<ul>
 <li>各个结点的邻接点都相同</li>
 <li>边也都相同</li>
 <li>所以位置虽然不一样，但其实<code>都是一张图。</code></li>
</ul>
<p>那么该如何将图在内存中表示呢？</p>
<ul>
 <li>既然任意两个顶点都可能存在联系</li>
 <li>我们不能线性的表达数据元素之间得关系</li>
 <li>因为内存的物理位置也是线性的，而图的元素关系是平面的。</li>
 <li>既然线性关系不行，那用多重链表呢？可以！</li>
 <li>但会造成巨大的资源浪费，各个顶点得度数如果相差很大，就会造成很大的浪费。</li>
</ul>
<h1 id="%E8%A7%A3%E5%86%B3">解决</h1>
<p>想明白上面得问题，我们就来回答这个问题</p>
<ul>
 <li>图是由顶点和边两部分组成的，合在一起表示困难，我们分开表示就好了</li>
 <li>**顶点：**因为不分大小、主次，用一个简单的一维数组来存储就好</li>
 <li>**边、弧：**其实就是顶点和顶点之间得关系，一个二维数组来存储就好</li>
 <li>所以，我们使用<code>邻接矩阵方案</code>，撒花！</li>
</ul>
<h1 id="%E6%97%A0%E5%90%91%E5%9B%BE%E7%9A%84%E9%82%BB%E6%8E%A5%E7%9F%A9%E9%98%B5">无向图的邻接矩阵</h1>
<p>**图的邻接矩阵（Adjacency Matrix）：**存储方式是用两个数组来表示图。</p>
<ul>
 <li>一个一维数组存储图中得顶点信息</li>
 <li>一个二维数组（邻接矩阵）存储图中边、弧的信息</li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-14-15447540206199.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>我们试着来存放上面这个无向图，首先设计一个一维数组 vexs 存放顶点信息</p>
<table>
 <thead>
  <tr>
   <th>vexs0</th>
   <th>vexs1</th>
   <th>vexs2</th>
   <th>vexs3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>V1</td>
   <td>V2</td>
   <td>V3</td>
  </tr>
 </tbody>
</table>
<p>接着设计一个邻接矩阵（二维数组）arcs，存放边和边得信息</p>
<table>
 <thead>
  <tr>
   <th></th>
   <th>V0</th>
   <th>V1</th>
   <th>v2</th>
   <th>v3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>0</td>
   <td>1</td>
   <td>1</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
  <tr>
   <td>V2</td>
   <td>1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V3</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
 </tbody>
</table>
<p>因为是无向图，所以</p>
<ul>
 <li>无论是先行再列看（V0，V1）还是 先列再行看（V1，V0）都可以</li>
 <li>邻接矩阵存储得是边、弧，如果存在就写1，反之则写0</li>
 <li>这个邻接矩阵也是一个对称矩阵，因为这是一个无向图。</li>
</ul>
<h1 id="%E6%97%A0%E5%90%91%E5%9B%BE%E9%82%BB%E6%8E%A5%E7%9F%A9%E9%98%B5%E7%9A%84%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84">无向图邻接矩阵的存储结构</h1>
<p>我们设计这个存储结构时</p>
<ul>
 <li>设计两个数组</li>
 <li>顶点数组vertex[4]</li>
 <li>边数组 arc[4][4] 为对称矩阵</li>
 <li>边数组中，0表示顶点间不存在边，1表示顶点间存在边</li>
</ul>
<p>所谓对称矩阵，就是</p>
<ul>
 <li>N 阶矩阵的元满足</li>
 <li>a[i][j]=a[j]<a href="https://www.bliner.me/0%3C=i,j%3C=n">i</a></li>
 <li>也就是从矩阵的左上角到右下角为轴</li>
 <li>右上角得元与左下角相对应得元全都是相等的</li>
</ul>
<p>有了这个数据结构，我们就可以很轻松的知道</p>
<ul>
 <li>任意两个顶点之间是否存在边，0就是没边，1就是有边</li>
 <li>某个顶点的度，就是顶点 Vi 在邻接矩阵中第 i 行或 i 列的元素的和。</li>
 <li>还记得无向图顶点的度嘛？就是该顶点邻接的边的个数</li>
 <li>就是这一列或这一行，有多少个 1，加起来就是这个 Vi 的度</li>
 <li>最后一个就是求 Vi 顶点的所有邻接点</li>
 <li>就是将第 i 行元素扫描一遍，只要 arc[ i ][ j ]为1就是邻接点</li>
</ul>
<table>
 <thead>
  <tr>
   <th></th>
   <th>V0</th>
   <th>V1</th>
   <th>v2</th>
   <th>v3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>0</td>
   <td>1</td>
   <td>1</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
  <tr>
   <td>V2</td>
   <td>1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V3</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
 </tbody>
</table>
<p>V1 的度是2，因为无论行、列，为1的元素加起来，都是2
 <br>
 V1 的邻接点是 V0、V2，因为 V1 行只有 V0、V2 的元素为1</p>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-14-15447540206199.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>我们看看图对不对，没有问题！</p>
<h1 id="%E6%9C%89%E5%90%91%E5%9B%BE%E7%9A%84%E9%82%BB%E6%8E%A5%E7%9F%A9%E9%98%B5">有向图的邻接矩阵</h1>
<p>我们在无向图中发现，邻接矩阵竟然是对称的，原因也很简单</p>
<ul>
 <li>因为无论是顶点 A 到顶点 B 还是顶点 B 到顶点 A 都是相同的</li>
 <li>那么在有向图中，给顶点规定了方向之后，会不会好一些呢？</li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-14-15447577692706.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>有向图最重要的一点就是区分方向，我们按照上面的思路，首先设计一个一维数组 vexs 存放顶点信息</p>
<table>
 <thead>
  <tr>
   <th>vexs0</th>
   <th>vexs1</th>
   <th>vexs2</th>
   <th>vexs3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>V1</td>
   <td>V2</td>
   <td>V3</td>
  </tr>
 </tbody>
</table>
<p>接着设计一个邻接矩阵（二维数组）arcs，存放边和边得信息</p>
<table>
 <thead>
  <tr>
   <th></th>
   <th>V0</th>
   <th>V1</th>
   <th>v2</th>
   <th>v3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>0</td>
   <td>0</td>
   <td>0</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
  <tr>
   <td>V2</td>
   <td>1</td>
   <td>1</td>
   <td>0</td>
   <td>0</td>
  </tr>
  <tr>
   <td>V3</td>
   <td>0</td>
   <td>0</td>
   <td>0</td>
   <td>0</td>
  </tr>
 </tbody>
</table>
<p>因为我们要注意方向</p>
<ul>
 <li>所以行为弧为、列为弧头</li>
 <li>如果不规定，那么 A-&gt;B 和 B-&gt;A 就一样了</li>
 <li>这就不是有向图了</li>
</ul>
<h1 id="%E6%9C%89%E5%90%91%E5%9B%BE%E9%82%BB%E6%8E%A5%E7%9F%A9%E9%98%B5%E7%9A%84%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84">有向图邻接矩阵的存储结构</h1>
<p>我们设计这个存储结构时</p>
<ul>
 <li>设计两个数组</li>
 <li>顶点数组vertex[4]</li>
 <li>边数组 arc[4][4] ，有向图矩阵并不对称</li>
 <li>边数组中，0表示顶点间不存在边，1表示顶点间存在边</li>
</ul>
<p>有向图有入度和出度的概念，所以</p>
<ul>
 <li>顶点 V1 的入度为1，正好是第 V1列的各数之和</li>
 <li>顶点 V1 的出度为2，正好是第 V2行的各数之和</li>
 <li>我们看看下表</li>
</ul>
<table>
 <thead>
  <tr>
   <th></th>
   <th>V0</th>
   <th>V1</th>
   <th>v2</th>
   <th>v3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>0</td>
   <td>0</td>
   <td>0</td>
   <td>1</td>
  </tr>
  <tr>
   <td>V1</td>
   <td>1</td>
   <td>0</td>
   <td>1</td>
   <td>0</td>
  </tr>
  <tr>
   <td>V2</td>
   <td>1</td>
   <td>1</td>
   <td>0</td>
   <td>0</td>
  </tr>
  <tr>
   <td>V3</td>
   <td>0</td>
   <td>0</td>
   <td>0</td>
   <td>0</td>
  </tr>
 </tbody>
</table>
<p>V1 的入度是1，出度是2</p>
<ul>
 <li>V1列所有元素的和为1</li>
 <li>V1行所有元素的和为2</li>
 <li>我们看下图验证一下</li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-14-15447577692706.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>没有问题，我们接下来实际设计一下数据结构。</p>
<h1 id="%E9%82%BB%E6%8E%A5%E7%9F%A9%E9%98%B5%EF%BC%88%E7%BD%91%EF%BC%89">邻接矩阵（网）</h1>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-14-15447584041093.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>我们在上一节，说到了网这个概念，实际上就是每条边上带有权的图，就是网。</p>
<ul>
 <li>网跟上面的思路一样，使用两个数组搞定</li>
 <li>在数组中的元素就不在是0和1了</li>
 <li>因为每条边有权，所以我们就将每条边的权值赋值到二维数组中</li>
</ul>
<p>网最重要的一点就是看好权值，我们按照上面的思路，首先设计一个一维数组 vexs 存放顶点信息</p>
<table>
 <thead>
  <tr>
   <th>vexs0</th>
   <th>vexs1</th>
   <th>vexs2</th>
   <th>vexs3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>V1</td>
   <td>V2</td>
   <td>V3</td>
  </tr>
 </tbody>
</table>
<p>接着设计一个邻接矩阵（二维数组）arcs，存放边和边得信息</p>
<table>
 <thead>
  <tr>
   <th></th>
   <th>V0</th>
   <th>V1</th>
   <th>v2</th>
   <th>v3</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>V0</td>
   <td>$\infty$</td>
   <td>$\infty$</td>
   <td>$\infty$</td>
   <td>18</td>
  </tr>
  <tr>
   <td>V1</td>
   <td>8</td>
   <td>$\infty$</td>
   <td>2</td>
   <td>$\infty$</td>
  </tr>
  <tr>
   <td>V2</td>
   <td>4</td>
   <td>$\infty$</td>
   <td>$\infty$</td>
   <td>$\infty$</td>
  </tr>
  <tr>
   <td>V3</td>
   <td>$\infty$</td>
   <td>$\infty$</td>
   <td>$\infty$</td>
   <td>$\infty$</td>
  </tr>
 </tbody>
</table>
<p>这里有三种情况</p>
<ul>
 <li>如果有弧，则将权值写入</li>
 <li>如果指向自己，那就写$\infty$</li>
 <li>如果没有弧，那就写入$\infty$</li>
 <li>$\infty$ 表示计算机允许的，一个大于所有权值的值。</li>
</ul>
<h1 id="%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0">代码实现</h1>
<pre><code class="hljs language-c"><span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> {</span> DG, UDG } GraphType; <span class="hljs-comment">//声明图的类型，有向还是无向</span>
<span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> {</span>
    <span class="hljs-type">char</span> vexs[MAX_VEX_NUM];  <span class="hljs-comment">//一维数组，用于存放顶点</span>
    <span class="hljs-type">int</span> arcs[MAX_VEX_NUM][MAX_VEX_NUM];  <span class="hljs-comment">//二维邻接矩阵，存放边、弧</span>
    <span class="hljs-type">int</span> vexnum, arcnum;  <span class="hljs-comment">//存放顶点数量和边、弧的数量</span>
    GraphType type;  <span class="hljs-comment">//从有向和无向中选择一个</span>
} MGraph;
</code></pre>
<p>好了，理解了上述概念，我们下节课来讲，如何创建一个图。</p>
<h1 id="%E5%B0%BE%E5%B7%B4">尾巴</h1>
<p>这是我的个人学习笔记，主要是应付考研复习使用，充斥着一些吐槽和个人观点，并不严谨，欢迎大家参考、指正。</p>]]></description><guid isPermaLink="false">/archives/Data_structure_course_064_graph_graph_storage_structure</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Fri, 14 Dec 2018 02:04:26 GMT</pubDate></item><item><title><![CDATA[数据结构之图-图结构的简介和引入（下）-学习笔记-63]]></title><link>https://www.bliner.me/archives/Data_structure_course_063_graph_graph_introduction_2</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E5%9B%BE-%E5%9B%BE%E7%BB%93%E6%9E%84%E7%9A%84%E7%AE%80%E4%BB%8B%E5%92%8C%E5%BC%95%E5%85%A5%EF%BC%88%E4%B8%8B%EF%BC%89-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-63&amp;url=/archives/Data_structure_course_063_graph_graph_introduction_2" width="1" height="1" alt="" style="opacity:0;">
<h1 id="%E5%BC%95%E5%85%A5">引入</h1>
<p>前面我们基本讲了什么是图结构，以及顶点、边和弧之间不同状态的特殊图结构，我们今天继续，看看这些顶点、边和弧之间的关系。</p>
<h1 id="%E5%85%B3%E7%B3%BB">关系</h1>
<p>我们来讲讲顶点和边的一些关系</p>
<h2 id="%E9%A1%B6%E7%82%B9%E5%92%8C%E8%BE%B9%E7%9A%84%E5%85%B3%E7%B3%BB">顶点和边的关系</h2>
<p>我们说，如果存在一个<code>无向图</code>，G（V，E）</p>
<ul>
 <li>图中的两个顶点构成的边$(V1 , V2)\in E$属于 E 的集合</li>
 <li>那么我们就说 V1 和 V2 互为<code>邻接点（Adjacent）</code></li>
 <li>也就说明 V1 和 V2 <code>相邻接，不是连接！</code>。</li>
 <li>对于边(V1 , V2)来说</li>
 <li>边(V1 , V2)依附（Incident）于 顶点 V1和 V2</li>
 <li>也可以说边(V1 , V2)与顶点 V1 、V2 相关联</li>
</ul>
<h2 id="%E6%97%A0%E5%90%91%E5%9B%BE%E4%B8%AD%E7%9A%84%E5%BA%A6">无向图中的度</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446757823062.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<!-- more -->
<p>顶点 V 的度（Degree）是和 V 相关联的边的数目，记为 TD（V）</p>
<ul>
 <li>V 相关联得边根据上面得定义，就是根顶点 V 相连接的边</li>
 <li>上图中顶点 A、B互为邻接点</li>
 <li>边（A，B）依附于顶点 A 与 B 上</li>
 <li>顶点 A 的度为 A 关联得边得数目</li>
 <li>关联的边有（A，B）、（A，C）（A，D）</li>
 <li>所以顶点 A 得度为 3</li>
 <li>B 的关联边是（B，A）、（B，C）度是 2</li>
</ul>
<h2 id="%E6%9C%89%E5%90%91%E5%9B%BE%E4%B8%AD%E7%9A%84%E5%BA%A6">有向图中的度</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446766779780.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>那么在有向图中的度呢？现在有有向图 G=（V，E）</p>
<ul>
 <li>如果弧$&lt;V1,V2&gt;\in E$，<code>注意是尖括号。</code>属于边的集合E</li>
 <li>则称顶点 V1邻接到顶点 V2</li>
 <li>顶点 V2 邻接自顶点 V1</li>
 <li>V1是弧尾，V2是弧头，所以这里得邻接是有方向的</li>
 <li><code>邻接自</code>和<code>邻接到</code>是不同的，请注意！</li>
</ul>
<p>所以，有向图就跟无向图不同了</p>
<ul>
 <li>以顶点 V 为头的弧的数目称为 V 的入度（InDegree）记为 ID（V）</li>
 <li>以顶点 V 为尾的弧的数目称为 V 的出度（OutDegree）记为 OD（V）</li>
 <li>因此，该顶点 V 的度为$TD(V)=ID(V)+OD(V)$</li>
</ul>
<p>我们看上面的有向图中</p>
<ul>
 <li>顶点 A 为头，指向 A 的入度为2</li>
 <li>顶点 A 为尾，从 A 出去的出度为1</li>
 <li>A 的度为$2+1=3$</li>
</ul>
<h1 id="%E8%B7%AF%E5%BE%84">路径</h1>
<p>在图中，我们从一个顶点到另一个顶点的路线，<code>称为路径（Path）</code></p>
<h2 id="%E6%97%A0%E5%90%91%E5%9B%BE%E7%9A%84%E8%B7%AF%E5%BE%84">无向图的路径</h2>
<p>以下四种是在无向图 G 中顶点 A 到顶点 D 的四种不同的路径
 <br>
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15447050631466.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>我们看到顶点到顶点之间有这么多种不同的走法</p>
<ul>
 <li>以后我们学习图的主要目的就是简化路径</li>
 <li>找出最优路径</li>
</ul>
<h2 id="%E6%9C%89%E5%90%91%E5%9B%BE%E7%9A%84%E8%B7%AF%E5%BE%84">有向图的路径</h2>
<p>以下是在有向图 G 中从 B 到 D 的路径
 <br>
 <img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15447052521603.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>有向图的路径需要额外注意方向</p>
<ul>
 <li>如果我从 A 到 B 是不行的，因为没有 A 为弧头、B 为弧尾的边。</li>
 <li>必须是按照有向图的指向来从一个顶点到另一个顶点</li>
</ul>
<h2 id="%E8%B7%AF%E5%BE%84%E7%9A%84%E9%95%BF%E5%BA%A6">路径的长度</h2>
<p>路径的长度就是路径上<code>边或弧的数量。</code></p>
<h2 id="%E5%9B%9E%E8%B7%AF%EF%BC%88%E7%8E%AF%EF%BC%89">回路（环）</h2>
<p>如果从第一个顶点到最后一个顶点相同的路径，我们称之为环</p>
<h2 id="%E7%AE%80%E5%8D%95%E7%8E%AF">简单环</h2>
<p>既然一个顶点到最后一个顶点得路径如果相同，我们就称之为环，那么什么是简单环呢？</p>
<ul>
 <li>在第一个顶点到最后一个顶点得环路上，每个顶点只出现一次。</li>
 <li>除了第一个和最后一个顶点外，其余顶点都不重复出现得回路</li>
 <li>满足以上条件，就是简单环了</li>
 <li>简单来说，就是路径上的顶点不能重复，且能构成环状。</li>
</ul>
<table>
 <thead>
  <tr>
   <th>简单环</th>
   <th>不是简单环</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td></td>
   <td></td>
  </tr>
 </tbody>
</table>
<p>右侧图不是简单环得原因是</p>
<ul>
 <li>环可以是 BCADCB，C 出现了两次</li>
 <li>所以不是简单环。</li>
</ul>
<h1 id="%E8%BF%9E%E9%80%9A%E5%9B%BE">连通图</h1>
<p>如果在一个<code>无向图中</code></p>
<ul>
 <li>顶点 V1 到顶点 V2 有路径，则称 V1 和 V2 是连通的。</li>
 <li>如果图中得任意两个顶点 Vi 和 Vj 都是连通的</li>
 <li>我们就称这个图 G 为连通图（ConnectedGraph）</li>
</ul>
<table>
 <thead>
  <tr>
   <th>不是连通图</th>
   <th>连通图</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td></td>
   <td></td>
  </tr>
 </tbody>
</table>
<p>为什么左边得图不是连通图呢？因为</p>
<ul>
 <li>E F没有一个顶点跟 ABCD 连通</li>
 <li>所以并不是所有顶点都互相连通，不是连通图</li>
</ul>
<blockquote>
 <p><strong>注意：</strong>
  <br>
  完全图是：任意两个顶点必须是连接得，<code>也就是得有边。</code>
  <br>
  连通图是：任意两个顶点只要<code>有路径能连过去就行。</code></p>
</blockquote>
<h2 id="%E8%BF%9E%E9%80%9A%E5%88%86%E9%87%8F">连通分量</h2>
<p>无向图中的极大连通子图称为<code>连通分量。</code></p>
<ul>
 <li>无向图，就是边没有指定方向得图。</li>
 <li>极大，就是必须包含这个子图中所有的顶点</li>
 <li>连通，就是任意两个顶点都互相连通。</li>
 <li>子图，就是顶点和边都属于无向图 G （V，E）。</li>
 <li>**注意:**具有极大顶点数的连通子图包含依附于这些顶点所有的边。</li>
</ul>
<table>
 <thead>
  <tr>
   <th>图 G</th>
   <th>极大连通图-1</th>
   <th>极大连通图-2</th>
   <th>不是极大连通图</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td></td>
   <td></td>
   <td></td>
   <td></td>
  </tr>
 </tbody>
</table>
<p>我们看上面的图</p>
<ul>
 <li>ABCD 一定是图 G 的子图</li>
 <li>ABCD 的任意两个结点相互连接的</li>
 <li>子图 ABCD 顶点数也是最大</li>
 <li>那么我们就说子图 ABCD 是图 G 的极大连通子图</li>
 <li>也是图 G 的连通分量</li>
</ul>
<h1 id="%E5%BC%BA%E8%BF%9E%E9%80%9A%E5%9B%BE">强连通图</h1>
<p>我们说的连通图是无向图，对于有向图来说</p>
<ul>
 <li>如果对于每一对儿 Vi 到 Vj 都存在路径，则称 G 是强连通图。</li>
 <li>相应的，对于有向图中得极大强连通子图称为有向图的<code>强连通分量。</code></li>
</ul>
<table>
 <thead>
  <tr>
   <th>不是强连通图</th>
   <th>强连通图</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td></td>
   <td></td>
  </tr>
 </tbody>
</table>
<p>为什么左侧得不是强连通图？</p>
<ul>
 <li>因为任意两个顶点没有连通</li>
</ul>
<p>但是右侧得可以是左侧图到极大强连通子图</p>
<ul>
 <li>任意两个顶点联通</li>
 <li>是左侧图的子图</li>
 <li>所有的顶点都包含，极大。</li>
</ul>
<h1 id="%E8%BF%9E%E9%80%9A%E5%9B%BE%E7%94%9F%E6%88%90%E6%A0%91">连通图生成树</h1>
<p>连通图生成树，顾名思义，通过连通图生成一棵树，<code>连通图的生成树是一个极小的连通子图，</code>为什么呢？因为：</p>
<ul>
 <li>它含有图中全部的 n 个顶点</li>
 <li>但只有 n-1条边，因为 n-1条边就可以生成一棵树了</li>
</ul>
<table>
 <thead>
  <tr>
   <th>普通图 G</th>
   <th>极小连通子图/树</th>
   <th>极小连通子图/树</th>
   <th>不是极小连通子图/树</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td></td>
   <td></td>
   <td></td>
   <td></td>
  </tr>
 </tbody>
</table>
<p>中间两个图，都符合以下条件</p>
<ul>
 <li>它含有图中全部的 n 个顶点</li>
 <li>但只有 n-1条边，因为 n-1条边就可以生成一棵树了</li>
 <li>所以是<code>极小连通子图，也是连通图生成树</code></li>
</ul>
<p>最右边的图，不符合以下条件</p>
<ul>
 <li>虽然符合只有 n-1 条边</li>
 <li>没有包含有图中全部的 n 个顶点</li>
 <li>所以不是极小连通子图</li>
</ul>
<h1 id="%E6%9C%89%E5%90%91%E6%A0%91">有向树</h1>
<p>如果一个<code>有向图</code>，符合以下条件</p>
<ul>
 <li>有一个顶点入度为0，即没有其它顶点指向它</li>
 <li>其它顶点得入度都是1，也就是其他顶点都只有一个顶点指向它</li>
 <li>我们就称这是<code>一棵有向树。</code></li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15447094924083.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>上面两张图不是有向树，左图因为 D 结点的入度为3，右图因为 A 结点入度为2</p>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15447095594099.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>上图是有向树</p>
<ul>
 <li>F 得入度为0，没有顶点指向 F</li>
 <li>E G的入度都为1</li>
 <li>所以上图是有向树</li>
</ul>
<h1 id="%E5%B0%BE%E5%B7%B4">尾巴</h1>
<p>这是我的个人学习笔记，主要是应付考研复习使用，充斥着一些吐槽和个人观点，并不严谨，欢迎大家参考、指正。</p>]]></description><guid isPermaLink="false">/archives/Data_structure_course_063_graph_graph_introduction_2</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Thu, 13 Dec 2018 12:00:15 GMT</pubDate></item><item><title><![CDATA[数据结构之图-图结构的简介和引入（上）-学习笔记-62]]></title><link>https://www.bliner.me/archives/Data_structure_course_062_graph_graph_introduction_1</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E5%9B%BE-%E5%9B%BE%E7%BB%93%E6%9E%84%E7%9A%84%E7%AE%80%E4%BB%8B%E5%92%8C%E5%BC%95%E5%85%A5%EF%BC%88%E4%B8%8A%EF%BC%89-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-62&amp;url=/archives/Data_structure_course_062_graph_graph_introduction_1" width="1" height="1" alt="" style="opacity:0;">
<h1 id="%E5%BC%95%E5%85%A5">引入</h1>
<p>终于，我们迎来了新的数据结构，图结构。之前的线性表，主要是一对一的关系，一个元素和另一个元素的关系。树结构，主要层与层之间一对多的关系，即一个结点可以有 N 个子树，N 个子树也只对应一个双亲结点。那么大家也应该猜到了，图解决的是多对多的数据关系。</p>
<h1 id="%E5%9B%BE%E7%9A%84%E5%AE%9A%E4%B9%89">图的定义</h1>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446748009361.png%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt="">
 <br>
 （顶点1有一个环的图结构）</p>
<blockquote>
 <p>**图（Graph）：**是有顶点的又穷非空集合和顶点之间的边集合组成。</p>
</blockquote>
<ul>
 <li>通常表示为G（V，E）</li>
 <li>G 是一个图</li>
 <li>V 是图 G 中顶点的集合</li>
 <li>E 是图 G 中边的集合。</li>
</ul>
<!-- more -->
<p>对于上面的图</p>
<ul>
 <li>每一个圆圈表示图的一个顶点，顶点放在一起就是 V</li>
 <li>连接顶点的连线称之为图的边，边放在一起就是 E</li>
</ul>
<h2 id="%E6%95%B0%E6%8D%AE%E5%85%83%E7%B4%A0%E7%9A%84%E7%A7%B0%E5%91%BC">数据元素的称呼</h2>
<p>我们回顾一下线性表和树的数据</p>
<ul>
 <li>线性表中我们把数据称之为元素</li>
 <li>树中我们把数据称之为结点</li>
 <li>图中我们把数据称之为顶点（Vertex）</li>
</ul>
<h2 id="%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%E5%85%83%E7%B4%A0">没有数据元素</h2>
<p>我们回顾一下线性表和树没有数据元素时</p>
<ul>
 <li>线性表可以没有数据元素，称为空表。</li>
 <li>树中可以没有结点，称为空树。</li>
 <li>图一般不为空，我们一般说<code>顶点集合 V 要有穷非空。</code></li>
</ul>
<h2 id="%E6%95%B0%E6%8D%AE%E5%85%83%E7%B4%A0%E7%9A%84%E5%85%B3%E7%B3%BB">数据元素的关系</h2>
<p>我们回顾一下线性表和树中数据元素之间的关系</p>
<ul>
 <li>线性表中的数据元素，一对一，我们说它们有线性关系。</li>
 <li>树结构中的数据元素，一对多，我们说相邻两层的结点具有层次关系。</li>
 <li>图结构中的数据元素，多对多，任意两个顶点之间都可能有关系，顶点之间的逻辑关系用边来表示，边集可以为空，即数据元素可以跟任何其他数据元素无关。</li>
</ul>
<h1 id="%E5%9B%BE%E7%9A%84%E8%BE%B9">图的边</h1>
<p>图中的各种特性和定义比较多，我们分开讲</p>
<h2 id="%E6%97%A0%E5%90%91%E8%BE%B9">无向边</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446757823062.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt="">
 <br>
 看着上面这张图，我们来说明一下</p>
<ul>
 <li>若顶点 Vi 到 Vj 之间的<code>边没有方向</code></li>
 <li>则称这条边为<code>无向边（Edge）</code></li>
 <li>用无序偶（Vi，Vj） 来表示</li>
 <li>V 是顶点的集合哈，Vi 和 Vj 就是其中的两个顶点。别忘了。</li>
</ul>
<p>知道了上面的概念之后，我们就可以说</p>
<ul>
 <li>上图G1是一个<code>无向图</code>，如果 $G1=\left { V1 , E2\right }$</li>
 <li>顶点的集合：$V1=\left{A,B,C,D\right}$</li>
 <li>边的集合：$E1=\left{(A,B),(B,C),(C,D),(D,A),(A,C)\right}$</li>
</ul>
<h2 id="%E6%9C%89%E5%90%91%E8%BE%B9">有向边</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446766779780.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>看着上面这张图，我们来说明一下</p>
<ul>
 <li>若顶点 Vi 到 Vj 之间的<code>边有方向</code></li>
 <li>则称这条边为<code>有向边，也称为弧（Arc）</code></li>
 <li>用有序偶 &lt; Vi , Vj &gt; 表示，注意这里是尖括号</li>
 <li>Vi 称为弧尾，Vj 称为弧头。</li>
 <li>因为是有向边，所有 Vi 和 Vj 顺序不能错，一定是尾巴指向头。</li>
</ul>
<p>知道了上面的概念之后，我们就可以说</p>
<ul>
 <li>上图G2是一个<code>有向图</code>，如果 $G2=\left { V2 , E2\right }$</li>
 <li>顶点的集合：$ V1= \left{ A,B,C,D \right} $</li>
 <li>边的集合：$E1=\left{(B,A),(B,C),(C,A),(A,D)\right}$</li>
 <li>这里边的集合要注意顺序！！！</li>
</ul>
<h2 id="%E7%AE%80%E5%8D%95%E5%9B%BE">简单图</h2>
<p>什么叫做简单图呢？在一个图结构中</p>
<ul>
 <li>若不存在顶点到其自身的边</li>
 <li>同一条边不重复出现</li>
 <li>满足以上两个条件的图，叫做简单图。</li>
</ul>
<p>以下两个都<code>不是简单图</code></p>
<table>
 <thead>
  <tr>
   <th>同一条边出现两次</th>
   <th>A 不能指向自己</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td></td>
   <td></td>
  </tr>
 </tbody>
</table>
<blockquote>
 <p>**注意：**我们目前讲的主要都是简单图，因为应用广泛。</p>
</blockquote>
<h1 id="%E7%89%B9%E6%AE%8A%E7%9A%84%E5%9B%BE">特殊的图</h1>
<p>根据图边、弧和顶点的不同情况，又分为以下几种常见图</p>
<h2 id="%E6%97%A0%E5%90%91%E5%AE%8C%E5%85%A8%E5%9B%BE">无向完全图</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446911282424.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>如果在一个<code>无向图中</code></p>
<ul>
 <li>任意两个顶点之间都存在边</li>
 <li>则称该图为无向完全图</li>
 <li>n 个顶点的无向完全图有 $n\times(n-1)\div2$ 条边</li>
 <li>上面就是一张无向完全图，所有顶点都连着边</li>
 <li>ABCD 4个顶点就是 $4\times(4-1)\div2=6$ 条边</li>
</ul>
<h2 id="%E6%9C%89%E5%90%91%E5%AE%8C%E5%85%A8%E5%9B%BE">有向完全图</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446917095559.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>如果在一个<code>有向图中</code></p>
<ul>
 <li>任意两个顶点之间都存在方向互为相反的两条弧</li>
 <li>则称该图为有向完全图</li>
 <li>n 个顶点的无向完全图有 $n\times(n-1)$ 条边</li>
 <li>上面就是一张无向完全图，所有顶点都与另一个顶点互为相反弧</li>
 <li>ABCD 4个顶点就是 $4\times(4-1)=12$ \条边</li>
</ul>
<h2 id="%E7%A8%80%E7%96%8F%E5%9B%BE%E5%92%8C%E7%A8%A0%E5%AF%86%E5%9B%BE">稀疏图和稠密图</h2>
<p>这里讲的稀疏和稠密都是相对而言的，通常</p>
<ul>
 <li>边或者弧数小于 $n\times \log n$时的图为稀疏图</li>
 <li>反之为稠密图</li>
</ul>
<h2 id="%E5%B8%A6%E6%9D%83%E5%9B%BE">带权图</h2>
<p>这里说的权根我们在哈夫曼树中说的权是一样的</p>
<ul>
 <li>图的边或者弧带有与它相关的数字</li>
 <li>我们把这些相关树称作<code>权（weight）</code></li>
 <li>我们称这种<code>带权图为网（NetWork）</code></li>
</ul>
<h2 id="%E5%AD%90%E5%9B%BE">子图</h2>
<p>如果有两个图 G1=（V1，E1）和 G2=（V2，E2）</p>
<ul>
 <li>如果 $V2 \subseteq V1$，G2的顶点都在 G1 的顶点的集合内</li>
 <li>并且！！！</li>
 <li>$E2 \subseteq E1$，G2的边都在 G1 的边的集合内</li>
 <li>记住，上面两个条件如果同时成立！</li>
 <li>我么你就说 G2 是 G1 的子图</li>
 <li>简单就是，我的顶点你也有，我的边你也有，那我就是你的子图</li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446924501218.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-13-15446925426071.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>上面两张图中，红框内的都是左边图的子图。
 <br>
 记住有向图还要关注方向是否相同！</p>
<p>基础知识还有不少，我们下节继续！</p>
<h1 id="%E5%B0%BE%E5%B7%B4">尾巴</h1>
<p>这是我的个人学习笔记，主要是应付考研复习使用，充斥着一些吐槽和个人观点，并不严谨，欢迎大家参考、指正。</p>]]></description><guid isPermaLink="false">/archives/Data_structure_course_062_graph_graph_introduction_1</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Thu, 13 Dec 2018 06:16:39 GMT</pubDate></item><item><title><![CDATA[数据结构之树-哈夫曼编码-学习笔记-61]]></title><link>https://www.bliner.me/archives/Data_sturcture_course_061_tree_Huffman_coding_2</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E6%A0%91-%E5%93%88%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-61&amp;url=/archives/Data_sturcture_course_061_tree_Huffman_coding_2" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p>未完待续…</p>
</blockquote>]]></description><guid isPermaLink="false">/archives/Data_sturcture_course_061_tree_Huffman_coding_2</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Thu, 13 Dec 2018 04:16:39 GMT</pubDate></item><item><title><![CDATA[数据结构之树-哈夫曼编码-学习笔记-60]]></title><link>https://www.bliner.me/archives/Data_sturcture_course_060_tree_Huffman_coding_1</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E6%A0%91-%E5%93%88%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-60&amp;url=/archives/Data_sturcture_course_060_tree_Huffman_coding_1" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p>未完待续…</p>
</blockquote>]]></description><guid isPermaLink="false">/archives/Data_sturcture_course_060_tree_Huffman_coding_1</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Thu, 13 Dec 2018 02:16:39 GMT</pubDate></item><item><title><![CDATA[数据结构之树-哈夫曼树-学习笔记-59]]></title><link>https://www.bliner.me/archives/Data_sturcture_course_059_tree_Huffman_tree</link><description><![CDATA[<img src="https://www.bliner.me/plugins/feed/assets/telemetry.gif?title=%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8B%E6%A0%91-%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-59&amp;url=/archives/Data_sturcture_course_059_tree_Huffman_tree" width="1" height="1" alt="" style="opacity:0;">
<h1 id="%E5%BC%95%E5%85%A5">引入</h1>
<p>上一节我们发现，树、森林和二叉树之间竟然有这么多有趣的关联，前根和后根遍历结果竟然都可以跟二叉树相同。二叉树竟然这么的独特，今天我们就来看看，如何打造一棵<code>完美二叉树！</code></p>
<h1 id="%E4%BB%8E%E4%B8%80%E4%B8%AA%E9%97%AE%E9%A2%98%E5%87%BA%E5%8F%91">从一个问题出发</h1>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15445857246635.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>我们在使用二叉树的时候，会遇到类似这样的问题</p>
<ul>
 <li>这是一棵二叉树，结点连接线上的数字，是访问这个结点的概率</li>
 <li>我们有5%的几率访问 A、15%访问 B、70%访问 C、10%访问 D</li>
 <li>那么问题来了，既然绝大多数都是访问 C 的</li>
 <li>那访问 C 必须要先判断是否是 A 或者 B，这样太麻烦了</li>
</ul>
<p>要弄清楚这个问题，我先首先要弄清楚刚才哪些<code>加了数字的结点是什么。</code></p>
<!-- more -->
<h1 id="%E5%B8%A6%E6%9D%83%E5%8F%B6%E5%AD%90%E7%BB%93%E7%82%B9">带权叶子结点</h1>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15445857246635.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>还是这张图，我们看到这棵二叉树有一点点不同</p>
<ul>
 <li>结点前有一个数值，我们把这种<code>结点间连线的相关书叫做权。</code></li>
 <li>我们管这些叶子结点，叫做带权叶子结点。</li>
 <li>数值越大，权重越大。</li>
</ul>
<h1 id="%E7%BB%93%E7%82%B9%E7%9A%84%E8%B7%AF%E5%BE%84%E9%95%BF%E5%BA%A6">结点的路径长度</h1>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15445857246635.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt="">
 <br>
 我们引申出一个新定义，结点的路径长度，我们来看一下</p>
<h2 id="%E7%BB%93%E7%82%B9%E7%9A%84%E8%B7%AF%E5%BE%84%E9%95%BF%E5%BA%A6">结点的路径长度</h2>
<blockquote>
 <p>**定义：**根结点到叶子结点的路径上的连接数。</p>
</blockquote>
<p>上图中，C 结点的路径长度为 3。</p>
<ul>
 <li>根到右子树，为1</li>
 <li>右子树到右子树为，为2</li>
 <li>右子树到右子树的左子树 C ，为3</li>
</ul>
<h2 id="%E6%A0%91%E7%9A%84%E8%B7%AF%E5%BE%84%E9%95%BF%E5%BA%A6">树的路径长度</h2>
<blockquote>
 <p>**定义：**根到每一个结点的路径长度之和。</p>
</blockquote>
<p>上图中，我们来算一下</p>
<ul>
 <li>根到 A 是1</li>
 <li>根到 B 是2</li>
 <li>根到 C 是3</li>
 <li>根到 D 是3</li>
 <li>所以$1+2+3+3=9$</li>
 <li>上面这棵<code>树的路径长度为9。</code></li>
</ul>
<h2 id="%E7%BB%93%E7%82%B9%E5%B8%A6%E6%9D%83%E8%B7%AF%E5%BE%84%E9%95%BF%E5%BA%A6">结点带权路径长度</h2>
<p>结点的路径长度是根到结点，那么带上权呢？</p>
<blockquote>
 <p>**定义：**结点的路径长度与结点权值的乘积。</p>
</blockquote>
<p>我们还是拿 C 结点举例</p>
<ul>
 <li>C 结点的路径长度我们算过了，长度是 3</li>
 <li>那么 C 结点的带权路径长度就是$3 \times 70=210$</li>
 <li>C 结点的带权路径长度为210</li>
</ul>
<h2 id="%E6%A0%91%E7%9A%84%E5%B8%A6%E6%9D%83%E8%B7%AF%E5%BE%84%E9%95%BF%E5%BA%A6">树的带权路径长度</h2>
<blockquote>
 <p>**定义：**根到每一个结点的路径长度乘以权值的和。</p>
</blockquote>
<p>上图中，我们来算一下</p>
<ul>
 <li>根到 A 是1，权值是5，$1 \times 5=5$</li>
 <li>根到 B 是2，权值是15，$2 \times 15=30$</li>
 <li>根到 C 是3，权值是70，$3 \times 70=210$</li>
 <li>根到 D 是3，权值是10，$3 \times 10=30$</li>
 <li>所以$5+30+210+30=275$</li>
 <li>上面这棵<code>树的带权路径长度为275。</code></li>
</ul>
<p>我们将树的带权路径长度称为 WPL（Weighted Path Length）
 <br>
 记住，WPL 就是树中所有叶子结点的带权路径长度之和。</p>
<h1 id="%E6%9C%80%E4%BC%98%E4%BA%8C%E5%8F%89%E6%A0%91">最优二叉树</h1>
<p>我们称 WPL 的值越小，构造出来的二叉树就约优秀，那么该如何构造出最优的二叉树呢？对了，<code>最优二叉树我们也称为哈夫曼树！</code></p>
<h2 id="%E5%88%9D%E5%A7%8B%E5%8C%96">初始化</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15446023950288.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>首先，我们在森林中选择两课根结点权值最小的树，上图所示</p>
<ul>
 <li>我们把 A B C D 看做四棵树组成的森林</li>
 <li>A B C D 就是四个根节点，四个根节点都有一个权值</li>
 <li>我们把最小的两个提取出来，即 C 和 D</li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15446025187699.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt=""></p>
<p>接着我们来操作上面的两个最小的结点</p>
<ul>
 <li>把两个结点中权值较小的放到左边，即 C 放到左边，作为左孩子</li>
 <li>权值较大的结点放在右边，作为右子树</li>
 <li>将左右子树的权值相加，得到6，作为左右子树的双亲结点，我们记作N1</li>
</ul>
<h2 id="%E7%BB%A7%E7%BB%AD%E6%B7%BB%E5%8A%A0">继续添加</h2>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15446032514500.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt="">
 <br>
 我们剩下的还有两个结点，A 和 B</p>
<ul>
 <li>上一步我们得到了一个 N1，权值是 C D 的和</li>
 <li>此时我们从 A 和 B 中选择一个较小的结点 B，拿出来</li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15446033807921.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt="">
 <br>
 我们开始比较 B 和 N1</p>
<ul>
 <li>如果 B 比 N1 大，那就放右边作为右子树，反之作为左子树</li>
 <li>因为 B 是5，N1是6，所以我们把 B 放在左边</li>
 <li>同样的生成一个 N2，N2的权值是 N1和 B 的和，即5+6=11</li>
</ul>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15446034794809.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt="">
 <br>
 最后剩下的结点 A 相同，最后得到这棵哈夫曼树的根权值为18。
 <br>
 哈夫曼树构造完毕。</p>
<h2 id="%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91%E7%9A%84%E4%BC%98%E7%82%B9%EF%BC%9F">哈夫曼树的优点？</h2>
<p>我们费劲儿构建的这棵哈夫曼树有什么厉害的地方呢？</p>
<ul>
 <li>WPL 最小，WPL 还记得吧？就是树的带权路径</li>
 <li>我们不可能构建出比哈夫曼树更好的排列方式</li>
 <li>所以我们将哈夫曼树也成为<code>完美二叉树。</code></li>
</ul>
<h1 id="%E5%9B%9E%E5%88%B0%E9%97%AE%E9%A2%98">回到问题</h1>
<p><img src="https://www.bliner.me/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fimage.bliner.me%2F2018-12-12-15445857246635.jpg%3FimageView2%2F0%2Fq%2F100%257Cwatermark%2F1%2Fimage%2FaHR0cDovL2ltYWdlLmJsaW5lci5tZS9ibGluZXJ3YXRlcm1hcmsucG5n%2Fdissolve%2F40%2Fgravity%2FSouthWest%2Fdx%2F10%2Fdy%2F10%257Cimageslim&amp;size=m" alt="">
 <br>
 还记得我们开头这个问题吗？既然访问节点的概率就是权值的话，我们用哈夫曼树的构建方式，将 A B C D 重新构建之后，就可以解决啦！</p>
<h1 id="%E5%B0%BE%E5%B7%B4">尾巴</h1>
<p>这是我的个人学习笔记，主要是应付考研复习使用，充斥着一些吐槽和个人观点，并不严谨，欢迎大家参考、指正。</p>]]></description><guid isPermaLink="false">/archives/Data_sturcture_course_059_tree_Huffman_tree</guid><dc:creator>Bliner</dc:creator><category>笔记&amp;教程</category><pubDate>Wed, 12 Dec 2018 08:35:54 GMT</pubDate></item></channel></rss>