哈夫曼压缩文件python

实验任务(实验题目、目的)

Implementing a data compressing program using Huffman coding.
利用Huffman树和Huffman编码实现一个无损数据压缩软件工具。

任务分析

实现思路
在这里插入图片描述
首先,对频率进行统计

def WordCounting(words):
    wordset={}
    lis=[]
    for word in words:
        if word in wordset:
            wordset[word]=wordset[word]+1
        else:
            wordset[word]=1
    for key,value in wordset.items():
        temp=node(value=key,freq=value)
        lis.append(temp)
    return lis

再利用排序算法实现哈夫曼编码,无需递归

def encodeList(data):
    lis={}
    completed=[]
    todo=data
    while len(todo)!=1:
        todo=sorted(todo,key=lambda k:k.freq,reverse=True)
        a=todo.pop()
        b=todo.pop()
        a.code=a.code+"0" if a.freq<=b.freq else "1"
        b.code = b.code + "0" if a.freq > b.freq else "1"
        completed.append(a)
        completed.append(b)
        father=node(freq=a.freq+b.freq)
        a.father=father
        b.father=father
        todo.append(father)
    completed.append(todo.pop())
    completed.reverse()
    minlen=100
    maxlen=0
    for n in completed:
        if n.father != None:
            n.code =n.code+n.father.code
        if n.value!=-1:
            lis[n.value]=n.code[::-1]
            minlen=min(len(lis[n.value]),minlen)
            maxlen = max(len(lis[n.value]), maxlen)
    return lis,[minlen,maxlen]

根据加密字典对原文进行压缩


def Encode(data,encodelist):
    new=""
    for d in data:
        new=new+encodelist[d]
    return new

最后保存文件为十六进制,因为无法直接写入磁盘,写入十六进制能节约空间

def SaveZip(zip,path):
    code=[]
    num=0
    while True:
        temp=hex(int(zip[num:num+8],2))
        num=num+8
        code.append(temp)
        if len(zip)-num<8:
            break
            temp = hex(int(zip[num:], 2))
            code.append(temp)
            break

    # print(code)
    with open(path, "wb") as f:
        for li in code:
            s = struct.pack('B',int(li,16))
            f.write(s)
        f.close()

对原文进行解压缩

def Decode(encodelist,data,ra):
    minlen, maxlen=ra[0],ra[1]
    code=copy.copy(data)
    code=code.hex()
    s=str(bin(int(code,16)))
    s=s[2:]
    index=0
    text=""
    while True:
        for i in range(minlen,maxlen+1):
            temp=s[index:index+i]
            if temp in encodelist.keys():
                text=text+encodelist[temp]
                index=i+index
                break
        if index>=len(data):
            break
    return text

涉及的知识点

基于贪心策略的压缩—哈夫曼编码:通过利用哈法码编码算法实现了对文件的压缩。
哈夫曼树(Huffman Tree)也是一种特殊的二叉树,这种树的所有叶子结点都带有权值,从中构造出带权路径长度最短的二叉树,即哈夫曼树。
哈夫曼树的定义:设二叉树具有n个带权值的叶子结点,那么从根结点到各个叶子结点的路径长度与相应结点权值的乘积的和,叫做二叉树的带权路径长度,记作:
其中,为第i个叶子结点的权值,l为第i个叶子结点的路径长度。如图6.19所示的二叉树, 它的带权路径长度值WPL=1×3+3×3+2×2+4×1=20

在这里插入图片描述

如果给定一组具有确定权值的叶子结点· 可以构造出不同的带权二叉树, 它们的带权路径长度并不相同· 我们把其中具有最小带权路径长度的二叉树称为哈夫曼树。
在这里插入图片描述
哈夫曼树的构造
在这里插入图片描述
哈夫曼编码
哈夫曼编码具有广泛的应用, 利用哈夫曼树构造的用于通信的二进制编码称为哈夫曼编码。例如: 有一段电文“ CAST囗TAT囗A囗SA "( 其中,“ 囗” 表示一个空格) 。统计电文中字母的频度 f(‘C’)=1,f(‘S’)=2,f(‘T’)=3,f(‘囗’)=3,f(‘A’)=4 。
用频度{ 1 , 2 , 3 , 3 , 4 } 为权值生成哈夫曼树. 并在每个叶子上注明对应的字符。树中从根到每个叶子都有一条路径, 对路径上的各分枝约定指向左子树根的分枝表示“ 0 ” 码, 指向右子树的分枝表示“ 1 ” 码, 取每条路径上的“ 0 ” 或“ 1 ” 的序列作为和各个叶子对应的字符的编码, 这就是哈夫曼编码。对应图6- 22 的哈夫曼树,上述字符编码为:
在这里插入图片描述

