// 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. 【读书笔记】iOS-NSString的length

    NSString的length方法能够准确无误地处理国际字符串,如含有俄文,中文或者日本文字符的字符串,以及使用Unicode国际字符标准的字符串.在C语言中处理这些国际字符串是件令人非常头疼的事情 ...

  2. iOS之 PJSIP静态库编译(一)

    首先放上pjsip官方网站http://www.pjsip.org/download.htm 下载的时候注意while the .bz2 has LF line-ends and is for Uni ...

  3. MAC OS Finder 中快速定位指定路径

    在看一些 tip 文章的时候,时不时会有需要进到某某目录替换文件之类的步骤.如果碰上这个目录层次够多,一层一层的点击既麻烦又容易出错,有什么快捷的办法呢? 快捷键:Shift + Command + ...

  4. Openstack python api 学习文档 api创建虚拟机

    Openstack python api 学习文档 转载请注明http://www.cnblogs.com/juandx/p/4953191.html 因为需要学习使用api接口调用openstack ...

  5. 使用 ServiceStack.Text 序列化 json 比Json.net更快

    本节将介绍如何使用ServiceStack.Text 来完成高性能序列化和反序列化操作. 在上章构建高性能ASP.NET应用的几点建议 中提到使用高性能类库,有关于JSON序列化的讨论. 在诊断web ...

  6. eclipse常用快捷键及调试方法(虽然现在看不懂,但是感觉以后肯定会用到,先转了)

    常用快捷键 Eclipse最全快捷键,熟悉快捷键可以帮助开发事半功倍,节省更多的时间来用于做有意义的事情. Ctrl+1 快速修复(最经典的快捷键,就不用多说了) Ctrl+D: 删除当前行 Ctrl ...

  7. solrcloud 配置实践

    1.环境 3台虚拟机:192.168.26.129.192.168.26.131.192.168.26.132,使用命令sudo iptables -F 关闭防火墙 Solr: solr-6.1.0 ...

  8. hibernate多对多映射关系实现

    Course.hbm.xml: <?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC        &q ...

  9. session实现购物系统的简例和application实现统计页面访问次数的简例

    login.jsp <body>  <form action="checkLogin.jsp">  <table>  <tr>< ...

  10. 设计模式C#实现(八)——原型模式

    原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.(要创建一个对象,这个对象为实现原型接口,方法是原型克隆.克隆只是方法而不是原型模式的目的,创建对象才是目的) UML类图: ...