在数据压缩的领域里,香农-范诺编码(英语:Shannon–Fano coding)是一种基于一组符号集及其出现的概率(估量或测量所得),从而构建前缀码的技术。其名称来自于以克劳德·香农和罗伯特·法诺。在理想意义上,它与哈夫曼编码一样,并未实现码词(code word)长度的最低预期;然而,与哈夫曼编码不同的是,它确保了所有的码词长度在一个理想的理论范围
之内。这项技术是香农于1948年,在他介绍信息理论的文章“通信数学理论”中被提出的。
这个方法归功于范诺,他在不久以后以技术报告发布了它。 香农-范诺编码不应该与香农编码混淆,后者的编码方法用于证明Shannon's noiseless coding theorem,或与Shannon–Fano–Elias coding(又被称作Elias coding)一起,被看做算术编码的先驱。
香农-范诺编码,符号从最大可能到最少可能排序,将排列好的信源符号分化为两大组,使两组的概率和近于相同,并各赋予一个二元码符号“0”和“1”。只要有符号剩余,以同样的过程重复这些集合以此确定这些代码的连续编码数字。依次下去,直至每一组的只剩下一个信源符号为止。当一组已经降低到一个符号,显然,这意味着符号的代码是完整的,不会形成任何其他符号的代码前缀。
上面介绍的编码方法即为最原始简单的香农-范诺编码。下面我们用MATLAB来实现香农编码。
p=randsample(100,10); %随机生成10个数字
p=p/sum(p); %归一化处理使之成为符号概率
p=sort(p,'descend'); %倒叙排列
len=length(p);
for i=1:len
P(i)=sum(p(1:i))-p(i);
end
K=ceil(-log2(p));
for i=1:len
code{i}='';
end
for i=1:len
while length(code{i})<K(i)
if P(i)*2>=1
code{i}=[code{i},'1'];
P(i)=2*P(i)-1;
else
P(i)=2*P(i);
code{i}=[code{i},'0'];
end
end
end
h=sum(p.*(-log2(p)));k_anv=sum(p.*K);eff=h/k_anv;
fprintf('%s ','符号概率');fprintf(' %s ','累加概率');
fprintf('%s ','码字长度');fprintf('%s n','香农编码');
for i=1:len
fprintf('%f ',p(i));
fprintf(' %f ',P(i));
fprintf(' %d ',K(i));
disp(code{i});
end
fprintf('编码效率为%f',eff);
运行结果如下所示