Huffman树
来源:互联网 发布:软件设计方案书 编辑:程序博客网 时间:2024/06/05 18:35
哈夫曼树(Huffman):给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
路径:从A节点到B节点所经过的分支序列成为A节点到B节点的路径
路径长度:从A节点到B节点所经过的分支个数为A到B的路径长度
从根节点到二叉树所有节点的路径长度之和为二叉树的路径长度
哈夫曼树的构造:
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
示例:
int array[]={3,7,12,6}
1、按权值大小排序,int array[]={3,6,7,12}
2、取权值最小的两个节点,作为新树的左右节点,将左右子树的权值相加作为新的根节点的权值
3、将旧的节点删除,并将新的根节点放入队列
4、重复2、3,直到队列中只剩一个节点
WPL=3*3+3*6=2*7+1*12=53
代码实现如下:
1、按权值排列时与小堆相似,所以调用堆的代码
#include<iostream>using namespace std;#include<vector>#include<assert.h>template<class T> //Huffman树是按小堆排列的struct Less{ bool operator()(const T& left,const T& right) { return left<right; }};template<class T>struct Greater{ bool operator()(const T& left,const T& right) { return left>right; }};template<class T,class compare=Less<T>>class Heap{public: Heap() {} Heap(const T array[],size_t size) { _heap.resize(size); for(size_t i=0; i<size; ++i) _heap[i]=array[i]; int root=(_heap.size()-2)>>1; for(root=root;root>=0; --root) _AdjustDown(root); }protected: void _AdjustDown(size_t parent) { size_t size=_heap.size(); size_t child=parent*2+1; while(child<size) { compare com; if( child+1<size && com(_heap[child+1],_heap[child])) child+=1; if(com(_heap[child],_heap[parent])) { std::swap(_heap[parent],_heap[child]); parent=child; child=parent*2+1; } else return; } } void _AdjustUp() { size_t child=_heap.size()-1; size_t parent=(child-1)>>1; while(child != 0) { if(compare()(_heap[child],_heap[parent])) { std::swap(_heap[child],_heap[parent]); child=parent; parent=(child-1)>>1; } else return; } }public: void Insert(const T& data) { _heap.push_back(data); if(_heap.size()>1) _AdjustUp(); } void Remove() { assert(!Empty()); std::swap(_heap[0],_heap[_heap.size()-1]); _heap.pop_back(); if(_heap.size()>1) _AdjustDown(0); } size_t Size()const { return _heap.size(); } bool Empty()const { return 0 ==_heap.size(); } const T& Top()const { return _heap[0]; }private: vector<T> _heap;};
2、创建Huffman树
#include "heap.cpp"template<class T>struct HuffmanTreeNode //创建节点{ HuffmanTreeNode(const T& weight) :_weight(weight) ,_pLeft(NULL) ,_pRight(NULL) ,_pParent(NULL) {} T _weight; HuffmanTreeNode<T>* _pLeft; HuffmanTreeNode<T>* _pRight; HuffmanTreeNode<T>* _pParent;};template<class T>class HuffmanTree{ typedef HuffmanTreeNode<T> Node;public: HuffmanTree() :_pRoot(NULL) {} HuffmanTree(const T array[],size_t size,const T& invalid) { _Create(array,size,invalid); } ~HuffmanTree() { _Destroy(_pRoot); }private: void _Create(const T array[],size_t size,const T& invalid) //创建Huffman树 { struct Compare { bool operator()(const Node* pLeft,const Node* pRight) { return pLeft->_weight<pRight->_weight; } }; Heap<Node*,Compare> hp; for(size_t i=0;i<size;++i) { if(array[i] != invalid) hp.Insert(new Node(array[i])); } while(hp.Size()>1) { Node* pLeft=hp.Top(); hp.Remove(); Node* pRight=hp.Top(); hp.Remove(); //取权值最小的两个节点,并删除节点 Node* pParent=new Node(pLeft->_weight+pRight->_weight); //构造新的根节点 pParent->_pLeft=pLeft; pParent->_pRight=pRight; pLeft->_pParent=pParent; pRight->_pParent=pParent; //将节点连接起来 hp.Insert(pParent); //将新的根节点放入队列 } _pRoot=hp.Top(); } const Node* pRoot()const { return _pRoot; } void _Destroy(Node*& pRoot) { if(pRoot) { _Destroy(pRoot->_pLeft); _Destroy(pRoot->_pRight); delete pRoot; pRoot=NULL; } }private: Node* _pRoot;};
带权路径长度(WPL)=节点的权值*根节点到该节点的长度
一棵树的带权路径长度=所有节点的带权路径长度之和
- Huffman树&&Huffman编码
- Huffman树
- Huffman 树
- huffman树
- huffman 树
- Huffman树
- Huffman树
- Huffman树
- Huffman树
- Huffman树
- Huffman树
- Huffman树
- Huffman树
- Huffman树
- huffman 树
- Huffman树
- Huffman树
- Huffman树
- 深入浅出mybatis中原始dao的开发和mapper代理开发
- bzoj2823: [AHOI2012]信号塔
- LoadRunner12使用教程(四)——事务与集合点
- redhat 7 防火墙
- Redis环境安装与配置
- Huffman树
- C++求数组中和为定值的组合
- C++标准库:关联容器(set、map、unordered、multi)
- 【redis源码剖析】 redis内置数据类型之字符串sds
- Linux编写shell脚本处理Catalina.out长时间大量日志占用系统空间问题
- nodejs 安装与配置
- qt开发过程中遇到的问题整理
- 利用KETTLE进行数据迁移(改良版)
- Javascript跳转页面和打开新窗口等方法