神秘的哈夫曼编码

神秘的哈夫曼编码

       哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。

       假设我们原有的字符串为:

               Nature has given us that two ears, two eyes, and but one tongue, to the end that we should hear and see more than we speak.(天赋我们两耳,两眼,一张嘴巴,归根到底该多听,多看,少说话。)
               我们如果需要在网络中传输就需要把它转换为计算机认识的0和1,下面是进过转换的二进制编码:

0b10011100b11000010b11101000b11101010b11100100b11001010b1000000b11010000b11000010b11100110b1000000b11001110b11010010b11101100b11001010b11011100b1000000b11101010b11100110b1000000b11101000b11010000b11000010b11101000b1000000b11101000b11101110b11011110b1000000b11001010b11000010b11100100b11100110b1011000b1000000b11101000b11101110b11011110b1000000b11001010b11110010b11001010b11100110b1011000b1000000b11000010b11011100b11001000b1000000b11000100b11101010b11101000b1000000b11011110b11011100b11001010b1000000b11101000b11011110b11011100b11001110b11101010b11001010b1011000b1000000b11101000b11011110b1000000b11101000b11010000b11001010b1000000b11001010b11011100b11001000b1000000b11101000b11010000b11000010b11101000b1000000b11101110b11001010b1000000b11100110b11010000b11011110b11101010b11011000b11001000b1000000b11010000b11001010b11000010b11100100b1000000b11000010b11011100b11001000b1000000b11100110b11001010b11001010b1000000b11011010b11011110b11100100b11001010b1000000b11101000b11010000b11000010b11011100b1000000b11101110b11001010b1000000b11100110b11100000b11001010b11000010b11010110b101110

               统计了一下有1078个字符
               那么如果我们利用赫夫曼编码进行缩短后呢?

110101111101111110111001110100011111100110001100001101010110100110101010011011011000111101111110111100111110010010000101111010011011010000001111100100100001011101000101011010000001110010110001001100111110111111000100010110100111101000101110000110111011000000111101000011110111101001010101100010011110111111011110010010101000110011101001101111001101000100011110111101001100111001011000100011010110100110010101001001110100111101111110010100100101010001101100100101111011000111100010

               仅且只有480个字符
               压缩率为44.5%,超过了一般,就是我们在互联网发送中,我们可以节省一半的时间去发这句话,接下来我们就来讲解下如何实现Huffman Coding:
               定义树的节点:
class Node:
    def __init__(self, data):
        self.data = data[0]  # 节点的值(保存字符)
        self.left = None  # 节点的左子节点
        self.right = None  # 节点的右子节点
        self.weight = data[1]  # 节点的值(保存字符出现的次数)

 

 

统计字符出现的次数,并转换为Node:

#         统计字符出现的个数
def sumchar(oldMsg):
    # 利用字典统计每一个byte出现的次数
    d = {}
    q = []
    for M in oldMsg:
        if not M in d:
            d[M] = 1
        else:
            d[M] += 1
    # 将字典的键值对转换为Node,并放入队列中
    for no in sorted(d.items(), key=lambda x: x[1], reverse=True):
        q.append(Node(no))
    return q

 
dataweightleftright
 25NoneNone
e16NoneNone
t12NoneNone
a10NoneNone
h7NoneNone
s7NoneNone
n7NoneNone
o7NoneNone
u5NoneNone
r4NoneNone
w4NoneNone
d4NoneNone
,3NoneNone
g2NoneNone
N1NoneNone
i1NoneNone
v1NoneNone
y1NoneNone
b1NoneNone
I1NoneNone
m1NoneNone
p1NoneNone
k1NoneNone
.1NoneNone



               生成Huffman树,然后生成Huffman编码表:(有兴趣的朋友可以试试自己画一下Huffman树,公众号回复Huffman获取Huffman树图片)
  0
100
101
110
111
10000
10001
10010
10011
101
110000
1100010
1100011
1100100
1100101
1100110
1100111
1101000
1101001
1101010
1101011
11011
1110
1111
# 生成哈夫曼树
def creatHuffmanTree(q):
    while len(q) != 1:
        left = q.pop()
        right = q.pop()
        parent = Node([None, left.weight + right.weight])
        parent.left = left
        parent.right = right
        i = 0
        t = True
        while t:
            if i < len(q) and parent.weight < q[i].weight:
                i += 1
            else:
                q.insert(i, parent)
                t = False
    return q[0]


