赫夫曼编码
一、实验目的
利用赫夫曼编码进行通信可以大大提高通信利用率,缩短信息传输时间,降低传输成本。赫夫曼编码是信源编码中最基本的编码方法。
- 理解赫夫曼编码,无论是二进制赫夫曼编码,还是 m 进制赫夫曼编码,都要理解
其编码原理和编码步骤。
- 回顾无失真信源编码定理,理解无失真编码的基本原理和常用编码方法。。
- 掌握二进制赫夫曼编码和 m 进制赫夫曼编码的基本步骤,能计算其平均码长,编
码效率等。
- 应用二进制赫夫曼编码或 m 进制赫夫曼编码处理简单的实际信源编码问题
二,实验内容
- 单符号二进制赫夫曼编码
(1)赫夫曼树的定义:
当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。
(2)赫夫曼树(二叉树)的构建过程:
对于给定的有各自权值的 n 个结点,构建哈夫曼树有一个行之有效的办法:
1. 在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和;
2. 在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推;
3. 重复 1 和 2 ,直到所以的结点构建成了一棵二叉树为止,这棵树就是赫夫曼树。
3)赫夫曼编码的构建原理:
赫夫曼树中的结点结构:
(以二叉树为例)
由于哈夫曼树的构建是从叶子结点开始,不断地构建新的父结点,直至树根,所以结点中应包含指向父结点的指针。但是在使用哈夫曼树时是从树根开始,根据需求遍历树中的结点,因此每个结点需要有指向其左孩子和右孩子的指针。
结点结构代码:
def __init__(self, name, weight):
self.name = name #节点名
self.weight = weight #节点权重
self.left = None #节点左孩子
self.right = None #节点右孩子
self.father = None # 节点父节点
赫夫曼树构建流程
三.实验结果以及源码
(1)实验文件:
2 4 7 85 69 3 5 4 2 63 5 11 25 44 5 85 96 74 1 10 20 30 50 60 40 35
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
(2)二进制实验结果:
A : 111010001
B : 11101001
C : 0001111
D : 001
E : 1101
F : 00011101
G : 11101011
H : 11101010
I : 00011100
J : 1100
K : 0001010
L : 000110
M : 10100
N : 0110
O : 0001011
P : 010
Q : 100
R : 1111
S : 111010000
T : 000100
U : 111011
V : 10101
W : 0111
X : 1011
Y : 0000
Z : 11100
单符号二进制编码效率为: 99.16%
四。二进制代码
#hefuman.ppy
'''
huffman编码
'''
import copy
import math
class Node:
def __init__(self, name, weight):
self.name = name #节点名
self.weight = weight #节点权重
self.left = None #节点左孩子
self.right = None #节点右孩子
self.father = None # 节点父节点
#判断是否是左孩子
def is_left_child(self):
return self.father.left == self
#创建最初的叶子节点
def create_prim_nodes(data_set, labels):
if(len(data_set) != len(labels)):
raise Exception('数据和标签不匹配!')
nodes = []
for i in range(len(labels)):
nodes.append( Node(labels[i],data_set[i]) )
return nodes
# 创建huffman树
def create_HF_tree(nodes):
#此处注意,copy()属于浅拷贝,只拷贝最外层元素,内层嵌套元素则通过引用,而不是独立分配内存
tree_nodes = nodes.copy()
while len(tree_nodes) > 1: #只剩根节点时,退出循环
tree_nodes.sort(key=lambda node: node.weight)#升序排列
new_left = tree_nodes.pop(0)
new_right = tree_nodes.pop(0)
new_node = Node(None, (new_left.weight + new_right.weight))
new_node.left = new_left
new_node.right = new_right
new_left.father = new_right.father = new_node
tree_nodes.append(new_node)
tree_nodes[0].father = None #根节点父亲为None
return tree_nodes[0] #返回根节点
#获取huffman编码
def get_huffman_code(nodes):
codes = {}
for node in nodes:
code=''
name = node.name
while node.father != None:
if node.is_left_child():
code = '0' + code
else:
code = '1' + code
node = node.father
codes[name] = code
return codes
if __name__ == '__main__':
with open('C:/temps/ceshi.txt','r') as f:
content = list(f)
print(content)
str2 = content[1]
str1 = content[0]
str_list1 = str1.split()
str_list2 = str2.split()
str_list3 = str_list1
for i in range(0,len(str_list1)):
str_list3[i]=int(str_list1[i])
sum = 0
for i in str_list3:
sum = int(i+sum)
str_list4 = str_list3
for i in range(0,len(str_list1)):
str_list4[i]=str_list3[i] / sum
Hx = 0.00
for i in str_list4:
Hx = -i * math.log2(i) + Hx
print(str_list2)
print(str_list3)
labels = str_list2
data_set = str_list3
nodes = create_prim_nodes(data_set,labels)#创建初始叶子节点
root = create_HF_tree(nodes)#创建huffman树
codes = get_huffman_code(nodes)#获取huffman编码
#打印huffman码
#保存数据open函数
ki = 0
ka = 0.0
niu = 0.00
kba = 0.00
for key in codes.keys():
kba = str_list4[ki] * len(codes[key]) + kba
ki = ki+1
niu = Hx / kba
with open('C:/temps/hefumanjieguo.txt','w',encoding='utf-8') as f:#使用with open()新建对象f
for key in codes.keys():
print(key,': ',codes[key],)
bianma = [key,":" ,codes[key]]
print(bianma)
f.write(key)
f.write(' : ')
f.write(codes[key]+'\n')#写入数据,文件保存在上面指定的目录,加\n为了换行更方便阅读
f.write('单符号二进制编码效率为: {:.2f}%'.format(niu*100)+'\n')
print(niu)
print(kba)
print(Hx)
三进制编码
#sanjinzhihefuman.ppy
#hefuman.ppy
'''
huffman编码
'''
import copy
import math
class Node:
def __init__(self, name, weight):
self.name = name #节点名
self.weight = weight #节点权重
self.left = None #节点左孩子
self.mid = None #结点中孩子
self.right = None #节点右孩子
self.father = None # 节点父节点
#判断是否是左孩子
def is_left_child(self):
return self.father.left == self
def is_mid_child(self):
return self.father.mid == self
#创建最初的叶子节点
def create_prim_nodes(data_set, labels):
if(len(data_set) != len(labels)):
raise Exception('数据和标签不匹配!')
nodes = []
for i in range(len(labels)):
nodes.append( Node(labels[i],data_set[i]) )
return nodes
# 创建huffman树
def create_HF_tree(nodes):
#此处注意,copy()属于浅拷贝,只拷贝最外层元素,内层嵌套元素则通过引用,而不是独立分配内存
tree_nodes = nodes.copy()
while len(tree_nodes) > 1: #只剩根节点时,退出循环
tree_nodes.sort(key=lambda node: node.weight)#升序排列
new_left = tree_nodes.pop(0)
new_mid = tree_nodes.pop(0)
new_right = tree_nodes.pop(0)
new_node = Node(None, (new_left.weight + new_mid.weight + new_right.weight))
new_node.left = new_left
new_node.mid = new_mid
new_node.right = new_right
new_left.father = new_mid.father = new_right.father = new_node
tree_nodes.append(new_node)
tree_nodes[0].father = None #根节点父亲为None
return tree_nodes[0] #返回根节点
#获取huffman编码
def get_huffman_code(nodes):
codes = {}
for node in nodes:
code=''
name = node.name
while node.father != None:
if node.is_left_child():
code = '0' + code
elif node.is_mid_child():
code = '1' + code
else:
code = '2' + code
node = node.father
codes[name] = code
return codes
if __name__ == '__main__':
#读取文件并且把文件中的数据存入列表
with open('C:/temps/ceshi.txt','r') as f:
content = list(f)
print(content)
str2 = content[1]
str1 = content[0]
str_list1 = str1.split()
str_list6 = str1.split()
str_list2 = str2.split()
str_list3 = str_list1
str_list5 = str_list6
#计算各个数据的概率以及H(x)
for i in range(0,len(str_list1)):
str_list3[i]=int(str_list1[i])
sum = 0
for i in str_list3:
sum = int(i+sum)
str_list4 = str_list3
for i in range(0,len(str_list1)):
str_list4[i]=str_list3[i] / sum
Hx = 0.00
for i in str_list4:
Hx = -i * math.log2(i) + Hx
print(str_list4)
#计算个数,查看是否会缺数字
for i in range(0,100):
if len(str_list6) == 3*i-1:
str_list6.append('0')
str_list2.append('nan')
str_list7 = str_list6
for i in range(0,len(str_list6)):
str_list5[i]=int(str_list6[i])
str_list7[i]=str_list5[i] / sum
#输出验证一下
print(str_list2)
print(str_list5)
print(len(str_list2))
print(len(str_list5))
#开始正式编码
labels = str_list2
data_set = str_list5
nodes = create_prim_nodes(data_set,labels)#创建初始叶子节点
root = create_HF_tree(nodes)#创建huffman树
codes = get_huffman_code(nodes)#获取huffman编码
#计算编码效率
ki = 0
ka = 0.0
niu = 0.00
kba = 0.00
for key in codes.keys():
kba = str_list7[ki] * len(codes[key]) + kba
ki = ki+1
R = kba*math.log2(3)
niu = Hx / R
#存储文件
with open('C:/temps/sanjizhi.txt','w',encoding='utf-8') as f:#使用with open()新建对象f
for key in codes.keys():
print(key,': ',codes[key],)
bianma = [key,":" ,codes[key]]
print(bianma)
f.write(key)
f.write(' : ')
f.write(codes[key]+'\n')#写入数据,文件保存在上面指定的目录,加\n为了换行更方便阅读
f.write('单符号三进制编码效率为: {:.2f}%'.format(niu*100)+'\n')
print(niu)
print(kba)
print(Hx)