神秘的哈夫曼编码
哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做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
| data | weight | left | right |
| 25 | None | None | |
| e | 16 | None | None |
| t | 12 | None | None |
| a | 10 | None | None |
| h | 7 | None | None |
| s | 7 | None | None |
| n | 7 | None | None |
| o | 7 | None | None |
| u | 5 | None | None |
| r | 4 | None | None |
| w | 4 | None | None |
| d | 4 | None | None |
| , | 3 | None | None |
| g | 2 | None | None |
| N | 1 | None | None |
| i | 1 | None | None |
| v | 1 | None | None |
| y | 1 | None | None |
| b | 1 | None | None |
| I | 1 | None | None |
| m | 1 | None | None |
| p | 1 | None | None |
| k | 1 | None | None |
| . | 1 | None | None |
生成Huffman树,然后生成Huffman编码表:(有兴趣的朋友可以试试自己画一下Huffman树,公众号回复Huffman获取Huffman树图片)
| 0 | |
| o | 100 |
| n | 101 |
| s | 110 |
| h | 111 |
| , | 10000 |
| d | 10001 |
| w | 10010 |
| r | 10011 |
| e | 101 |
| g | 110000 |
| . | 1100010 |
| k | 1100011 |
| p | 1100100 |
| m | 1100101 |
| l | 1100110 |
| b | 1100111 |
| y | 1101000 |
| v | 1101001 |
| i | 1101010 |
| N | 1101011 |
| u | 11011 |
| a | 1110 |
| t | 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,看看自己的做法对不对

7555

被折叠的 条评论
为什么被折叠?



