#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std; //定义哈夫曼树存储结构
typedef struct
{
char data; //存放结点数据
int weight; //记录结点权值
int parent, lchild, rchild;
}HTNode, * HuffmanTree; //哈夫曼编码存储表示
typedef char** HuffmanCode; //动态分配数组储存哈夫曼编码表 //初始化
HuffmanTree InitHuffman(HuffmanTree& HT, int n)
{
if (n < )
{
cout << "输入初态结点数目不正确!!!" << endl;
return NULL;
}
else
{
int m = * n - ; //n个叶子结点的哈夫曼树有2n-1个结点
HT = new HTNode[m + ]; //0号单元未用,申请m+1个空间
for (int i = ; i <= m; i++)
{
HT[i].parent = ;
HT[i].lchild = ;
HT[i].rchild = ;
HT[i].weight = ;
HT[i].data = '-';
} //输入初始数据,为了方便理解HT[0]不存放数据
cout << "请输入初态结点数据及相应权值(格式形式:a 3):";
for (int i = ; i <= n; i++)
{
cin >> HT[i].data;
cin >> HT[i].weight;
}
return HT;
}
} //打印HT
void PrintState(HuffmanTree& HT, int n)
{
int m = * n - ; //总结点数
cout << "结点i\tdata值\tweight\tparent\tlchild\trchild" << endl;
for (int i = ; i <= m; i++)
{
cout << setw() << i << "\t";
cout << setw() << HT[i].data << "\t";
cout << setw() << HT[i].weight << "\t";
cout << setw() << HT[i].parent << "\t";
cout << setw() << HT[i].lchild << "\t";
cout << setw() << HT[i].rchild << "\t" << endl;
}
} //选择双亲域为0且两权值最小的结点,选择范围为1到i-1
int* Select(HuffmanTree& HT, int n, int* Idx)
{
int MIN, MinSecond;
//打擂台法使权最小值和次权最小值最大(假设第一个值权值最小无法进行)
MIN = MinSecond = ;
//循环从1到n次
for (int i = ; i <= n; i++)
{
//如果双亲为0(未删除结点与新生成结点),一定会执行if语句,寻找权最小值
if ((HT[i].parent == ) && HT[i].weight < MIN)
{
//将最小的权值给MinSecond方便寻找次最小值
MinSecond = MIN;
MIN = HT[i].weight;
//记录权最小值下标
Idx[] = i;
}
//否则如果满足条件寻找次最小值
else if ((HT[i].parent == ) && HT[i].weight < MinSecond)
{
MinSecond = HT[i].weight;
//记录权次最小值下标
Idx[] = i;
} }
return Idx;
} //构造哈夫曼树
void CreateHuffmanTree(HuffmanTree& HT, int n)
{
if (n <= )
return; int m = * n - ; //n个叶子结点的哈夫曼树有2n-1个结点
//从n+1开始构造哈弗曼树
for (int i = n + ; i <= m; i++)
{
//Idx用于存放两个返回最小权值的下标,i-1为前n个结点,后面随着i增加,n也增加
int* Idx = Idx = new int[];
Idx = Select(HT, i - , Idx);
int s1 = Idx[]; //权最小值下标
int s2 = Idx[]; //权次最小值下标
//给两权值最小的结点置双亲,使s1,s2结点不在录入Select范围
HT[s1].parent = i;
HT[s2].parent = i; //给新节点i左右孩子置位s1,s2
HT[i].lchild = s1;
HT[i].rchild = s2; //给新结点赋权值
HT[i].weight = HT[s1].weight + HT[s2].weight;
delete[]Idx;
}
} //哈夫曼编码
void CreateHuffmanCode(HuffmanTree& HT, HuffmanCode& HC, int n)
{
HC = new char* [n + ]; //分配字符的空间
char* TempCode = new char[n]; //分配临时编码表空间n个
TempCode[n - ] = '\0'; //编码有叶子结点开始逆序存放,先将末尾结束符标志打上,为后序strcpy
//for循环逐个逆序求叶子结点的哈夫曼编码
for (int i = ; i <= n; i++)
{
int start = n - ; //开始存放的起点指向末尾,用于后面HC拷贝是的起始地址
int NodeIdx = i; //NodeIdx最开始存放叶子结点序号
int ParentsIdx = HT[i].parent; //Parents指向其双亲结点序号
//若有双亲则由下到上进行编码,编码的字符,从序号1开始
while (ParentsIdx)
{
start--; //在一维数组末尾,strat先指向最后
//若双亲结点的左结点序号为NodeIdx,将0打入一维临时数组中,否则打入1
if (HT[ParentsIdx].lchild == NodeIdx)
TempCode[start] = '';
else
TempCode[start] = '';
//结点的序号更新,进入上一层
NodeIdx = ParentsIdx;
ParentsIdx = HT[NodeIdx].parent;
}
//临时一维数组存放编码成功,开始用HC顺序存放字符编码
HC[i] = new char[n - start]; //为序号为i的字符分配编码空间
strcpy_s(HC[i], n - start, &TempCode[start]); //编码字符串拷贝strcpy报错因为没有指定长度
}
//打印哈夫曼编码
cout << "---字符对应编码----" << endl;
for (int i = ; i <= n; i++)
{
cout << HT[i].data << "\t\t" << HC[i] << endl;
}
delete []TempCode;
} //输入字符打印哈夫曼编码
void PrintCode(HuffmanTree & HT, HuffmanCode & HC, int n)
{
char *str =new char[]; //存储需要解码的字符
int flag = ; //flag用于检查输入是否错误
cout << "请输入需要编码的字符:";
cin >> str;
//匹配字符并打印相应的哈夫曼编码
cout << "输入的字符哈夫曼编码为:";
for (int j = ; j < strlen(str); j++)
{
flag = ;
for (int i = ; i <= n; i++)
{
//匹配成功打印编码
if (HT[i].data == str[j])
{
cout << HC[i] ;
flag = ; //匹配成功
}
}
//如果有匹配失败的情况,则跳出循环
if (flag == )
{
cout << "\n第" << j+ << "字符输入错误!" ;
break;
} }
putchar();
delete []str; //释放str空间
} //哈夫曼解码并打印
void HuffmanDecode(HuffmanTree& HT, int n)
{
char* str = new char[];
cout << "请输入二进制编码:";
cin >> str; int flag = ; //用于检查二进制编码是否输入错误
cout << "解码对应字符为:";
//遍历二进制编码
for (int i = ; i < strlen(str);)
{
int Root = * n - ; //Root为根结点序号
//当结点的左右孩子不为空时进入循环,由根结点进入
while (HT[Root].lchild && HT[Root].rchild)
{
if (str[i] == '')
Root = HT[Root].lchild;
else if (str[i] == '')
Root = HT[Root].rchild;
else
{
cout << "输入的二级制编码有误!" << endl;
flag = ;
break;
}
i++; //相后读取二进制编码,i值更新
}
//如果找到错误跳出循环
if (flag)
break;
//打印编码对应字符
cout << HT[Root].data;
}
delete []str;
} int main()
{
int n;
cout << "请输入哈夫曼树初态结点数:";
cin >> n; //初始化哈夫曼树
HuffmanTree HT = InitHuffman(HT, n);
//打印HT初态
cout << "--------------------HT初态--------------------" << endl;
PrintState(HT, n);
//构造哈夫曼树
CreateHuffmanTree(HT, n);
//打印HT终态
cout << "--------------------HT终态--------------------" << endl;
PrintState(HT, n); HuffmanCode HC;
//哈夫曼编码-由下而上
CreateHuffmanCode(HT, HC, n);
//打印字符对应编码
PrintCode(HT, HC, n);
//哈夫曼解码并打印-由上而下
HuffmanDecode(HT, n); return ;
}

