哈夫曼树的建立(二叉链表)
作者: 冯向阳时间限制: 10S章节: DS:树
截止日期: 2022-06-30 23:55:00
问题描述 :
内容:请参照二叉树的ADT模板,设计Huffman树的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考教材、课件,以及网盘中的二叉树ADT原型文件,自行设计Huffman树的ADT。)
应用:要求设计一个算法,使用动态存储的方式,实现Huffman树的ADT。
提示:动态存储是指在新添加一个数据元素时,为它申请一个动态变量。删除一个数据元素时,释放该元素的存储空间。huffman树类的行为主要有两个:构造一棵haffuman树和获取叶子结点的Huffman编码。但由于树上的结点都是动态申请的,为此还需要一个析构函数。每个结点要保存的信息有4个:结点的值、结点的权值、左孩子指针、右孩子指针。
注意:为了保证你生成的哈夫曼树和题目的要求一致,需要遵循以下原则:
1、两个结点合并成一棵树时,权重小的结点为新树的左子树,权重大的结点为新树的右子树。
2、如果两个结点权重相等,则本来在左边的结点为新树的左子树。
3、新创建的树始终放在集合(森林)的最右边。
Huffuman类的参考定义:
/* Huffman树的结点定义 */
template<class ElemType>
struct Huffman_TreeNode{
Huffman_TreeNode *LChild, *RChild; //左、右孩子指针
ElemType data; //结点值
int weight; //结点的权值
Huffman_TreeNode(int w, Huffman_TreeNode *l = NULL, Huffman_TreeNode *r = NULL): weight(w), LChild(l), RChild(r){}
Huffman_TreeNode(const ElemType d, int w, Huffman_TreeNode *l = NULL, Huffman_TreeNode *r = NULL): data(d), weight(w), LChild(l), RChild(r){}
ElemType getData(){ return data;} //取得结点中的数据
};
const int MAX_INT = 32767;
//Huffman树
template<class ElemType>
class Huffman_Tree{
private:
Huffman_TreeNode<ElemType> *root;
public:
//带参数的构造函数
Huffman_Tree(const ElemType *v, const int *w, int size);
//析构函数
~Huffman_Tree(){clear(root);}
//获取根结点
Huffman_TreeNode<ElemType> * GetRoot() const{ return root;}
//前序遍历
bool PreOrderTraverse( Huffman_TreeNode<ElemType> *T, bool (*visit)(Huffman_TreeNode<ElemType> *T) ) const; //前序遍历(递归)
//中序遍历
bool InOrderTraverse( Huffman_TreeNode<ElemType> *T, bool (*visit)(Huffman_TreeNode<ElemType> *T) ) const; //前序遍历(递归)
//后序遍历
bool PostOrderTraverse( Huffman_TreeNode<ElemType> *T, bool (*visit)(Huffman_TreeNode<ElemType> *T) ) const; //前序遍历(递归)
//层次遍历
bool LayerOrderTraverse(bool (*visit)(Huffman_TreeNode<ElemType> *T)) const;
//删除huffman树
void clear(Huffman_TreeNode<ElemType> *t);
//查找值为x的结点的位置 (递归)
void Location_Cursive( Huffman_TreeNode<ElemType> * root, const ElemType &x, Huffman_TreeNode<ElemType> * &location ); //采用先序遍历
//获取父结点(递归)
void GetParent_Cursive(Huffman_TreeNode<ElemType> * parent, Huffman_TreeNode<ElemType> * &x, Huffman_TreeNode<ElemType> * &result, int &flag);
//查找从根结点到元素值为x的叶子结点的路径,路径经过的结点指针存放在顺序栈中(用于获取编码)
void FindPath( Huffman_TreeNode<ElemType> * &x, stack<ElemType> &Q );
};
辅助函数:
(1)Huffuman树遍历用visit函数,显示结点的权值
template<class ElemType>
bool visit(Huffman_TreeNode<ElemType> * root){
if(!root) return false;
else{
if(root->LChild || root->RChild)
cout<<"("<<root->weight<<") ";
else
cout<<root->data<<"("<<root->weight<<") ";
}
return true;
}
(2)Huffman树用栈遍历
template<class ElemType>
void Huffman_Tree_StackTraverse(stack<ElemType> &Q){
char p;
//打印顺序栈
int length = Q.size();
ElemType path[length];
for( int i = 0; i < length; i++){
p = Q.top();
Q.pop();
path[i] = p;
}
for( int i = 0; i < length; i++) cout<<path[i];
}
输入说明 :
第一行:待编码的字符集的个数
第二行:待编码的字符
第三行:字符对应的权值
输出说明 :
第一行:Huffman树的层次遍历结果(非叶子结点显示形式: (结点权值),叶子结点显示形式: 结点data(结点权值) )
第二行:Huffman树的前序遍历结果(非叶子结点显示形式: (结点权值),叶子结点显示形式: 结点data(结点权值) )
第三行:Huffman树的中序遍历结果(非叶子结点显示形式: (结点权值),叶子结点显示形式: 结点data(结点权值) )
第四行:Huffman树的后序遍历结果(非叶子结点显示形式: (结点权值),叶子结点显示形式: 结点data(结点权值) )
第五行:空行
第六行开始:n个叶子结点对应的Huffuman编码(1个叶子结点的Huffman编码占一行)
输入范例 :
5
d i a n w
7 5 2 4 9
输出范例 :
(27) (11) (16) i(5) (6) d(7) w(9) a(2) n(4)
(27) (11) i(5) (6) a(2) n(4) (16) d(7) w(9)
i(5) (11) a(2) (6) n(4) (27) d(7) (16) w(9)
i(5) a(2) n(4) (6) (11) d(7) w(9) (16) (27)
d:10
i:00
a:010
n:011
w:11
#include<iostream>
#include<queue>
using namespace std;
int zong;
typedef struct
{
string code="";
char te=0;
int w=-2;
int parent=-2;
int l=-2;
int r=-2;
}havetree;
void tiao(havetree T[],int n,int &X,int &J)
{
int xiao=0;
for(int jj=1;jj<=n;jj++)
{
if(T[jj].parent==-2)
{
xiao=jj;
break;
}
}
for (int j = 0; j < n; ++j)
{
if (T[j].parent == -2)
{
if (T[j].w < T[xiao].w)
xiao = j;
}
}
X = xiao;
for (int i = 0; i < n; ++i)
{
if (T[i].parent == -2 && i != X)
{
xiao = i;
break;
}
}
for (int j = 0; j <n; ++j)
{
if (T[j].parent == -2 && j != X)
{
if (T[j].w< T[xiao].w)
xiao = j;
}
}
J = xiao;
}
void havema(havetree &T,havetree tree[],string s="0")
{
if (T.te != '1') {
string a = s.substr(1, s.size() - 1);
T.code += a;
}
if (T.l != -2) havema(tree[T.l],tree, s + "0");
if (T.l != -2) havema(tree[T.r], tree, s + "1");
}
void ceng(havetree T[],int n)
{
queue<havetree> Q;
Q.push(T[2 * n - 2]);
havetree PPT;
while (!Q.empty())
{
PPT = Q.front();
if(PPT.te!=0)
cout <<PPT.te;
cout <<"(" << PPT.w<< ") ";
Q.pop();
if (PPT.l != -2)
{
Q.push(T[PPT.l]);
}
if (PPT.r != -2)
{
Q.push(T[PPT.r]);
}
}
}
void qian(havetree TT,havetree T[])
{
if (TT.te != 0)
{
cout << TT.te;
}
cout << "(" << TT.w << ")"<<" ";
if (TT.l!= -2)
{
qian(T[TT.l],T);
}
if (TT.r != -2)
{
qian(T[TT.r],T);
}
}
void zhong(havetree TT,havetree T[])
{
if (TT.l != -2)
{
zhong(T[TT.l], T);
}
if (TT.te != 0)
{
cout << TT.te;
}
cout << "(" << TT.w<< ")" << " ";
if (TT.r != -2)
{
zhong(T[TT.r],T);
}
}
void hou(havetree TT,havetree tree[])
{
if (TT.l != -2)
{
hou(tree[TT.l], tree);
}
if (TT.r != -2)
{
hou(tree[TT.r], tree);
}
if (TT.te != 0)
{
cout << TT.te;
}
cout << "(" << TT.w << ")" << " ";
}
int main()
{
int num = 0;
cin >> num;
zong = 2 * num - 1;
havetree T[100];
for(int xi=0;xi<num;xi++)
{
cin>>T[xi].te;
}
for(int xi=0;xi<num;xi++)
{
cin>>T[xi].w;
}
int xiaozhi1=0;
int xiaozhi2=0;
for(int jj=num;jj<zong;jj++)
{
tiao(T,jj,xiaozhi1,xiaozhi2);
T[xiaozhi1].parent = jj;
T[xiaozhi2].parent = jj;
T[jj].l= xiaozhi1;
T[jj].r = xiaozhi2;
T[jj].w= T[xiaozhi1].w + T[xiaozhi2].w;
}
ceng(T, num);
cout << endl;
qian(T[2*num-2],T);
cout << endl;
zhong(T[2*num-2],T);
cout << endl;
hou(T[2*num-2], T);
cout << endl;
havema(T[2*num-2], T);
cout << endl;
for (int i=0;i<num;++i)
{
if (T[i].te!= '1')
{
cout<<T[i].te<< ":" << T[i].code;
if(i!=num-1)
cout << endl;
}
}
return 0;
}