// haffman.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include<iostream>
using namespace std; typedef struct hfnode
{
char ch; //存储字符
int weight; //存储权值
int parent; //双亲结点位置
int lchild; //左右孩子结点位置
int rchild;
} hfnode,*hfmtree; typedef struct node
{
char code[];
} node,*hfcode; #define Nsymbols 10 hfnode *Inithfm(hfnode *tree,int n) //千万不能用关键字命名。把这些节点作为带权值的二叉树的根节点,左右子树为空
{
//tree = new hfnode[n]; //多余了,已经在main函数中声明了。
for(int i = ;i < n; i++)
{
tree[i].ch = '';
tree[i].weight = ;
tree[i].lchild = ;
tree[i].rchild = ;
tree[i].parent = ;
}
cout << "请输入想要编码的字符序列,按照先字符后次数的顺序输入" << endl;
for(int i = ;i < ; i++)
{
cin >> tree[i].ch >>tree[i].weight;
}
cout <<endl; for(int i = ;i < ;i++)
cout << tree[i].ch << " "<<tree[i].weight<<" ";
cout << endl;
return tree;
} void select(hfnode *tree,int n,int *p1,int *p2) //选择两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且至新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
{
//找一个作为参考,返回的是结点
int x,y;
for(int i = ;i <= n;i++)
{
if(tree[i].parent==)
{
x = i;
break;//找到一个参考点即可
}
} for(int i = ;i <= n;i++) //找出最小的结点
{
if((tree[i].parent==)&&(tree[i].weight!=))
{
if(tree[i].weight < tree[x].weight)
x = i;
}
} for(int j = ;j <= n;j++)
{
if((tree[j].parent==)&&(j!=x))
{
y = j;
break;//找到一个参考点即可
}
}
for(int j = ;j <= n;j++) //找出次小的结点
{
if((tree[j].parent==)&&(tree[j].weight!=)&&j!=x)
{
if(tree[j].weight < tree[y].weight)
y = j;
}
}
*p1 = x;
*p2 = y;
}
//对哈弗曼树进行编码。 void HfCode(hfnode *tree,int n,node *hfmcode,int m)
{
int c,f;
int start = ; for(int i=;i<;i++)
{
for(c=i,f=tree[c].parent;f!=;c=f,f=tree[c].parent) //追溯法,从叶子节点出发,一路往上追溯。
{
if(tree[f].lchild==c)
hfmcode[i].code[start++] = '';
else
hfmcode[i].code[start++] = '';
}
start = ;
}
} void Print(node *hfmcode,int m)
{
for(int i = ;i < m;i++)
{
for(int j = ;j < m;j++)
cout <<hfmcode[i].code[j];
cout << endl;
}
cout << endl;
} int main()
{
int p1=,p2=; //为了接收最小和次小的两个节点
hfnode tree[Nsymbols]; //当我们不是用指针,这种情况下,已经全部赋值了。不用再一次赋值了。
Inithfm(tree,Nsymbols); //初始化结构体数组。 //建立哈弗曼树 for(int m = ;m < *-;m++) //二叉树性质
{
select(tree,m-,&p1,&p2);
tree[p1].parent = m;
tree[p2].parent = m;
tree[m].lchild = p1;
tree[m].rchild = p2;
tree[m].weight = tree[p1].weight + tree[p2].weight;
tree[m].parent =; //其实这句也可以不用,因为初始化时已经初始化为0了。
} node hfmcode[];
// 初始化,不然打印的时候会出现未知错。
for(int i = ;i < ;i++)
{
for(int j = ;j < ;j++)
hfmcode[i].code[j]='\0';
} HfCode(tree,Nsymbols,hfmcode,); //编码函数
Print(hfmcode,); //打印函数
return ;
}

实验名称:哈弗曼编码

实验目的:了解前缀编码的概念,理解数据压缩的基本方法;

掌握Huffman编码的设计思想并能熟练应用。

实验要求:对有字符集{A,B,C,D},各字符在电文中出现的次数集为{1,3,4,7};

要求编程实现Huffman树的构造,并在此基础上编程实现Huffman编码。

实验步骤及内容

1、首先建立一个定义哈弗曼树的结构体Node,及结构体指针LinkList,该结构体包含一个存储字符的ch,存储权值的weight,存储双亲结点的parent,存储左右孩子的lchild与rchild。代码如下:

