rpc压缩原理哈夫曼编码解码

环境:突然间想要知道rpc为什么会受到欢迎,总结有以下几点
1.rpc是基于http2.0协议的
2.数据编码压缩减少了传输的数据量
http2.0 :基于https ,以及请求数据加密(更加安全),头部数据压缩(传输数据变少),引入流式传输以及请求方式

实现哈夫曼编码的流程:(这里只实现字符串编码和解码)
1.统计字符在字符串中出现的次数
2.按字符出现的次数从小到大排序
3.构建哈夫曼树
4.确定字典
5.把字符串替换成编号
哈夫曼解码就是按照字典去比对数据然后拼接

代码:

package Huffman

import "sort"

type NodeList []*Node

func (list NodeList) Len() int {
	return len(list)
}

func (list NodeList) Swap(i, j int) {
	list[i], list[j] = list[j], list[i]
}

func (list NodeList) Less(i, j int) bool {
	return list[i].Weight < list[j].Weight
}

// Node 赫夫曼节点,用于构成赫夫曼树
type Node struct {
	Weight uint   //权重
	Data   string //数据
	Parent *Node  //父节点
	Left   *Node  //左孩子
	Right  *Node  //右孩子
}

// Tree 赫夫曼树结构
type Tree struct {
	root    *Node             //根节点
	leaf    NodeList          //所有叶子节点(即数据对应的节点)
	src     map[string]uint   //源数据,key为数据,value为权重
	codeSet map[string]string //编码集,key为数据,value为通过构造赫夫曼树得到的数据的编码
}

// NewHuffmanTree 给定一组字符及其权重的集合,初始化出一棵赫夫曼树
func NewHuffmanTree(src map[string]uint) *Tree {
	var tree = &Tree{
		src: src,
	}
	tree.init()
	tree.build()
	tree.parse()
	return tree
}

// Coding 根据数据进行赫夫曼编码
func (h *Tree) Coding(target string) (result string) {

	for _, t := range target {
		v := string(t)
		if c, ok := h.codeSet[v]; !ok {
			panic("invalid code: " + v)
		} else {
			result += c
		}
	}
	return result
}

// UnCoding 根据赫夫曼编码获取数据
func (h *Tree) UnCoding(target string) (result string) {
	node := h.root
	for i := 0; i < len(target); i++ {
		switch target[i] {
		case '0':
			node = node.Left
		case '1':
			node = node.Right
		}
		if node.Left == nil && node.Right == nil {
			result = result + node.Data
			node = h.root
		}
	}
	return
}

// 初始化所有叶子节点
func (h *Tree) init() {
	if len(h.src) <= 1 {
		panic("invalid src length.")
	}
	h.codeSet = make(map[string]string)
	h.leaf = make(NodeList, len(h.src))
	var i int
	for data, weight := range h.src {
		var node = &Node{
			Weight: weight,
			Data:   data,
		}
		h.leaf[i] = node
		i++
	}
	//对leaf根据权值排序
	sort.Sort(h.leaf)
}

// 构造赫夫曼树
// src: key为data,value为权值
func (h *Tree) build() {
	nodeList := h.leaf
	//根据huffman树的规则构造赫夫曼树
	for nodeList.Len() > 1 {
		//1. 选取权值最小的两个node构造出第一个节点
		var temp = &Node{
			Weight: nodeList[0].Weight + nodeList[1].Weight,
			Left:   nodeList[0],
			Right:  nodeList[1],
		}
		nodeList[0].Parent = temp
		nodeList[1].Parent = temp

		//2.将生成的新节点插入节点序列中
		nodeList = newList(nodeList[2:], temp)
	}
	h.root = nodeList[0]
}

/*
找出每一个字符对应的编码
*/
func (h *Tree) parse() {
	if h.root == nil {
		return
	}
	var temp *Node
	var code string
	for _, n := range h.leaf {
		temp = n
		for temp.Parent != nil {
			if temp == temp.Parent.Left {
				code = "0" + code
			} else {
				code = "1" + code
			}
			temp = temp.Parent
		}
		h.codeSet[n.Data] = code
		code = ""
	}
}

// 将生成的节点放入节点列表,列表始终按照从小到大排序
func newList(src NodeList, temp *Node) NodeList {
	length := len(src)
	result := make(NodeList, len(src)+1)
	if length == 0 {
		result[0] = temp
		return result
	}
	if src[length-1].Weight <= temp.Weight {
		copy(result, src)
		result[length] = temp
		return result
	}
	for i := range src {
		if src[i].Weight <= temp.Weight {
			result[i] = src[i]
		} else {
			result[i] = temp
			copy(result[i+1:], src[i:])
			break
		}
	}
	return result
}

测试代码:

package main

import (
	"fmt"
	"strings"
	"webIm/Huffman"
)

func main() {
	str := "霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种。\n\n霍夫曼编码使用变长编"
	fmt.Println(str)
	/**
	1.计算每个字符的出现次数
	2.按照出现次数从小到大排序
	3.构建哈夫曼树
	4.确定字符的路径(编号)
	5.用编号替换字符
	**/
	mapStr := make(map[string]uint)
	strSpli := strings.Split(str, "")
	for _, v := range strSpli {
		if _, ok := mapStr[v]; ok {
			mapStr[v]++
		} else {
			mapStr[v] = 1
		}
	}
	treeHaf := Huffman.NewHuffmanTree(mapStr)
	HuffmanCode := treeHaf.Coding(str)
	println(HuffmanCode)
	println(treeHaf.UnCoding(HuffmanCode))
}

思考:在实际运用当中哈夫曼编码用byte去存而不是用字符串

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值