逻辑与代码 3

这篇博客介绍了如何使用Prolog编程语言实现哈夫曼编码。通过一系列的谓词,如`initialize`、`make_tree`和`traverse_tree`,从符号频率列表构建霍夫曼树,并生成相应的霍夫曼编码。示例展示了如何处理符号频率列表 `[fr(a,45),fr(b,13),fr(c,12),fr(d,16),fr(e,9),fr(f,5)]`,得到哈夫曼编码表 `[hc(a, '0'), hc(b, '101'), hc(c, '100'), hc(d, '111'), hc(e, '1101'), hc(f, '1100')]`。最后,博客还展示了计算平均编码长度和输出统计信息的步骤。" 122764758,8753399,VTK实战:等高线到曲面转换,"['图形渲染', 'C++编程', 'VTK库', '3D建模', 'Visual Studio']
摘要由CSDN通过智能技术生成

转载自:https://mp.weixin.qq.com/s/JkjTL5yGhNQaww6GMiwX1A

5、哈夫曼码

首先,研究一本有关离散数学或算法的好书,以详细描述霍夫曼代码,或者查阅 维基百科。

我们假设一组符号及其频率作为frSF)项的列表给出。

例如: [fr(a,45),fr(b,13),fr(c,12),fr(d,16),fr(e,9),fr(f,5)]. 

 我们的目标是构造一个列表hc(S,C)项,其中C是符号S的霍夫曼代码字。在我们的示例中,结果可能是[hc(a, '0'), hc(b, '101'), hc(c, '100'), hc(d, '111'), hc(e, '1101'),  hc(f, '1100')] 

 

该任务应由以下定义的谓词huffman/2执行:

huffman(Fs,Hs):- Hs是频率表Fs (list-of-fr/2-terms, list-of-hc/2-terms)的霍夫曼代码表。

在构造过程中,我们需要节点n(F,S),其中开始时F是频率,S是符号。在此过程中,随着n(F,S)成为内部节点,S成为项s(L,R),其中LR再次成为n(F,S)项。称为Nsn(F,S)项列表被维护为一种优先级队列。

 

1  huffman(Fs,Cs) :-

2 initialize(Fs,Ns),

3 make_tree(Ns,T),

4 traverse_tree(T,Cs).

5

注释行:

1.

2.  初始化

3.  生成树

4.  遍历树T并构造霍夫曼代码表Cs

5.  空行

 

6  initialize(Fs,Ns) :- 

7 init(Fs,NsU),

8 sort(NsU,Ns).

9

注释行:

6. 

7.  %根据列表Fs初始化列表项NsU

8.  %对列表项NsU排序,结果放到Ns

9.  

 

10 init([],[]).

11 init([fr(S,F)|Fs],[n(F,S)|Ns]) :-

12  init(Fs,Ns).

13

注释行:

10. %终止条件

11. %根据列表Fs内的元素项重新名命函子名为n的项的列表

12. %递归遍历处理后续列表项

13. 空行

 

测试:

?- init([fr(a,45),fr(b,13),fr(c,12),fr(d,16),fr(e,9),fr(f,5)],X),sort(X,Y).

X = [n(45, a), n(13, b), n(12, c), n(16, d), n(9, e), n(5, f)],

Y = [n(5, f), n(9, e), n(12, c), n(13, b), n(16, d), n(45, a)].

 

14 make_tree([T],T).

15 make_tree([n(F1,X1),n(F2,X2)|Ns],T) :- 

16 F is F1+F2,

17 insert(n(F,s(n(F1,X1),n(F2,X2))),Ns,NsR),

18 write('Ns = '),write(Ns),nl,

19 write('NsR = '),write(NsR),nl,

20 make_tree(NsR,T).

21

注释行:

14. 参数1列表中的项T,与参数2相同则终止

15. 

16. 取列表的前两项的参数F1与F2求和后的值赋给F

17. 将节点n(F,s(n(F1,X1),n(F2,X2)))加入到Ns

18. 运行时观察点

19. 运行时观察点

20. 递归继续生成树

21. 

 

我们来观察make_tree运行的过程

?- init([fr(a,45),fr(b,13),fr(c,12),fr(d,16),fr(e,9),fr(f,5)],X),sort(X,Y),write('Y = '),write(Y),nl,make_tree(Y,Z).

Y = [n(5,f),n(9,e),n(12,c),n(13,b),n(16,d),n(45,a)]

Ns = [n(12,c),n(13,b),n(16,d),n(45,a)]

NsR = [n(12,c),n(13,b),n(14,s(n(5,f),n(9,e))),n(16,d),n(45,a)]

Ns = [n(14,s(n(5,f),n(9,e))),n(16,d),n(45,a)]

NsR = [n(14,s(n(5,f),n(9,e))),n(16,d),n(25,s(n(12,c),n(13,b))),n(45,a)]

Ns = [n(25,s(n(12,c),n(13,b))),n(45,a)]

NsR = [n(25,s(n(12,c),n(13,b))),n(30,s(n(14,s(n(5,f),n(9,e))),n(16,d))),n(45,a)]

Ns = [n(45,a)]