//由于编译器版本原因strcpy出现不安全原因,导致无法运行,后使用strcpy_s给予拷贝长度得到解决;把“==”写成“=”导致报错;
/*
输入字符串统计字符个数(权值)
int CreateWeightArray(char* str, int* Array) {
//初始化权值数组,128为str[i]的最大数值
for (int i = 0; i < 128; i++)
{
Array[i] = 0;
}

int length = 0;

//利用下标记录位权
for (int i = 0; str[i]; i++)
{
Array[str[i]]++; //值加1,下标即字符
}
//统计字符串去重后的长度
for (int i = 0; i < 128; i++)
{
if (Array[i] != 0)
{
length++;
}
}
return length;
}
*/

c++实现哈夫曼树,哈夫曼编码,哈夫曼解码(字符串去重,并统计频率)的更多相关文章

  1. 20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码

    20172332 2017-2018-2 <程序设计与数据结构>Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 哈夫曼树 1.路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子 ...

  2. [C++]哈夫曼树(最优满二叉树) / 哈夫曼编码(贪心算法)

    一 哈夫曼树 1.1 基本概念 算法思想 贪心算法(以局部最优,谋求全局最优) 适用范围 1 [(约束)可行]:它必须满足问题的约束 2 [局部最优]它是当前步骤中所有可行选择中最佳的局部选择 3 [ ...

  3. 采用C++实现哈夫曼树的创建并输出哈夫曼编码

    一.这篇随笔来自一道信息论的作业题,因为手动编码过于复杂,所以想到了编程解决,原题目如下图所示: 二.源代码如下: #include <iostream> #include <str ...

  4. 哈夫曼树【最优二叉树】【Huffman】

    [转载]只为让价值共享,如有侵权敬请见谅! 一.哈夫曼树的概念和定义 什么是哈夫曼树? 让我们先举一个例子. 判定树:         在很多问题的处理过程中,需要进行大量的条件判断,这些判断结构的设 ...

  5. 数据结构之C语言实现哈夫曼树

    1.基本概念 a.路径和路径长度 若在一棵树中存在着一个结点序列 k1,k2,……,kj, 使得 ki是ki+1 的双亲(1<=i<j),则称此结点序列是从 k1 到 kj 的路径. 从 ...

  6. C++哈夫曼树编码和译码的实现

    一.背景介绍: 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的 ...

  7. 哈夫曼树(三)之 Java详解

    前面分别通过C和C++实现了哈夫曼树,本章给出哈夫曼树的java版本. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载请注明出处:htt ...

  8. 哈夫曼树(二)之 C++详解

    上一章介绍了哈夫曼树的基本概念,并通过C语言实现了哈夫曼树.本章是哈夫曼树的C++实现. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载 ...

  9. 哈夫曼树(一)之 C语言详解

    本章介绍哈夫曼树.和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可.若 ...

  10. 【算法】赫夫曼树(Huffman)的构建和应用(编码、译码)

    参考资料 <算法(java)>                           — — Robert Sedgewick, Kevin Wayne <数据结构>       ...

随机推荐

  1. tomcat安装分享

    安装Tomcat前需要安装JDK 安装的jdk1.8   解压   在vim /etc/profile下面添加以下内容 export JAVA_HOME=/jdk/jdk1.8.0_111export ...

  2. each of which 用法

    each of which 在以下為 同位語,非關代. 1. An urn contains two balls, each of which is known to be either white ...

  3. MySQL 新建用户和数据库

    MySQL 新建用户和数据库 修改MySql的密码为qwe123 /usr/local/bin/mysqladmin -u root -p password qwe123 mysql设置root远程访 ...

  4. BUUCTF--xor

    测试文件:https://buuoj.cn/files/caa0fdad8f67a3115e11dc722bb9bba7/7ea34089-68ff-4bb7-8e96-92094285dfe9.zi ...

  5. Linux文件行排序

    sort:对文件的行排序 - 准备一份文件:char.txt - sort char.txt:结果会按照头字母顺序排 - sort -o sortchar.txt char.txt:排序char.tx ...

  6. Android学习电子书

           

  7. .net core 集成极光推送

    登录极光推送 创建应用 appkey和master secret在推送时会使用 设置推送 使用手机扫描二维码安装apk 下载dll 测试 using Jiguang.JPush; using Jigu ...

  8. vue星级评分组件

    <template> <div class="Rating-gray"> <i v-for="(item,index) in itemCla ...

  9. Kettle数据同步速度调优记录

    Msyql到Vertica 1.mysql中在openshop 数据库中选择其中一个300W左右数据的表 create table ip_records_tmp_01 AS SELECT * FROM ...

  10. SOA架构是什么?

    https://blog.csdn.net/u013343616/article/details/79460398 SOA是什么?SOA全英文是Service-Oriented Architectur ...