树的路径长度:
huffman说过:“从树中的一个节点到另一个节点之间的分支构成两个节点之间的路径,路径上的分支数目称为路径长度;数的路径长度就是树根到每一个节点的路径长度之和。”
树的带权路径长度:
huffman又说:“如果考虑到节点带权值,那么节点带权的路径长度为该节点到树根的路径长度与权值的乘积,因此树的带权路径长度为树中所有叶子节点的带权路径长度和。”
huffman树 == 带权路径长度最小的二叉树
从前面我们已经知道huffman树就是带权路径长度最短的树,因此构造huffman树只需要让权值较大的节点尽量靠近树根。
1.由给定的n个权值构造n棵只有根节点的二叉树森林;
2.在森林中选取两颗节点权值最小的二叉树,作为左右子树构造一棵新二叉树,新二叉树根节点的权值为左右子树节点的权值之和,并且在森林中删除你选取的两棵树,将新构造的树加入森林。然后重复上述直到森林仅剩下一棵树为止。
使用堆作为保存这棵huffman树的数据结构,why?因为每次要取最小的两个节点,因此这里我们使用优先级队列(底层是堆)priority_queue,比较方式采用大于greater比较,小根堆。
根据上述我们可以写出如下的赫夫曼树:
#ifndef _HUFFMANTREE_HPP_ #define _HUFFMANTREE_HPP_ #include#include #include using namespace std; template struct HuffmanTreeNode { HuffmanTreeNode * left; HuffmanTreeNode * right; W weight; HuffmanTreeNode(const W& w = W()) :left(nullptr), right(nullptr), weight(w) { } }; //实现对应于赫夫曼节点的greater()仿函数 template struct Com { typedef HuffmanTreeNode Node; bool operator()(const Node* left, const Node* right) { return left->weight > right->weight; } }; template class HuffmanTree { typedef HuffmanTreeNode Node; public: HuffmanTree() :root(nullptr) {} ~HuffmanTree() { Destroy(root); } void CreateHuffmanTree(vector & arr, size_t size) { //小堆 std::priority_queue , Com > q; //1.先使用所给的权值创建只有根节点的二叉树森林 for (size_t i = 0; i < size; ++i) { q.push(new Node(arr[i])); } //2.从森林中挑选两个权值最小的树并将其合并,直到剩一棵树 while (q.size() > 1) { Node* left = q.top(); q.pop(); Node* right = q.top(); q.pop(); //将left和right作为新节点的左右子树,新节点权值=左右之和; Node* New_Node = new Node(left->weight + right->weight); New_Node->left = left; New_Node->right = right; //把新的树插入到堆中; q.push(New_Node); } root = q.top(); } void Destroy(Node*& proot) { if (proot) { Destroy(proot->left); Destroy(proot->left); delete proot; proot = nullptr; } } private: Node* root; }; void test() { vector ar{ 3, 1, 7, 5 }; HuffmanTree t; t.CreateHuffmanTree(ar, ar.size()); } #endif



