<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>patience</title><link>https://lzxlog.xyz/</link><description>Recent content on patience</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Sun, 14 Jun 2026 11:40:00 +0800</lastBuildDate><atom:link href="https://lzxlog.xyz/index.xml" rel="self" type="application/rss+xml"/><item><title>C语言实现哈夫曼编码</title><link>https://lzxlog.xyz/posts/c%E8%AF%AD%E8%A8%80%E5%AE%9E%E7%8E%B0%E5%93%88%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81/</link><pubDate>Sun, 14 Jun 2026 11:40:00 +0800</pubDate><guid>https://lzxlog.xyz/posts/c%E8%AF%AD%E8%A8%80%E5%AE%9E%E7%8E%B0%E5%93%88%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;哈夫曼编码（Huffman Coding）是一种经典的无损数据压缩算法，由 David Huffman 于 1952 年提出。它的核心思想非常朴素——&lt;strong&gt;高频字符用短编码，低频字符用长编码&lt;/strong&gt;，从而达到整体压缩的效果。&lt;/p&gt;
&lt;p&gt;这篇文章将基于我课程设计的实际代码，从数据结构选型开始，逐步讲解哈夫曼树的构建、编码的生成、文件的压缩与解压，以及这个算法固有的局限性。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一数据结构选型"&gt;一、数据结构选型&lt;/h2&gt;
&lt;p&gt;在设计一个压缩系统之前，首先要回答一个问题：用什么来存储数据？&lt;/p&gt;
&lt;h3 id="为什么用顺序表数组而不是链表"&gt;为什么用顺序表（数组）而不是链表？&lt;/h3&gt;
&lt;p&gt;哈夫曼树的节点数是确定的——如果有 &lt;code&gt;n&lt;/code&gt; 个不同的字符，那么树中总共有 &lt;code&gt;2n - 1&lt;/code&gt; 个节点（因为每两个节点合并产生一个新节点）。既然总数确定，用数组来实现顺序存储就比链表更高效：随机访问是 O(1)，而链表每次选取最小权值节点时需要遍历。&lt;/p&gt;
&lt;h3 id="三个核心数据结构"&gt;三个核心数据结构&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;频率数组 &lt;code&gt;freq[256]&lt;/code&gt;&lt;/strong&gt;：ASCII 字符共 256 个（如果只考虑单字节），用一个 &lt;code&gt;int&lt;/code&gt; 类型的数组记录每个字符出现的次数。数组下标就是字符的 ASCII 码，值是它出现的次数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// 全局变量，所有源文件共享
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;哈夫曼树节点数组 &lt;code&gt;HuffNode ht[]&lt;/code&gt;&lt;/strong&gt;：用双亲表示法存储树结构。每个节点记录自己的权值、双亲节点下标、左右孩子下标。0 表示不存在。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 权值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 双亲、左孩子、右孩子下标，0 表示无
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;HuffNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;编码表 &lt;code&gt;HuffCode hc[]&lt;/code&gt;&lt;/strong&gt;：为每个叶子节点（字符）存储对应的哈夫曼编码，编码用字符串形式存放。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// 存放编码字符串，如 &amp;#34;0110&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;HuffCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="数组大小的确定"&gt;数组大小的确定&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;频率数组：256 个位置，覆盖所有可能的 &lt;code&gt;unsigned char&lt;/code&gt; 值&lt;/li&gt;
&lt;li&gt;哈夫曼树数组：最坏情况下 256 个不同字符全部出现，共 &lt;code&gt;2 × 256 - 1 = 511&lt;/code&gt; 个节点，定义 &lt;code&gt;MAX * 2&lt;/code&gt; 即 512 足够&lt;/li&gt;
&lt;li&gt;编码表：同样 256 个位置&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二读取文件与频率统计"&gt;二、读取文件与频率统计&lt;/h2&gt;
&lt;p&gt;一切压缩的前提是知道文件中每个字符出现了多少次。这一步由 &lt;code&gt;ReadFileAndCount()&lt;/code&gt; 完成：&lt;/p&gt;</description></item><item><title>创建个人静态博客</title><link>https://lzxlog.xyz/posts/%E5%88%9B%E5%BB%BA%E4%B8%AA%E4%BA%BA%E9%9D%99%E6%80%81%E5%8D%9A%E5%AE%A2/</link><pubDate>Sun, 14 Jun 2026 10:15:27 +0800</pubDate><guid>https://lzxlog.xyz/posts/%E5%88%9B%E5%BB%BA%E4%B8%AA%E4%BA%BA%E9%9D%99%E6%80%81%E5%8D%9A%E5%AE%A2/</guid><description/></item></channel></rss>