霍夫曼编码(matlab)学习笔记

(学生小白的学习笔记,若有侵权,联系后立即删除。贴上: 参考网址,笔记都是以自身学习状况和脑回路方便自己理解为原则写,如有欠缺或语言逻辑请见谅,若有问题也感谢指出,所有代码部分组合就是完整程序。)

手动霍夫曼编码大致思路:

(1)按从小到大的顺序排列
(2)合并最小两项,分别标记为0和1
(3)合并项与剩下的项重复以上步骤
(4)剩下只有两项时,按标记的倒序给对应项编码

matlab编码的大致思路:

以P=[0.1 0.2 0.3 0.4],顺序标记为1234,N=4举例

在这里插入图片描述

码树构建

霍夫曼编码(matlab)学习笔记_第1张图片

(1)输入概率向量,检测合法性(每项不小于零,合等于1)

%取得信源概率矩阵,并进行合法性判断
P=input('请输入信源概率向量P=' );

N=length(P);
for component=1:1:N
if (P (component) <0)
error('信源概率不能小于0');
end
end
if((sum(P)-1)>0.0001)
error('信源概率之和必须为1');
end

(2)建:每次检索向量L(1,N);每次的排序向量Q(1,N);总的检索向量index(N-1,N);总的顺序向量G(N-1,N);

(3)合并Q的前两项,排序成下一个Q,每次的位置标记存入L,循环N-1次。一次Q为G的一个行向量,缺的地方补1,一次L为index的一个行向量,缺的地方补0;

%建立各概率符号的位置索引矩阵Index,利于编码后从树根进行回溯,从而得出对应的编码
Q=P;
Index=zeros(N-1,N); %初始化Index
for i=1:N-1
[Q, L]=sort(Q) ;%注释①
Index(i, :)=[L(1:N-i+1), zeros(1, i-1)];
G(i,:)=Q;
Q=[Q(1)+Q(2), Q(3:N), 1]; %将Q中概率最小的两个元素合并,元素不足的地方补1
end
0.1 0.2 0.3 0.4
0.3 0.3 0.4 1
0.4 0.6 1 1

记录顺序的G向量如上表

1 2 3 4
1 2 3 0
2 1 0 0

检索记录index向量如上表

码树建立过程到此就结束了,接下来就是回溯过程。我们有按顺序结合后的向量(码树),也有它顺序改变的路径(index)。接下来就是在码数树上赋予编码,并且根据路径找到概率对应的总编码。

码树回溯

霍夫曼编码(matlab)学习笔记_第2张图片

(4)建:Char(N-1,N2)(这个向量用来放编码,一行即为一次排序,输入的P长度为N,每一个概率最长码长为N,所以每一列的长度为N×N,没编码的地方为定义为空。从N-1行开始编,知道第一层,第一层即为霍夫曼编码。)

%根据以上建立的Index矩阵,进行回溯,获取信源编码
for i=1:N-1
Char(i, :)=blanks (N*N) ; %初始化一一个由空格符组成的字符矩阵N*N,用于存放编码
end

(5)给第Char的N-1行赋值:给index的最后一行的两个数分别编码为0和1,存入Char的N-1行的第N列和第2*N列。

char的最后一行 0 1 …(共16列)
%从码树的树根向树叶回溯,即从G矩阵的最后一行按与Index中的索引位置的对应关系向其第--行进行编码
Char(N-1,N)='0' ;%G中的N-1行即最后一行第一个元素赋为0,存到Char中N-1行的N列位置
Char(N-1, 2*N)='1';%G中的N-1行即最后一行第二个元素赋为1,存到Char中N-1 行的2*N列位置

(6)从N-2行到第一行,找出index中为1的数(即对应G中上一行的最小两个数0.3和0.3的合0.6),给那两个最小数(0.3和0.3)的编码的最后一位分别编为0和1(Chars的第N列赋值为0,Chars的第N*2列赋值为1)。然后将0.6的编码加在这两个数的编码前面。

最小的两个数(0.1和0.2)编码最后一位赋0和1,编码前面的位照搬合(0.3)的编码。循环至第一行。

%以下从G的倒数第二行开始向前编码
for i=2:N-1
Char (N-i, 1:N-1)=Char (N-i+1, N* (find (Index(N-i+1, :)==1))- (N-2) :N* (find (Index(N-i+1, :)==1))) ;
%将Index后一行中索引为1的编码码字填入到当前行的第一-个编码位置
Char(N-i,N)='0' ; %然后在当前行的第一一个编码位置末尾填入'0'
Char (N-i, N+1:2*N-1)=Char(N-i, 1:N-1); %将G后- -行中索引为1的编码码字填入到当前行的第二个编码位置
Char(N-i, 2*N)='1'; %然后在当前行的第二个编码位置末尾填入’1

(7)把其余空缺的编码按顺序补上

for j=1:i-1
%内循环作用:将Index后一行中索引不为1处的编码按照左右顺序填入当前行的第3个位置开始的地方,最后计算到Index的首行为止
Char(N-i, (j+1) *N+1: (j+2)*N) =Char (N-i+1, N* (find(Index(N-i+1, :)==j+1)-1) +1:N*find (Index(N-i+1, :)==j+1)) ;
end
end

(8)至此,霍夫曼编码已经完成,即Chars向量的第一行,现在要把他们分离出来。

%Char中第一行的编码结果就是所需的Huffman编码输出,通过Index中第--行索引将编码对应到相应概率的信源符号上。
for i=1:N
Result(i, 1:N)=Char(1, N*(find(Index(1, :)==i)-1) +1:find (Index(1, :)==i)*N) ;
end

%打印编码结果
String='信源概率及其对应的Huffman编码如下';
disp (String) ;disp(P) ;disp(Result) ;

注释①

在这里插入图片描述
霍夫曼编码(matlab)学习笔记_第3张图片
霍夫曼编码(matlab)学习笔记_第4张图片霍夫曼编码(matlab)学习笔记_第5张图片

转置:transpose(x)或者是x.’ (加.)

总结

这是第一次写学习笔记,之前其实有交过很多次编程作业,不过像这种固定的编码的代码,网上都有很多,我觉得只要会用就行。这是第一次一行一行的读代码,自己弄懂,其实挺快的,也不是那么枯燥。但我实在做事有点拖沓,喜欢一做就要求每个细节都要弄懂,或者完全犯懒一点不涉及。就像追剧,我不爱看剧,但有时候看了,就一定会通宵把他看完。吃东西要么就不吃,要么就必吃光。其实也知道一切细水长流慢慢积累才是最持久,最有效的。编程或者深度学习类的都前沿了,把基础完全弄懂是不大可能的,重要的是能拿来用,要敢于尝试,这是我最大的问题了,不敢尝试,漫漫长路要启程啊。

你可能感兴趣的:(matlab学习日记,matlab,霍夫曼树,编码器)