二叉树部分写起来比预想中的要麻烦,估计在这一章上会多停留一段时间。项目昨天没有写进度记录但还是一直有在做,今天会补一篇。日语学习也得赶上进度,啊啊,快去世了。
基本概念:
哈夫曼树是一种特殊的二叉树,它的每一个结点都带有权值,且总是有最小的带权路径(WPL),它也叫最优二叉树。
相关概念解释:
(一)路径:从树中一个结点到另一个结点之间的分支构成两个结点的路径
(二)路径长度:路径上的分支数目叫做路径长度。而整个树的路径长度是从根到每一个结点的路径长度之和
(三)带权路径长度:哈夫曼树的每一个结点带有权,带权路径长度需要用路径长度乘以对应结点的权值,而树的带权路径长度则是从根到每一个结点的带权路径长度之和。 而哈夫曼树即是树的带权路径最小的二叉树。
哈夫曼树的特点:
1.每个节点的度只能为2或者0(我们总是选用两个最小权的节点构造一棵子树)
2.叶子结点数是n时,中间节点数为n-1,总结点数2n-1
由哈夫曼树可以进而构造哈夫曼编码。详见百度百科
哈夫曼树的构建:
基本思想是:每次都取两个权值最小的节点构造一颗树。
假设这里有权值为2 4 5 9 13的五个节点,以此来构建一颗哈夫曼树,用画图随便画了画:
(画图鬼才)
思想还是很简单的,注意如果选取的两个节点都不是已经构造出的新节点,则是在旁边新建一棵树。
具体程序实现(c++,template):
知道了构造的原理后要码代码就很简单了,我们先把权值放进数组里,再每次挑选最小的两个(用排序操作),构造出节点和树,并更新数组。
(一)数据结构分析
1.哈夫曼节点:
构造函数
指向左右子节点的指针
权值
一个flag用于构建时的标记
2.哈夫曼树
public:
构造、析构函数
排序算法
创建哈夫曼树
三种遍历,打印方法
删除节点,销毁整棵树
private:
哈夫曼根节点
一个森林
(二)相关定义,声明
template <typename T>
struct HuffmanNode
{
HuffmanNode(T k,HuffmanNode<T>* l,HuffmanNode<T>* r):
key(k),lchild(l),rchild(r),flag(0){}
T key;
HuffmanNode<T>* lchild;
HuffmanNode<T>* rchild;
int flag;
};
//节点的定义
template <typename T>
class Huffman{
public:
void preTraversing();
void inTraversing();
void postTraversing();
void create(T a[],int size);
void destroy();
void print();
void my_sort(int size);
Huffman():root(NULL){}
~Huffman(){
destroy(root);
}
private:
void preTraversing(HuffmanNode<T>* pnode);
void inTraversing(HuffmanNode<T>* pnode);
void postTraversing(HuffmanNode<T>* pnode);
void print(HuffmanNode<T>* pnode);
void destroy(HuffmanNode<T>* pnode);
HuffmanNode<T>* root;
HuffmanNode<T>* forest[100];
};
//整棵树的定义
(三)成员函数实现
/*sorting排序操作*/
template <typename T>
void Huffman<T>::my_sort(int size)
{
for(int i=0;i<size-1;i++)
{
for(int j=i+1;j<size;j++)
{
if(forest[i]->key > forest[j]->key)
{
swap(forest[i],forest[j]);
}
else continue;
}
}
};
//构建哈夫曼树
template <typename T>
void Huffman<T>::create(T a[],int size)
{
int j=0,k=0;
for(int i=0;i<size;i++)
{
HuffmanNode<T>* ptr=new HuffmanNode<T>(a[i],NULL,NULL);
forest[i]=ptr;
}
for(int i=0;i<size-1;i++)
{
my_sort(size+k);
for(j=0; ;j++)
{
if(forest[j]->flag!=1&&forest[j+1]->flag!=1)
{
HuffmanNode<T>* node=new HuffmanNode<T>(forest[j]->key+forest[j+1]->key,
forest[j],forest[j+1]);
forest[size+k]=node;
k++;
forest[j]->flag=1;
forest[j+1]->flag=1;
break;
}
else continue;
}
}
root=forest[size+k-1];
};
/*three types of traversing*/
//遍历
template <typename T>
void Huffman<T>::preTraversing(HuffmanNode<T>* pnode)
{
if(pnode!=NULL)
{
std::cout<<pnode->key;
preTraversing(pnode->lchild);
preTraversing(pnode->rchild);
}
};
template <typename T>
void Huffman<T>::preTraversing()
{
preTraversing(root);
};
template <typename T>
void Huffman<T>::inTraversing(HuffmanNode<T>* pnode)
{
if(pnode!=NULL)
{
inTraversing(pnode->lchild);
std::cout<<pnode->key;
inTraversing(pnode->rchild);
}
};
template <typename T>
void Huffman<T>::inTraversing()
{
inTraversing(root);
};
template <typename T>
void Huffman<T>::postTraversing(HuffmanNode<T>* pnode)
{
if(pnode!=NULL)
{
postTraversing(pnode->lchild);
postTraversing(pnode->rchild);
std::cout<<pnode->key;
}
};
template <typename T>
void Huffman<T>::postTraversing()
{
postTraversing(root);
};
//打印
template <typename T>
void Huffman<T>::print(HuffmanNode<T>* pnode)
{
if(pnode!=NULL)
{
std::cout<<"Node:"<<pnode->key<<std::endl;
if(pnode->lchild!=NULL)std::cout<<"left child:"<<pnode->lchild->key<<".";
else std::cout<<"No leftchild ";
if(pnode->rchild!=NULL)std::cout<<"right child:"<<pnode->rchild->key<<std::endl;
else std::cout<<"No rightchild"<<std::endl;
print(pnode->lchild);
print(pnode->rchild);
}
};
template <typename T>
void Huffman<T>::print()
{
print(root);
};
/*destroy*/
template <typename T>
void Huffman<T>::destroy(HuffmanNode<T>* pnode)
{
if(pnode!=NULL)
{
destroy(pnode->lchild);
destroy(pnode->rchild);
delete pnode;
pnode=NULL;
}
};
template <typename T>
void Huffman<T>::destroy()
{
destroy(root);
};
测试一下:
int main()
{
Huffman<int> HT;
int a[]={10,20,30,40};
HT.create(a,4);
HT.print();
HT.inTraversing();
return 0;
}
格式好像有些问题,后面来改改