# 生成哈夫曼编码表
HuffmanTable = {}

# 生成哈夫曼编码表
def creatHuffmanTable(tree):
    if tree:
        creatHuffmanTables(tree.left, "0", "")
        creatHuffmanTables(tree.right, "1", "")
    return HuffmanTable


def creatHuffmanTables(node, num, yuan):
    yuan = yuan + num
    if node.data is None:
        creatHuffmanTables(node.left, "0", yuan)
        creatHuffmanTables(node.right, "1", yuan)
    else:
        HuffmanTable[node.data] = yuan


然后就可以进行压缩和解压缩了,实际代码如下:
class Node:
    def __init__(self, data):
        self.data = data[0]  # 节点的值(保存字符)
        self.left = None  # 节点的左子节点
        self.right = None  # 节点的右子节点
        self.weight = data[1]  # 节点的值(保存字符出现的次数)


#         统计字符出现的个数
def sumchar(oldMsg):
    # 利用字典统计每一个byte出现的次数
    d = {}
    q = []
    for M in oldMsg:
        if not M in d:
            d[M] = 1
        else:
            d[M] += 1
    # 将字典的键值对转换为Node,并放入队列中
    for no in sorted(d.items(), key=lambda x: x[1], reverse=True):
        q.append(Node(no))
    return q


# 生成哈夫曼树
def creatHuffmanTree(q):
    while len(q) != 1:
        left = q.pop()
        right = q.pop()
        parent = Node([None, left.weight + right.weight])
        parent.left = left
        parent.right = right
        i = 0
        t = True
        while t:
            if i < len(q) and parent.weight < q[i].weight:
                i += 1
            else:
                q.insert(i, parent)
                t = False
    return q[0]


# 生成哈夫曼编码表
HuffmanTable = {}

# 生成哈夫曼编码表
def creatHuffmanTable(tree):
    if tree:
        creatHuffmanTables(tree.left, "0", "")
        creatHuffmanTables(tree.right, "1", "")
    return HuffmanTable


def creatHuffmanTables(node, num, yuan):
    yuan = yuan + num
    if node.data is None:
        creatHuffmanTables(node.left, "0", yuan)
        creatHuffmanTables(node.right, "1", yuan)
    else:
        HuffmanTable[node.data] = yuan


# 进行压缩
def zip(oldMsg, HuffmanTable):
    newData = ""
    for c in oldMsg:
        newData += HuffmanTable.get(c)
    return newData


# 进行解压
def unzip(newData, HuffmanTable):
    temp = {}
    for i, k in HuffmanTable.items():
        temp[k] = i
    i = 0
    newMsg = ""
    while i < len(newData):
        count = 1
        flag = True
        b = ""
        while flag:
            keyy = newData[i:i + count]
            b = temp.get(keyy)
            if b is None:
                count += 1
            else:
                flag = False
        newMsg += b
        i += count
    return newMsg


oldMsg = "Nature has given us that two ears, two eyes, and but one tongue, to the end that we should hear and see more than we speak."
print("原有的数据为:" + oldMsg)
oldData = ""
for m in oldMsg:
    oldData += bin(ord(m))
print("转为二进制数据大小为:", len(oldData), "\n为:", oldData)
tree = creatHuffmanTree(sumchar(oldMsg))
creatHuffmanTable(tree)
newData = zip(oldMsg, HuffmanTable)
print("进过哈夫曼编码后的二进制数据大小为:", len(newData), "\n为:", newData)
newMsg = unzip(newData, HuffmanTable)
print("解码哈夫曼编码后的二进制数据为:" + newMsg)
print("此数据在哈夫曼编码的压缩率为(压缩后二进制/源数据二进制):", len(newData) / len(oldData))
Huffman编码不仅仅运用于传播的压缩,还能用于字符串的加密:
原有的数据为:


Nature has given us that two ears, two eyes, and but one tongue, to the end that we should hear and see more than we speak.

在进过Huffman加密后显示为:


×ß¹Ñù5iªm~óäé´Eh±3ïÄZz.°=zUïÞJé¼Ñ‑ôÎXi'O~RTl±â

只有进过解密才能看得见,原内容
尝试修改原版本升级为加密版Huffman编码吧,看看能否获取下面这段密文的秘密:


©M̸¤úù<_Ôæ

下载文章附带链接获取升级版加密模式的Huffman,看看自己的做法对不对
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值