python实现huffman编码

huffman编码

为什么要用huffman编码?

1.减少编码的冗余,实现图像压缩。
2. huffman编码可以实现小概率数据用长码,大概率数据用短码,使得每个数据都能被唯一标识,即每一个信源符号都可被映射为一个固定的编码符号序列。

这里为了方便只是用一个二维数组char_weights存放事前给定数据。

实现思路:

  1. 如何将数据建立成一个huffman树
  2. 如何将建立好的Huffman树进行编码。

建立Huffman树:

  1. 先设置一个结构体,有value,name以及左右子节点数据。方便后续实现树的建立
class Node(object):
   def __init__(self,name=None,value=None):
       self._name=name
       self._value=value
       self._left=None
       self._right=None

  1. 注意我们这里以倒序的方式建立树

    1. 先将预先给定的二维数组中的每一对建立成一个节点Node,并用一个数组Leav存放这些节点。
    2. 用while循环一直判断该数组的长度是否为1,如果长度为1就跳出循环,直接将最后一个数作为root根节点。
      3.在while循环里的操作: 对Leav数组按照其value值进行从大到小的排序,对最后面的两个节点进行以下处理(实现每个节点其左右节点的创立):

    将他们的value之和给一个新创立的节点,该新节点的左右节点就是这两个,并将他们移除该数组,新创立的节点进该数组(末尾添加)。

    注意一下此时的新节点他没有名字,就连root根节点也没有名字,因为它只是中间节点不是叶子节点,叶子结点即预先给定的数才有名字。这在对生成树进行huffman编码中可以体现该作用

    1. 具体代码:
    def __init__(self,char_weights):
        self.Leav=[Node(part[0],part[1]) for part in char_weights]
        #根据输入的字符及其频数生成节点
        while len(self.Leav)!=1:
            #当reverse不为true时(默认为false),sort就是从小到大输出
            #因为要排序的是结构体里面的某个值,所以要用参数key
            #lambda是一个隐函数,是固定写法
            self.Leav.sort(key=lambda node:node._value,reverse=True)
            c=Node(value=(self.Leav[-1]._value+self.Leav[-2]._value))
            #数组pop默认删除最后一个元素,参数为-1可加可不加,并返回该值
            c._left=self.Leav.pop(-1)
            c._right=self.Leav.pop(-1)
            #在数组最后添加新对象
            self.Leav.append(c)
        #最后一个节点作为根节点
        self.root=self.Leav[0]
        self.Buffer=list(range(10))
    
    

实现Huffman编码

主要思想就是利用递归,循环调用函数,实现编码。

  1. 刚开始从根节点开始编码,因为它没有名字,所以无法对其进行编码,但是可以递归到它的左节点。如果其左节点还是没有名字,就会一直进入self_pre(node._left,length+1),直到本次执行的节点有名字。
  2. 要注意的是:range(length)是从0到length-1,所以这也是一个比较巧妙的点。因为编码即print的时候,就是依据这一点进行编码,其Buffer就是对于(从大到小的huffman树)实现每一层次的存放数据:0/1.
  3. 以前两个节点d,c为例,草图如下:(图片上传不了,算了)

完整代码

class Node(object):
    def __init__(self,name=None,value=None):
        self._name=name
        self._value=value
        self._left=None
        self._right=None

class HuffmanTree(object):
    #根据Huffman树的思想:以节点为基础,反向建立Huffman树
    def __init__(self,char_weights):
        self.Leav=[Node(part[0],part[1]) for part in char_weights]
        #根据输入的字符及其频数生成节点
        while len(self.Leav)!=1:
            #当reverse不为true时(默认为false),sort就是从小到大输出
            #因为要排序的是结构体里面的某个值,所以要用参数key
            #lambda是一个隐函数,是固定写法
            self.Leav.sort(key=lambda node:node._value,reverse=True)
            c=Node(value=(self.Leav[-1]._value+self.Leav[-2]._value))
            #数组pop默认删除最后一个元素,参数为-1可加可不加,并返回该值
            c._left=self.Leav.pop(-1)
            c._right=self.Leav.pop(-1)
            #在数组最后添加新对象
            self.Leav.append(c)
        #最后一个节点作为根节点
        self.root=self.Leav[0]
        self.Buffer=list(range(10))

#用递归的思想生成编码
    def pre(self,tree,length):
        node=tree
        if (not node):
            return
        elif node._name:
            print (node._name + '    encoding:',end=''),
            for i in range(length):
                print (self.Buffer[i],end='')
            print ('\n')
            return
        self.Buffer[length]=0
        self.pre(node._left,length+1)
        self.Buffer[length]=1
        self.pre(node._right,length+1)

     #生成哈夫曼编码
    def get_code(self):
        self.pre(self.root,0)

if __name__=='__main__':
    #输入的是字符及其频数
    char_weights=[('a',6),('b',4),('c',10),('d',8),('f',12),('g',2)]
    tree=HuffmanTree(char_weights)
    tree.get_code()

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值