NsR = [n(45,a),n(55,s(n(25,s(n(12,c),n(13,b))),n(30,s(n(14,s(n(5,f),n(9,e))),n(16,d)))))]

Ns = []

NsR = [n(100,s(n(45,a),n(55,s(n(25,s(n(12,c),n(13,b))),n(30,s(n(14,s(n(5,f),n(9,e))),n(16,d)))))))]

X = [n(45, a), n(13, b), n(12, c), n(16, d), n(9, e), n(5, f)],

Y = [n(5, f), n(9, e), n(12, c), n(13, b), n(16, d), n(45, a)],

Z = n(100, s(n(45, a), n(55, s(n(25, s(n(12, c), n(13, b))), n(30, s(n(14, s(n(5, f), n(9, e))), n(16, d))))))) .

22 insert(N,[],[N]) :- !. %

23 insert(n(F,X),[n(F0,Y)|Ns],[n(F,X),n(F0,Y)|Ns]) :- 

24 F < F0, !.

25 insert(n(F,X),[n(F0,Y)|Ns],[n(F0,Y)|Ns1]) :- 

26 F >= F0

27 insert(n(F,X),Ns,Ns1).

28

注释行:

22. 当参数项1是参数3的列表项则截断终止

23. 将节点n(F,X)插入到Ns中,以使结果列表NsR再次相对于频率F进行排序。

24. 当F小于F0此节点的插入作为终结点

25. 

26. 当F大于等于F0

27. 继续递归插入后续节点

28. 

 

29 traverse_tree(T,Cs) :-

30 traverse_tree(T,'',Cs1-[]),

31 sort(Cs1,Cs). 

32

33 traverse_tree(n(_,A),Code,[hc(A,Code)|Cs]-Cs) :- 

34 atom(A).

35 traverse_tree(n(_,s(Left,Right)),Code,Cs1-Cs3) :-        

36 atom_concat(Code,'0',CodeLeft),

37 atom_concat(Code,'1',CodeRight),

38 traverse_tree(Left,CodeLeft,Cs1-Cs2),

39 traverse_tree(Right,CodeRight,Cs2-Cs3).

40

注释行:

29. 遍历树T并构造霍夫曼代码表Cs   traverse_tree/2

30. 根据T生成Cs1-[],Cs1是列表

31. 将列表Cs1排序后放入Cs作为结果

32. 空行

33. traverse_tree/3

34. 如果A是原子(叶)则此分支终止

35. 内部节点

36. 将字符’0‘拼接到Code原子的后面结果放入CodeLeft

37. 将字符’1‘拼接到Code原子的后面结果放入CodeRight

38. 递归处理左树

39. 递归处理右树

40. 空行

 

41 huffman(Fs) :- 

42 huffman(Fs,Hs) , 

43 nl

44 report(Hs,5), 

45 stats(Fs,Hs), 

46 write('Hs = '),write(Hs),nl.

47

注释行:

41. 输出统计信息

42. 生成哈夫曼码

43. 

44. 输出报表

45. 统计

46. 调试观察点

47. 

 

48 report([],_) :-

49 !, 

50 nl

51 nl.

52 report(Hs,0) :- 

53 !, 

54 nl

55 report(Hs,5).

56 report([hc(S,C)|Hs],N) :- 

57 N > 0N1 is N-1,

58 writef('%w %w  ',[S,C]),

60 report(Hs,N1).

61

注释行:

48. 报表为空截断后输出两行换行

49. 

50. 

51. 

52. 取值0,5的问题留给读者

53. 

54. 

55. 

56. 

57. 确保N大于0 ,并且N减以后赋值给N1

58. 打印输出

59.

60. 递归输出

61. 

 

62 stats(Fs,Cs) :- 

63 sort(Fs,FsS),

64 sort(Cs,CsS),

65 stats(FsS,CsS,0,0).

66

67 stats([],[],FreqCodeSum,FreqSum) :- 

68 Avg is FreqCodeSum/FreqSum,

69 writef('Average code length (weighted) = %w\n',[Avg]).

70 stats([fr(S,F)|Fs],[hc(S,C)|Hs],FCS,FS) :- 

71 atom_chars(C,CharList), 

72 length(CharList,N),

72 FCS1 is FCS + F*N,

73 FS1 is FS + F,  

74 stats(Fs,Hs,FCS1,FS1).

75   

注释行:

62. 

63. %排序列表Fs,放到列表FsS中

64. %排序列表Cs,放到列表CsS中

65. 

66. 

67. 

68. 

69. %输出平均值

70. 

71. %将字符串S装换为字符列表

72. %得到字符列表长度放到N

72. %初始值从0做递归累计

73. %初始值从0做递归累计

74. %递归累计

 

 

运行结果:

?- X = [fr(a,45),fr(b,13),fr(c,12),fr(d,16),fr(e,9),fr(f,5)], huffman(X).

 

a 0  b 101  c 100  d 111  e 1101  

f 1100  

 

Average code length (weighted) = 2.24

Hs = [hc(a,0),hc(b,101),hc(c,100),hc(d,111),hc(e,1101),hc(f,1100)]

X = [fr(a, 45), fr(b, 13), fr(c, 12), fr(d, 16), fr(e, 9), fr(f, 5)] .

 

?- 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值