typedef struct hfnode

{

char ch;      //存储字符

int weight;   //存储权值

int parent;   //双亲结点位置

int lchild;   //左右孩子结点位置

int rchild;

} hfnode,*hfmtree;

2、定义一个存储编码的结构体,主要是为了方便打印,代码如下:

typedef struct node

{

char code[10];

} node,*hfcode;

3、初始化函数,因为默认值是一个不确定的值,必须进行初始化才行。

hfnode *Inithfm(hfnode *tree,int n)  //千万不能用关键字命名。把这些节点作为带权值的二叉树的根节点,左右子树为空

{

//tree = new hfnode[n]; //多余了,已经在main函数中声明了。

for(int i = 0;i < n; i++)

{

tree[i].ch = '0';

tree[i].weight = 0;

tree[i].lchild = 0;

tree[i].rchild = 0;

tree[i].parent = 0;

}

cout << "请输入想要编码的字符序列,按照先字符后次数的顺序输入" << endl;

for(int i = 0;i < 4; i++)

{

cin >> tree[i].ch >>tree[i].weight;

}

cout <<endl;

for(int i = 0;i < 4;i++)

cout << tree[i].ch << " "<<tree[i].weight<<" ";

cout << endl;

return tree;

}

4、选择两棵根结点权值最小的树作为左右子树。

void select(hfnode *tree,int n,int *p1,int *p2) //选择两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且至新的二叉树的根结点的权值为其左右子树上根结点的权值之和。

{

//找一个作为参考,返回的是结点

int x,y;

for(int i = 0;i <= n;i++)

{

if(tree[i].parent==0)

{

x = i;

break;//找到一个参考点即可

}

}

for(int i = 0;i <= n;i++)  //找出最小的结点

{

if((tree[i].parent==0)&&(tree[i].weight!=0))

{

if(tree[i].weight < tree[x].weight)

x = i;

}

}

for(int j = 0;j <= n;j++)

{

if((tree[j].parent==0)&&(j!=x))

{

y = j;

break;//找到一个参考点即可

}

}

for(int j = 0;j <= n;j++)   //找出次小的结点

{

if((tree[j].parent==0)&&(tree[j].weight!=0)&&j!=x)

{

if(tree[j].weight < tree[y].weight)

y = j;

}

}

*p1 = x;

*p2 = y;

}

5、构造哈弗曼树

//建立哈弗曼树

for(int m = 4;m < 2*4-1;m++) //二叉树性质

{

select(tree,m-1,&p1,&p2);

tree[p1].parent = m;

tree[p2].parent = m;

tree[m].lchild = p1;

tree[m].rchild = p2;

tree[m].weight = tree[p1].weight + tree[p2].weight;

tree[m].parent =0; //其实这句也可以不用,因为初始化时已经初始化为了。

}

6、对哈弗曼树进行编码。编码函数如下:

//对哈弗曼树进行编码。

void HfCode(hfnode *tree,int n,node *hfmcode,int m)

{

int c,f;

int start = 0;

for(int i=0;i<10;i++)

{

for(c=i,f=tree[c].parent;f!=0;c=f,f=tree[c].parent) //追溯法,从叶子节点出发,一路往上追溯。

{

if(tree[f].lchild==c)

hfmcode[i].code[start++] = '0';

else

hfmcode[i].code[start++] = '1';

}

start = 0;

}

}

7、打印编码

void Print(node *hfmcode,int m)

{

for(int i = 0;i < m;i++)

{

for(int j = 0;j < m;j++)

cout <<hfmcode[i].code[j];

cout << endl;

}

cout << endl;

}

另配上一副自己用画图工具画的理论分析图:

结果与C++代码结果一致。

总结:

    此次实验,让我理解了结构体数组的使用以及初始化,内存管理等方面的熟悉,感觉收获挺大的。

