信源编码程序设计实验C语言实现,霍夫曼信源编码实验报告

41528d3028836879cd698677c3999917.gif霍夫曼信源编码实验报告

1 实验 1:霍夫曼信源编码综合设计 【实验目的】 通过本专题设计,掌握霍夫曼编码的原理和实现方法,并熟悉利用 C 语言进行 程序设计,对典型的文本数据和图像数据进行霍夫曼编解码。 【预备知识】 1、熵的概念,霍夫曼编码原则 2、数据结构和算法设计 3、C(或 C++)编程语言 【实验环境】 1、设备:计算机一台 2、软件:C 程序编译器 【设计要求】 根据霍夫曼编码原则,利用 C 语言设计并实现霍夫曼编码和解码程序,要求能 够对给出的典型文本数据和图像数据进行霍夫曼编解码,并计算相应的熵和压缩比。 【实验原理】 Huffman 编码属于熵编码的方法之一,是根据信源符号出现概率的分布特性而 进行的压缩编码。 Huffman 编码的主要思想是:出现概率大的符号用长的码字表示;反之,出现 概率小的符号用短的码字表示。 Huffman 编码过程描述: 1. 初始化:将信源符号按出现频率进行递增顺序排列,输入集合 L; 2. 重复如下操作直至 L 中只有 1个节点: (a) 从 L 中取得两个具有最低频率的节点,为它们创建一个父节点; (b) 将它们的频率和赋给父结点,并将其插入 L; 3. 进行编码 :从根节点开始,左子节点赋予 1,右节点赋予 0,直到叶子节点。2 【基本定义】 1. 熵和平均编码符号长度 熵是信息量的度量方法,它表示某一事件出现的概率越小,则该事件包含的信息 就越多。根据 Shannon 理论,信源 S 的熵定义为 ,其中 是符 2 ( ) log (1/ ) i i i H s p p   i p 号 在 S 中出现的概率; 表示包含在 中的信息量,也就是编码 所需要 i S 2 log (1/ ) i p i S i S 的位数 假设符号 编码后长度为 l i(i=1,…,n),则平均编码符号长度 L 为: i S i i i L pl   2. 压缩比 设原始字符串的总长度为 L orig 位,编码后的总长度为 L coded 位,则压缩比 R 为R = (L orig- L coded )/ L orig 【例子】 有一幅40个象素组成的灰度图像,灰度共有5级,分别用符号A、B、C、D和E 表示,40个象素中出现灰度A的象素数有15个,出现灰度B的象素数有7个,出现 灰度C的象素数有7个等等,如表1所示。如果用3个位表示5个等级的灰度值, 也就是每个象素用3位表示,编码这幅图像总共需要120位。 表1 符号在图像中出现的数目 符 号 A B C D E 出现的次数 15 7 7 6 5 根据Shannon理论,这幅图像的熵为 H(S) = (15/40) (40/15)+(7/40) (40/7)++(5/40) (40/5)=2.196 2 log 2 log 2 log 平均编码符号长度L为(15/40)*1+(7/40)*3+(7/40)*3+(6/40)*3+(5/40)*3 = 2.25 根据霍夫曼编码原则可以得到如下的霍夫曼编码表。 表2 霍夫曼编码举例 符号 出现的次数 log 2 (1/p i ) 分配的 代码 所需 位数 A 15(0.375) 1.4150 1 15 B 7(0.175) 2.5145 011 21 C 7(0.175) 2.5145 010 21 D 6(0.150) 2.7369 001 18 E 5(0.125) 3.0000 000 15 因而,这副图采用霍夫曼编码的压缩比R为1.3333:1(120:90)。 霍夫曼码的码长虽然是可变的,但却不需要另外附加同步代码。例如,码串中 的第1位为0,那末肯定是符号 A,因为表示其他符号的代码没有一个是以0开始的, 因此下一位就表示下一个符号代码的第1位。同样,如果出现“110”,那么它就代3 表符号D。如果事先编写出一本解释各种代码意义的“词典”,即码簿,那么就可以 根据码簿一个码一个码地依次进行译码。 【实验步骤】 (16学时) 根据提供的示例 Huffman 编译码器源程序,利用 VC++6.0 进行编译生成可执行 文件,阅读并运行程序。 1、用 Microsoft Office Vision 分别画出 Huffman 编码和译码程序流程图,写出用 到的主要数据结构并加以说明。 2、在 Huffman 编码器合适位置加入 4个函数: calcProbability,calcEntropy,calcAvgSymbolLength,calcCompressionRatio, 分别计算信源各符号出现的概率、信源的熵、平均编码符号长度以及压缩比。 (自定义函数的参数) 3、分析霍夫曼编译码码的计算复杂度,定量说明 Huffman 编码和译码哪种操作 更耗时? 4、设计中遇到的问题,怎样解决问题的。在设计过程中的心得体会。 思考题: 1、霍夫曼编码是否具有唯一性? 2、个人对霍夫曼编码方式的不足之处的思考以及怎么样在进行压缩时避免这些 问题。 3、分析霍夫曼编码对文本数据以及图象数据的编码效率,观察与对应信源概率 分布的关系。 4、参考静止图像压缩编码国际标准 JPEG,为了提高对图像编码的效率,通常要 在霍夫曼编码之前进行什么操作? 5、。 【实验结果】 一.译码与编码流程图如下所示: 1.译码流程图4 否 是 是 否 是 否 否 是 2.编码流程图 程序初始化 主程序 调用图像库数据 接收到有效指 令? 图像显示指令? 字符显示指令? 图像像素数据? 返回主程序 显示图像 显示字符 JPEG 格式图像解码 调用字符库数据5 否 是 是 否 是 否 否 是 二.四个部分的程序 1.计算每个个符号出现的概率 void calcProbability(int total, SymbolFrequencies *pSF) { 程序初始化 主程序 调用图像库数据 接收到有效指 令? 图像显示指令? 字符显示指令? 图像像素数据? 返回主程序 显示图像编码 显示字符编码 JPEG 格式图像编码 调用字符库数据6 int i; float prob[MAX_SYMBOLS]; memset(prob, 0, sizeof(prob)); for(i = 0; i count / total; printf(“%c, %f\n“, (*pSF)[i]->symbol, prob[i]); } } } 2.计算熵 void calcEntrop(SymbolFrequencies *pSF) { int i; float prob[MAX_SYMBOLS]; double entropy; double difference; double difference1; double difference2; entropy = 0; for(i = 0; i < MAX_SYMBOLS; ++i) { difference1 = log(prob[i]); difference2 = log(2); difference = difference1/difference2; entropy = entropy - prob[i]*difference; } printf(

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是香农编码并计算信源熵的C语言实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define MAX_SYMBOLS 256 // 最大符号数 // 定义符号节点结构体(二叉树结点) typedef struct symbol_node { int freq; // 频率 char symbol; // 符号 struct symbol_node* left_child; // 左子树 struct symbol_node* right_child; // 右子树 } SymbolNode; // 定义符号表结构体 typedef struct { SymbolNode* symbols[MAX_SYMBOLS]; // 符号节点指针数组 int size; // 符号数 } SymbolTable; // 创建符号节点 SymbolNode* create_symbol_node(int freq, char symbol, SymbolNode* left_child, SymbolNode* right_child) { SymbolNode* node = malloc(sizeof(SymbolNode)); node->freq = freq; node->symbol = symbol; node->left_child = left_child; node->right_child = right_child; return node; } // 创建符号表 SymbolTable* create_symbol_Table() { SymbolTable* table = malloc(sizeof(SymbolTable)); memset(table, 0, sizeof(SymbolTable)); return table; } // 添加符号及其出现频率到符号表 void add_symbol_to_table(SymbolTable* table, char symbol) { for (int i = 0; i < table->size; i++) { if (table->symbols[i]->symbol == symbol) { table->symbols[i]->freq++; return; } } table->symbols[table->size++] = create_symbol_node(1, symbol, NULL, NULL); } // 比较函数 int compare(const void* a, const void* b) { SymbolNode* sn1 = *(SymbolNode**)a; SymbolNode* sn2 = *(SymbolNode**)b; return sn1->freq - sn2->freq; } // 构建哈夫曼树 SymbolNode* build_huffman_tree(SymbolTable* table) { qsort(table->symbols, table->size, sizeof(SymbolNode*), compare); int size = table->size; // 由小到大取出两个权重最小的节点,合并到一个新的节点中,形成二叉树 for (int i = 0; i < size - 1; i++) { SymbolNode* new_node = create_symbol_node(table->symbols[0]->freq + table->symbols[1]->freq, 0, table->symbols[0], table->symbols[1]); // 将新节点添加到符号数组中 table->symbols[0] = new_node; // 将后续节点依次前移,覆盖掉原来的节点 for (int j = 1; j < size - i - 1; j++) { table->symbols[j] = table->symbols[j + 1]; } size--; // 数组大小减一 qsort(table->symbols, size, sizeof(SymbolNode*), compare); } return table->symbols[0]; } // 通过哈夫曼树生成编码表 void generate_encoding_table(SymbolNode* root, int* code, int depth) { if (!root) return; // 叶子节点 if (!root->left_child && !root->right_child) { printf("%c: ", root->symbol); for (int i = 0; i < depth; i++) { printf("%d", code[i]); } printf("\n"); } // 左子树深度加一,并将 0 入栈(左子树为 0) code[depth] = 0; generate_encoding_table(root->left_child, code, depth + 1); // 右子树深度加一,并将 1 入栈(右子树为 1) code[depth] = 1; generate_encoding_table(root->right_child, code, depth + 1); } // 计算信源熵 double calculate_source_entropy(SymbolTable* table, int total) { double entropy = 0.0; for (int i = 0; i < table->size; i++) { SymbolNode* node = table->symbols[i]; double probability = (double) node->freq / (double) total; entropy += probability * log2(1 / probability); } return entropy; } int main() { char input_str[100]; printf("请输入信源字符串:\n"); gets(input_str); SymbolTable* table = create_symbol_Table(); int total_symbols = 0; // 统计每个字符的出现频率 for (int i = 0; i < strlen(input_str); i++) { add_symbol_to_table(table, input_str[i]); total_symbols++; } SymbolNode* root = build_huffman_tree(table); int encoding_table[MAX_SYMBOLS] = {0}; printf("各个字符的哈夫曼编码:\n"); generate_encoding_table(root, encoding_table, 0); double entropy = calculate_source_entropy(table, total_symbols); printf("信源熵为:%.4lf\n", entropy); return 0; } ``` 这个程序可以接收用户输入的任意字符串,计算该字符串的信源熵,并生成各个字符的哈夫曼编码。程序的实现过程包括如下步骤: 1. 创建一个符号表,用于存储输入字符串中的每个字符及其出现频率。 2. 统计输入字符串中的每个字符的出现频率,更新符号表。 3. 根据符号表,构建哈夫曼树。 4. 通过哈夫曼树生成各个字符的编码表。 5. 计算输入字符串的信源熵。 程序的核心算法是哈夫曼编码算法,该算法主要包括构建哈夫曼树、生成各个字符的编码表两个步骤。这个示例程序通过递归遍历哈夫曼树的方式,生成了各个字符的编码表。计算信源熵的公式为:$H(S)=-\sum_{i}^{n}p_i\log_2{p_i}$,其中 $p_i$ 表示第 $i$ 个字符的出现概率,$n$ 表示字符数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值