Huffman编码树
- Huffman编码将为字母分配代码。代码长度取决于对应字母的相对使用频率或者“权重”(weight),因此它是一种变长编码。
- 每个字母的Huffman编码是从称为Huffman编码树(Huffman coding tree)或简称为Huffman树(Huffman tree)的满二叉树中得到。
- Huffman树的每个叶结点对应于一个字母,叶结点的权重就是它对应字母出现的频率。
- 一个叶结点的加权路径长度定义为权重乘以路径长度。
- 权重大的叶结点的深度小,因为它相对总路径长度的花费最小;权重晓得叶结点的深度大,因而它相对总路径长度的花费最大。
Huffman树的建立:首先,穿件n个初始的Huffman树,每棵树值包含一个单一的叶结点,叶结点记录对应的字母。将这n棵树按照权重(如频率)大小顺序排为一列。接着,拿走前两棵树(权重最小的两棵树),再把它们标记为Huffman树的叶结点,把这两个叶结点标记为一个分支节点的两个子结点,而这个分支节点的权重就为两个叶结点权重的和。把所得的新树放回到序列中的适当位置,是的权重的顺序保持升序。重复上述步骤,直至序列中只剩下一个元素,则Huffman树建立完毕。
如下图所示:
抽象基类HuffmanNode:
template<typename E>class HuffmanNode{
public:
virtual ~HuffmanNode() {}
virtual int weight() = 0;
virtual bool isLeaf() = 0;
};
- 子类LeafNode(用于叶子结点):
template<typename E>class LeafNode :public HuffmanNode < E > {
private:
E it; //元素值
int wgt; //权重
public:
//构造函数
LeafNode(const E& val,int wg)
{
it = val;
wgt = wg;
}
int weight() { return wgt; } //返回权重
E val() { return E; } //返回元素值
bool isLeaf() { return true; } //返回就是叶结点
};
- 子类IntlNode(用于分支结点):
template<typename E>
class IntlNode :public HuffmanNode < E > {
private:
HuffmanNode<E>* lc; //左子结点
HuffmanNode<E>* rc; //右子结点
int wgt; //权重
public:
//构造函数
IntlNode(HuffmanNode<E>* l,HuffmanNode<E>* r)
{
wgt = l->weight() + r->weight();
lc = l;
rc = r;
}
int weight() { return wgt; } //返回权重
bool isLeaf() { return false; } //不是叶结点
//返回左子结点和设置左子结点
HuffmanNode<E>* left() const { return lc; }
void setLeft(HuffmanNode<E>* l) { lc = l; }
//返回右子结点和设置右子结点
HuffmanNode<E>* right() const { return rc; }
void setRight(HuffmanNode<E>* r) { rc = r; }
};
- 最小堆的实现(用于选出一组树中最小的元素):
template<typename E> class heap{
private:
E* Heap; //堆序列的指针
int maxsize; //堆的最大容量
int n; //堆里面的元素数量
void siftdown(int pos)
{
while (!isLeaf(pos))
{
int j = leftchild(pos);
int rc = rightchild(pos);
if ((rc < n) && prior(Heap[j], Heap[rc]))
j = rc;
if (prior(Heap[j], Heap[pos])) return;
swap(Heap, pos, j);
pos = j;
}
}
public:
//构造函数
heap(E* h, int num, int max)
{
Heap = h; n = num; maxsize = max;s
buildHeap();
}
//返回对的大小
int size() const
{
return n;
}
//判断是否为叶节点
bool isLeaf(int pos) const
{
return (pos >= n / 2) && (pos < n);
}
//返回左节点
int leftchild(int pos) const
{
return 2 * pos + 1;
}
//返回右节点
int rightchild(int pos) const
{
return 2 * pos + 2;
}
//返回父节点
int parent(int pos) const
{
return (pos - 1) / 2;
}
//建堆
void buildHeap()
{
for (int i = n / 2 - 1; i >= 0; i--) siftdown(i);
}
//插入一个元素
void insert(const E& it)
{
assert(n < maxsize, "Heap is full");
int curr = n++;
Heap[curr] = it;
while ((curr != 0) && (prior(Heap[curr], Heap[parent(curr)])))
{
swap(Heap, curr, parent(curr));
curr = parent(curr);
}
}
//移除根节点
E removefirst()
{
assert(n > 0, "Heap is empty");
swap(Heap, 0, --n);
if (n != 0)siftdown(0);
return Heap[n];
}
//判断第一个参数是否再第二个参数之前
bool prior(E a, E b)
{
if (a > b) return true;
else return false;
}
//交换值
void swap(E* heap, int i, int j)
{
E temp;
temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
};
- Huffman树的实现:
template<typename E>
class HuffmanTree{
private:
HuffmanNode<E>* Root; //根结点
public:
//构造叶结点
HUffmanTree(E& val, int wg)
{
Root = new LeafNode<E>(val, wg);
}
//构造分支节点
HuffmanTree(HuffmanTree<E>* l, HuffmanTree<E>* r)
{
Root = new IntlNode<E>(l->root(), r->Root());
}
~HuffmanTree() {}
//返回根结点
HuffmanTree<E>* root() { return Root; }
//返回权值
int weight() { return Root->weight(); }
};
- 建立Huffman树:
template<typename E>
HuffmanTree<E>* buildHuffman(HuffmanTree<E>** TreeArray, int count)
{
heap<HuffmanTree<E>*>* forest = new heap<HuffmanTree<E>*>(TreeArray, count, count); //建造一个最小堆
HuffmanTree<char> *temp1, *temp2, *temp3 = NULL; //三个Huffman树
while (forest->size() > 1)
{
temp1 = forest->removefirst(); //将前两个树组合起来
temp2 = forest->removefirst();
temp3 = new HuffmanTree<E>(temp1, temp2);
forest->insert(temp3); //把新树放在堆的最后
delete temp1; //必须删除已用的树
delete temp2;
}
return temp3;
}