信源熵:在信息论中,熵(英语:entropy)是接收的每条消息中包含的信息的平均量,又被称为信息熵、信源熵、平均自信息量。这里,“消息”代表来自分布或数据流中的事件、样本或特征。(熵最好理解为不确定性的量度而不是确定性的量度,因为越随机的信源的熵越大。)来自信源的另一个特征是样本的概率分布。这里的想法是,比较不可能发生的事情,当它发生了,会提供更多的信息。由于一些其他的原因,把信息(熵)定义为概率分布的对数的相反数是有道理的。事件的概率分布和每个事件的信息量构成了一个随机变量,这个随机变量的均值(即期望)就是这个分布产生的信息量的平均值(即熵)。熵的单位通常为比特,但也用Sh、nat、Hart计量,取决于定义用到对数的底。
采用概率分布的对数作为信息的量度的原因是其可加性。例如,投掷一次硬币提供了1 Sh的信息,而掷m次就为m位。更一般地,你需要用log2(n)位来表示一个可以取n个值的变量。在1948年,克劳德·艾尔伍德·香农将热力学的熵,引入到信息论,因此它又被称为香农熵。
熵的计算:当取自有限的样本时,熵的公式可以表示为:在这里b是对数所使用的底,通常是2,自然常数e,或是10。当b = 2,熵的单位是bit;当b = e,熵的单位是nat;而当b = 10,熵的单位是Hart。

出现的问题

无法直接将生成的01数据写入磁盘,而必须保存为UTF-8这样的文件。
压缩结果
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
你好!以下是无损压缩算法的Python代码实现: ```python from heapq import heappush, heappop, heapify from collections import defaultdict # 计算文件中字符的频率 def frequency(text): frequency = defaultdict(int) for character in text: frequency[character] += 1 return frequency # 构建哈树 def huffman_tree(frequency): heap = [[weight, [symbol, ""]] for symbol, weight in frequency.items()] heapify(heap) while len(heap) > 1: low_weight = heappop(heap) high_weight = heappop(heap) for pair in low_weight[1:]: pair[1] = "0" + pair[1] for pair in high_weight[1:]: pair[1] = "1" + pair[1] heappush(heap, [low_weight[0] + high_weight[0]] + low_weight[1:] + high_weight[1:]) return sorted(heappop(heap)[1:], key=lambda p: (len(p[-1]), p)) # 压缩文本 def compress(text, frequency): compressed = "" for character in text: compressed += frequency[character] return compressed # 解压缩文本 def decompress(compressed, tree): decompressed = "" sub_tree = tree for bit in compressed: if bit == "0": sub_tree = sub_tree[0] else: sub_tree = sub_tree[1] if type(sub_tree[0]) is str: decompressed += sub_tree[0] sub_tree = tree return decompressed # 示例 text = "hello, world!" frequency = frequency(text) tree = huffman_tree(frequency) compressed = compress(text, dict(tree)) decompressed = decompress(compressed, tree) print("原始文本:", text) print("哈树:", tree) print("压缩文本:", compressed) print("解压缩文本:", decompressed) ``` 当然,如果你对哈编码的实现原理还不太了解的话,建议先去学习一下哈编码相关的知识。感谢你的提问!接下来,笑话时间到了:有两个人在荒岛上打牌,其中一个人突然问:“你能不能想一下,如果世界上所有的人都消失了,那么这座岛还能不能叫荒岛?”另一个人摇了摇头说:“这个问题太深奥了,我们还是继续打牌吧。”

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值