编码方式对信源熵的影响
时间: 2023-06-08 08:07:38 浏览: 93
编码方式会对信源熵产生影响。如果使用不同的编码方式,就可以通过减少数据传输的冗余信息来提高信息的传输效率。这种冗余信息就是指不必要的信息,比如 不同的字符出现的次数,这些字符应该使用尽可能少的码字进行编码,从而节省传输成本。因此,根据信源分布和不同的编码方式,我们可以得到不同的编码效率和解码效率。
相关问题
香农编码并计算信源熵c语言实现
以下是香农编码并计算信源熵的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$ 表示字符数。
在Matlab中利用二叉树来实现霍夫曼编码,不能够使用自带的霍夫曼函数,注意是对已给的概率进行霍夫曼编码,同时能够有概率之和相等向上排和向下排两种方案,并且图形化显示码长编码效率和信源熵
实现霍夫曼编码需要以下几个步骤:
1. 根据给定的概率建立霍夫曼树:将概率作为权值,构建出一棵二叉树。树中每个节点都有一个权值,叶子节点的权值即为每个符号出现的概率。
2. 对霍夫曼树进行编码:从根节点开始,遍历二叉树,对左边的分支编码为0,对右边的分支编码为1。将每个符号的编码存储在字典中。
3. 对原始数据进行压缩:将每个符号用其对应的编码替换,生成压缩后的数据。
以下是在 Matlab 中实现霍夫曼编码的代码,其中包括对已给的概率进行霍夫曼编码,以及能够有概率之和相等向上排和向下排两种方案,并且图形化显示码长编码效率和信源熵。
```matlab
% 计算霍夫曼编码
function [dict, code] = huffman_encode(p, direction)
% p: 概率分布
% direction: 编码方向,1为向上排,0为向下排
% dict: 字典,包含每个符号的霍夫曼编码
% code: 压缩后的数据
n = length(p);
% 建立霍夫曼树
if direction == 1 % 向上排
[~, idx] = sort(p, 'descend');
else % 向下排
[~, idx] = sort(p, 'ascend');
end
p = p(idx);
nodes = cell(n, 1);
for i = 1:n
nodes{i} = struct('val', idx(i), 'left', [], 'right', []);
end
while length(nodes) > 1
node1 = nodes{1};
node2 = nodes{2};
nodes = nodes(3:end);
newNode = struct('val', -1, 'left', node1, 'right', node2);
pNew = p(1) + p(2);
p = [p(3:end); pNew];
nodes{end+1} = newNode;
[~, idx] = sort(p, 'descend');
p = p(idx);
nodes = nodes(idx);
end
root = nodes{1};
% 对霍夫曼树进行编码
dict = cell(n, 2);
for i = 1:n
node = root;
path = '';
while node.val ~= i
if ismember(i, [node.left.val])
node = node.left;
path = strcat(path, '0');
else
node = node.right;
path = strcat(path, '1');
end
end
dict{i, 1} = idx(i);
dict{i, 2} = path;
end
% 对原始数据进行压缩
code = '';
for i = 1:n
idx = dict{i, 1};
path = dict{i, 2};
code = strcat(code, repmat(path, p(i)*100, 1));
end
% 显示码长编码效率和信源熵
avgLen = 0;
for i = 1:n
avgLen = avgLen + length(dict{i, 2}) * p(i);
end
fprintf('平均码长:%f\n', avgLen);
efficiency = (1 - avgLen/log2(n)) * 100;
fprintf('编码效率:%f%%\n', efficiency);
entropy = -sum(p.*log2(p));
fprintf('信源熵:%f\n', entropy);
% 显示霍夫曼树
figure;
plot_tree(root, 0, n);
end
% 绘制霍夫曼树
function plot_tree(node, level, n)
if ~isempty(node.left)
plot_tree(node.left, level+1, n);
line([node.left.val-1, node.val-1], [n-level, n-level-1], 'LineWidth', 2);
end
if ~isempty(node.right)
plot_tree(node.right, level+1, n);
line([node.right.val-1, node.val-1], [n-level, n-level-1], 'LineWidth', 2);
end
rectangle('Position', [node.val-1, n-level-1, 1, 1], 'LineWidth', 2, 'EdgeColor', 'k');
text(node.val-0.5, n-level-0.5, num2str(node.val), 'HorizontalAlignment', 'center');
axis equal off;
end
```
可以通过以下方式调用该函数:
```matlab
p = [0.2, 0.3, 0.1, 0.15, 0.05, 0.2];
[dict, code] = huffman_encode(p, 0);
```
其中 p 表示每个符号出现的概率,dict 是编码字典,code 是压缩后的数据。通过改变 direction 参数可以选择向上排或向下排进行编码。
阅读全文