在介绍哈弗曼树之前先来看几个简单的概念:
在一个二叉树中:
定义一个从A结点到B结点所经过的分支序列为从A结点到B结点的路径。
定义从A结点到B结点所经过的分支个数为从A结点到B结点的路径长度。
从二叉树的根节点到二叉树中所有节点的路径长度之和为该二叉树的路径长度。
Huffman树:带权路径长度最短的树称为哈夫曼树。
Huffman树的创建:(用小堆来保存二叉树森林中的树)如int array[]={5,3,2,7}。
1.先进行排序:升序排列为{2,3,5,7}。
2.选出最小的两个数,先进行建树。
3.将新的二叉树放入二叉树森林中。
4.继续步骤2和3。
下面为构建Huffman树的算法:
1.创建以权值为根的二叉树森林——>小堆
2.构建(直到二叉树森林中只剩一棵树)
1>.取权值最小的树pLeft,—–删除其。
2>.取权值最小的树pRight,—–删除其。
3>.pLeft的权值与pRight的权值作为其双亲,创建新树,将新树佳人苑二叉树森林中。
3.比较左右子树权值的大小,决定放在左子树还是右子树。
具体的代码实现如下:
#include<iostream>
#include<vector>
using namespace std;
template<class T>
class Heap
{
public:
Heap()
{}
Heap(const T*array, size_t size)//堆的创建
{
//1.将数组中的元素存起来
_array.resize(size);
for (size_t i = 0; i < size; i++)
{
_array[i] = array[i];
}
//2.向下调整
int root = (size - 2) >> 1;
for (; root >= 0; root--)
{
_AdjustDown(root);
}
}
void Push(const T& data)
{
_array.push_back(data);
if (_array.size() > 1)
{
_AdjustUp(_array.size() - 1);
}
}
void Pop()
{
if (Size() == 0)
return;
else
{
size_t last = _array.size() - 1;
swap(_array[0], _array[last]);
_array.pop_back();
//2.向下调整
_AdjustDown(0);
}
}
T Top()const
{
return _array[0];
}
bool Empty()const
{
return _array.empty();
}
size_t Size()const
{
return _array.size();
}
private:
void _AdjustDown(size_t parent)//向下调整
{
size_t child = parent * 2 + 1;
size_t size = _array.size();
while (child < size)
{
if ((child + 1 < size) && (_array[child] > _array[child + 1]))
{
child += 1;
}
if (_array[parent]>_array[child])
{
swap(_array[parent], _array[child]);
parent = child;
child = parent * 2 + 1;//继续走到其左侧,进行调整
}
else
{
break;
}
}
}
void _AdjustUp(size_t child)//向上调整
{
size_t size = _array.size();
size_t parent = (size - 2) >> 1;
while (child > 0)
{
if (_array[parent] > _array[child])
{
swap(_array[parent], _array[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
{
break;
}
}
}
private:
vector<T>_array;
};
template<class W>
struct HuffmanTreeNode
{
HuffmanTreeNode()
: _pLeft(NULL)
, _pRight(NULL)
, _weight(0)
{}
HuffmanTreeNode(W weight)
:_pLeft(NULL)
, _pRight(NULL)
, _weight(weight)
{}
HuffmanTreeNode<W>*_pLeft;
HuffmanTreeNode<W>*_pRight;
W _weight;//权值
};
template<class W>
class HuffmanTree
{
public:
typedef HuffmanTreeNode<W> Node;
typedef Node* pNode;
HuffmanTree()
:_pRoot(NULL)
{}
HuffmanTree( W*array, size_t size, const W&invalid)
{
_CreatHuffmanTree(array, size, invalid);
}
~HuffmanTree()
{
_Destroy(_pRoot);
}
private:
void _CreatHuffmanTree(W*array, size_t size, const W&invalid)
{
if (hp.Empty())
{
_pRoot = NULL;
}
Heap<pNode>hp;//堆中存的是节点
for (size_t i = 0; i<size; i++)
{
if (array[i] != invalid)
{
hp.Push(new Node(array[i]));
}
}
while (hp.Size()> 1)
{
//取堆顶元素
pNode pLeft = hp.Top();
hp.Pop();
pNode pRight = hp.Top();
hp.Pop();
pNode parent = new Node(pLeft->_weight + pRight->_weight);//左右权值相加
if (pLeft->_weight < pRight->_weight)
{
parent->_pLeft = pLeft;
parent->_pRight = pRight;
}
else
{
parent->_pLeft = pRight;
parent->_pRight = pLeft;
}
hp.Push(parent);
}
_pRoot = hp.Top();
}
void _Destory(pNode &pRoot)
{
if (pRoot)
{
_Destory(pRoot->_pLeft);
_Destory(pRoot->_pRight);
delete pRoot;
}
}
pNode _pRoot;
Heap<W> hp;
};
int main()
{
int array[] = { 5, 3, 2, 7 };
HuffmanTree<int>h(array, 4, 0);
system("pause");
return 0;
}
仿函数的形式写法为:
#include<iostream>
#include<vector>
using namespace std;
template<class T>
struct Greater
{
bool operator()(const T&a, const T&b)
{
return a > b;
}
};
template<class T>
struct Smaller
{
bool operator()(const T&a, const T&b)
{
return a < b;
}
};
template<class T, class compare = Smaller<T>>
class Heap
{
public:
Heap()
{}
Heap(T*array, int size)//堆的创建
{
//1.将数组中的元素存起来
_array.resize(size);
for (int i = 0; i < size; i++)
{
_array[i] = array[i];
}
//2.向下调整
int root = (size - 2) >> 1;
for (; root >= 0; root--)
{
_AdjustDown(root);
}
}
void Push(const T& data)
{
_array.push_back(data);
if (_array.size() > 1)
{
_AdjustUp(_array.size() - 1);
}
}
void Pop()
{
if (Size() == 0)
return;
else
{
int last = _array.size() - 1;
swap(_array[0], _array[last]);
_array.pop_back();
//2.向下调整
_AdjustDown(0);
}
}
T Top()const
{
return _array[0];
}
bool Empty()const
{
return _array.empty();
}
size_t Size()const
{
return _array.size();
}
private:
void _AdjustDown(int parent)//向下调整
{
int child = parent * 2 + 1;
int size = _array.size();
while (child < size)
{
if ((child + 1 < size) && (compare()(_array[child], _array[child + 1])))
{
child += 1;
}
if (compare()(_array[parent], _array[child]))
{
swap(_array[parent], _array[child]);
parent = child;
child = parent * 2 + 1;//继续走到其左侧,进行调整
}
else
return;
}
}
void _AdjustUp(int child)//向上调整
{
int size = _array.size();
int parent = (size - 2) >> 1;
while (child > 0)
{
if (compare()(_array[parent], _array[child]))
{
swap(_array[parent], _array[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
{
break;
}
}
}
private:
vector<T>_array;
};
template<class W>
struct HuffmanTreeNode
{
HuffmanTreeNode()
: _pLeft(NULL)
, _pRight(NULL)
, _weight(0)
{}
HuffmanTreeNode(W weight)
:_pLeft(NULL)
, _pRight(NULL)
, _weight(weight)
{}
HuffmanTreeNode<W>*_pLeft;
HuffmanTreeNode<W>*_pRight;
W _weight;//权值
};
template<class W>
class HuffmanTree
{
public:
typedef HuffmanTreeNode<W> Node;
typedef Node* pNode;
HuffmanTree()
:_pRoot(NULL)
{}
HuffmanTree( W*array, size_t size, const W&invalid)
{
_CreatHuffmanTree(array, size, invalid);
}
~HuffmanTree()
{
_Destroy(_pRoot);
}
private:
void _CreatHuffmanTree(W*array, size_t size, const W&invalid)
{
struct compare
{
bool operator()(pNode pLeft, pNode Pright)
{
return pLeft->_weight < Pright->_weight;
}
};
Heap<pNode, compare>hp;//堆中存的是节点
for (size_t i = 0; i<size; i++)
{
if (array[i] != invalid)
{
hp.Push(new Node(array[i]));
}
}
if (hp.Empty())
{
_pRoot = NULL;
}
while (hp.Size()> 1)
{
//取堆顶元素
pNode pLeft = hp.Top();
hp.Pop();
pNode pRight = hp.Top();
hp.Pop();
pNode parent = new Node(pLeft->_weight + pRight->_weight);//左右权值相加
hp.Push(parent);
}
_pRoot = hp.Top();
}
void _Destory(pNode &pRoot)
{
if (pRoot)
{
_Destory(pRoot->_pLeft);
_Destory(pRoot->_pRight);
delete pRoot;
}
}
pNode _pRoot;
Heap<W> hp;
};
int main()
{
int array[] = { 5, 3, 2, 7 };
HuffmanTree<int>h(array, 4, 0);
system("pause");
return 0;
}
struct compare
{
bool operator()(pNode pLeft, pNode Pright)
{
return pLeft->_weight < Pright->_weight;
}
};
关于此结构的说明:
我们需要将节点保存在堆中,但是在结构体中是节点的地址,则需要比较其权值,之后进行调整。