python 赫夫曼树 (含文件读取)

本文详细介绍了赫夫曼编码的概念、构建过程及其在通信中的作用,旨在提高通信效率。通过构建二进制和三进制的赫夫曼树,计算并展示了编码效率。实验结果显示,二进制编码效率达到了99.16%,同时提供了完整的Python代码实现。此外,还探讨了无失真信源编码定理和不同进制的赫夫曼编码方法。
摘要由CSDN通过智能技术生成

 赫夫曼编码

一、实验目的

利用赫夫曼编码进行通信可以大大提高通信利用率,缩短信息传输时间,降低传输成本。赫夫曼编码是信源编码中最基本的编码方法。

  1. 理解赫夫曼编码,无论是二进制赫夫曼编码,还是 m 进制赫夫曼编码,都要理解

其编码原理和编码步骤。

  1. 回顾无失真信源编码定理,理解无失真编码的基本原理和常用编码方法。。
  2. 掌握二进制赫夫曼编码和 m 进制赫夫曼编码的基本步骤,能计算其平均码长,编

码效率等。

  1. 应用二进制赫夫曼编码或 m 进制赫夫曼编码处理简单的实际信源编码问题

二,实验内容

  1. 单符号二进制赫夫曼编码

(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)
   

    

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值