C++哈弗曼编码的更多相关文章

  1. js神秘的电报密码---哈弗曼编码

    哈夫曼编码,根据每个单词在文本中出现的次数频率为权值,频率高的权值大.然后每次取两个频率最小的生成树,最后生成一颗大树.从根节点到该单词的路径,左边为0,右边为1, function HFM(){ v ...

  2. 用C++实现文件压缩(1 哈弗曼编码)

    今天下午想把文件压缩写一下,因为我觉得这个还是比较锻炼技术的,对数据结构的要求应该比较高,权当练习了吧. 我采用的压缩方式是Huffman编码,不过比较囧的是,我拼写拼错了,我拼的是haffman,在 ...

  3. java 哈夫曼编码

    //哈夫曼树类 public class HaffmanTree { //最大权值 ; int nodeNum ; //叶子结点个数 public HaffmanTree(int n) { this. ...

  4. 哈弗曼实现(C++)

    HuffmanCode.h #ifndef HUFFMANCODE_H #define HUFFMANCODE_H enum LRSTATUS { LEFTCHILD, //左子树 RIGHTCHIL ...

  5. K:哈弗曼树

    相关介绍:  树形结构除了应用于查找和排序等操作时能调高效率,它在信息通讯领域也有着广泛的应用.哈弗曼(Huffman)树就是一种在编码技术方面得到广泛应用的二叉树,它同时也是一种最优二叉树. 哈弗曼 ...

  6. 数据压缩之经典——哈夫曼编码(Huffman)

    (笔记图片截图自课程Image and video processing: From Mars to Hollywood with a stop at the hospital的教学视频,使用时请注意 ...

  7. 哈夫曼编码(Huffman coding)的那些事,(编码技术介绍和程序实现)

    前言 哈夫曼编码(Huffman coding)是一种可变长的前缀码.哈夫曼编码使用的算法是David A. Huffman还是在MIT的学生时提出的,并且在1952年发表了名为<A Metho ...

  8. java实现哈弗曼树

    O(∩_∩)O~~ 概述 我想学过数据结构的小伙伴一定都认识哈弗曼,这位大神发明了大名鼎鼎的“最优二叉树”,为了纪念他呢,我们称之为“哈弗曼树”.哈弗曼树可以用于哈弗曼编码,编码的话学问可就大了,比如 ...

  9. 哈弗曼树的理解和实现(Java)

    哈弗曼树概述 哈弗曼树又称最优树,是一种带权路径长度最短的树,在实际中有广泛的用途.哈弗曼树的定义,涉及路径.路径长度.权等概念.哈弗曼树可以用于哈弗曼编码,用于压缩,用于密码学等. 哈弗曼树的一些定 ...

随机推荐

  1. 【原】画流程图工具visio使用技巧汇总

    最近写论文需要画不少流程图,有两种选择,一是word, 二是visio.原先一直用word画,效果也还可以,但是每个部件画完后为了便于适应排版变动,需要将需要的模块按下ctrl逐个点击选中后进行组合. ...

  2. mac os x使用Git简易入门教程

    具体如下: 1, 首先要了解什么是Git. 简而言之,Git是一个分布式的代码版本管理工具.类似的常用工具还有SVN,CVS. 概念了解参见:http://baike.baidu.com/subvie ...

  3. 实验:传输层:UDP协议 学习笔记

    一.传输层协议 从之前介绍的网络层协议来看,通信的两端是两台主机,IP数据报首部就标明了这两台主机的IP地址.但是从传输层来看,是发送方主机中的一个进程与接收方主机中的一个进程在交换数据,因此,严格地 ...

  4. nim3取石子游戏 (威佐夫博弈)

    http://www.cnblogs.com/jackge/archive/2013/04/22/3034968.html 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有 ...

  5. Android keystore 密码忘记了的找回办法

    keystore密码忘记了,准备给自己的应用发布一个新版本,在apk打包时,发现之前的用的keystore密码忘了.如果换一个keystore,则之前已经安装应用的用户就必须手工卸载原应用才能安装,非 ...

  6. Effective Java 40 Design method signatures carefully

    Principle Choose method names carefully. Don't go overboard in providing convenience methods. Avoid ...

  7. Effective Java 52 Refer to objects by their interfaces

    Principle If appropriate interface types exist, then parameters, return values, variables, and field ...

  8. nginx添加模块 (非覆盖安装)

    nginx添加模块(非覆盖安装) 原已经安装好的nginx,现在需要添加一个未被编译安装的模块: 查看原来编译时都带了哪些参数# /usr/local/nginx/sbin/nginx -V ngin ...

  9. hdu 2199 Can you solve this equation?(二分搜索)

    Can you solve this equation? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ( ...

  10. hdu 2583 permutation

    permutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...