曾品闲的数据结构复习之四:二叉树之哈夫曼树

二叉树部分写起来比预想中的要麻烦,估计在这一章上会多停留一段时间。项目昨天没有写进度记录但还是一直有在做,今天会补一篇。日语学习也得赶上进度,啊啊,快去世了。


基本概念:

哈夫曼树是一种特殊的二叉树,它的每一个结点都带有权值,且总是有最小的带权路径(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;
}

在这里插入图片描述
格式好像有些问题,后面来改改

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值