链表哈夫曼树--编码--解码
哈夫曼树的编码解码,输入是一个txt文件吗,给出文件的路径;
里面包含的结构体声明如下:
#define NOTFIND -1
#define LEFT 0
#define RIGHT 1struct h_code{ //哈夫曼编码的结构体char data;vector<string>char_code; //存放字符的哈夫曼编码的
};struct node
{int count; //字符出现的次数char data; //保存字符struct node* pleftchild; //右孩子struct node* prightchild; //左孩子int level; //表示节点的所在层数
};bool operator <(node a,node b){ //给结构体设置优先队列return a.count>b.count;
}
类的声明如下:
class Huffman_code{
private:string filepath = R"(C:\Users\ycig\CLionProjects\haffman_code\data.txt)";char nochar = '#'; //非叶子节点的数据域保存的数据node *p; //哈夫曼树的工作指针node phead; //哈弗曼树头结点h_code *p_h_code; //哈夫曼编码结构体数组的首地址int char_size; //读取的字符的种类个数vector<char>chartxt; //存放文本的数据int Find_char(char input); //寻找字符在哈夫曼编码结构体数组的位置
public:Huffman_code(); //构造函数void char_code(); //打印哈夫曼树,生成哈夫曼编码void huffman_encode(); //对文本进行编码,并写入txt文档void huffman_decode(); //哈夫曼解码void Show_char_code(); //打印哈夫曼字符编码void Level_traversal(node * q,int level); //哈夫曼树的层次遍历,标记每一层节点所在的层数
};
大概流程是:
读取txt文件:
ifstream in(filepath); //打开文件,filepath的值是类的私有属性in>>noskipws; //不跳过换行和空格char ch; vector<char>words; //接收读取的txt的字符数组struct node *work_node = new struct node;while(in>>ch) //加入字符数组{words.push_back(ch);}
统计字符出现的次数:
vector<struct node>my_char; //存放字符出现次数的for(int i=0;i<words.size();i++){if(have_char(my_char,words[i]) == NOTFIND) //字符还没有统计{work_node->count = 1; //出现次数设置为1work_node->data = words[i]; //记录字符串work_node->pleftchild = nullptr; //左孩子置为空work_node->prightchild = nullptr; //右孩子置为空my_char.push_back(work_node[0]);}
将统计好次数的结构体数组放到优先队列里面去,哈夫曼树的构造选取的是贪心算法,每次取权重最小的两棵树,生成一颗新的树,然后放到优先队列里面去;循环的终止条件是优先队列里面只有一个树,也就是下面的node_priqueue.size() == 1的时候。
while(node_priqueue.size()>1){node * left = new node ; //左孩子节点node * right = new node; //右孩子节点node * father = new node; //父节点left->pleftchild = node_priqueue.top().pleftchild; //接收优先队列队首的值left->prightchild = node_priqueue.top().prightchild;left->data = node_priqueue.top().data;left->count = node_priqueue.top().count;node_priqueue.pop(); //出队right->data = node_priqueue.top().data;right->count = node_priqueue.top().count;right->prightchild = node_priqueue.top().prightchild;right->pleftchild = node_priqueue.top().pleftchild;node_priqueue.pop();father->pleftchild = left; //把左右孩子连接到父节点去father->prightchild = right;father->count = left->count+right->count;father->data = nochar; //父节点的字符域设为默认值node_priqueue.push(*father); //父节点进队}
生成之后初始化了些东西,如下:
phead = node_priqueue.top();p = &phead; //保存哈夫曼树的指针chartxt = words; //保存读取到的数据,后面生成编码会用到//*************设置哈夫曼树节点的层数**********************************Level_traversal(&phead); //给生成哈夫曼树的节点标记下层数,递归写的,生成哈夫曼字符编码会用到
下面开始遍历哈夫曼树,生成字符编码。
我的思路是用栈保存指针移动的轨迹,从头节点开始,如果向左移动,就往压栈0(0表示向左移动,1表示向右移动)。
先序遍历,当p第一次移动到空的时候:
节点栈里面的有:9,4,2,A
轨迹栈:0000
此时指针移动到A的左孩子,此时为空,然后弹节点栈,得到A的指针,判断节点A在多少层,A在第三层,轨迹栈只能有(A->level-1)3个元素,出栈一个元素;此时:
节点栈:9,4,2
轨迹栈:000
指针移动到A的右孩子,也为空,继续弹栈,得到2号节点,在第三层,轨迹栈只能有3-1个元素。
此时:
节点栈:9,4
轨迹栈:00
指针移动到2号节点的右孩子,到B位置,轨迹栈压栈1,此时
节点栈:9,4,B
轨迹栈:001
输出轨迹栈,用一个栈保存节点栈的数据,往新的栈里面压栈,然后再弹出就可以得到100的编码
指针继续移动到B的左孩子,B的左孩子为空,弹节点栈得到B号节点,判断节点B在多少层,B在第三层,轨迹栈只能有(B->level-1)3个元素,不出栈
此时:
节点栈:9,4
轨迹栈:001
B的右孩子也为空,将p空置,继续弹节点栈得到节点4,在第二层,轨迹栈最多1个元素,出轨迹栈两次
此时:
节点栈:9
轨迹栈:0
指针继续移动到第二个二号节点,压轨迹栈1。此时:
节点栈:9,2
轨迹栈:01
继续左移,到C节点,此时:
节点栈:9,2,c:
轨迹栈:010
记录C的哈夫曼编码。继续移动到C的孩子,为空,不压轨迹栈。
弹节点栈,弹栈得到第二个2号节点(9),在第三层,轨迹栈只能有2个元素,出栈一次(01)。移动到D号节点,轨迹栈压栈一次1,此时:
节点栈:9,D
轨迹栈:011
记录D的哈夫曼编码
D无左右孩子,弹栈得到9号节点(根节点),轨迹栈最多只能有(1-1)个元素,弹空。
以上就是左子树遍历的过程。有了哈夫曼编码,解码就容易多了。
下面就是全部代码:
#include <iostream>
#include "fstream"
#include "string"
#include<vector>
#include "queue"
#include "stack"
using namespace std;#define NOTFIND -1
#define LEFT 0
#define RIGHT 1struct h_code{ //哈夫曼编码的结构体char data;vector<string>char_code; //存放字符的哈夫曼编码的
};struct node
{int count; //字符出现的次数char data; //保存字符struct node* pleftchild; //右孩子struct node* prightchild; //左孩子int level;
};bool operator <(node a,node b){ //给结构体设置优先队列return a.count>b.count;
}class Huffman_code{
private:string filepath = R"(C:\Users\ycig\CLionProjects\haffman_code\data.txt)";char nochar = '#'; //非叶子节点的数据域保存的数据node *p; //哈夫曼树的工作指针node phead; //哈弗曼树头结点h_code *p_h_code; //哈夫曼编码结构体数组的首地址int char_size; //读取的字符的种类个数vector<char>chartxt; //存放文本的数据int Find_char(char input); //寻找字符在哈夫曼编码结构体数组的位置
public:Huffman_code(); //构造函数void char_code(); //打印哈夫曼树,生成哈夫曼编码void huffman_encode(); //对文本进行编码,并写入txt文档void huffman_decode(); //哈夫曼解码void Show_char_code(); //打印哈夫曼字符编码void Level_traversal(node * q,int level); //哈夫曼树的层次遍历,标记每一层节点所在的层数
};void Huffman_code::Level_traversal(node * q,int level=1) {if(q){q->level = level;if(q->pleftchild){Level_traversal(q->pleftchild,level+1);}if(q->prightchild){Level_traversal(q->prightchild,level+1);}}
}void Huffman_code::Show_char_code() {for(int i=0;i<char_size;i++){cout<<p_h_code[i].data<<"的哈夫曼编码是: ";for(int j=0;j<p_h_code[i].char_code.size();j++){cout<<p_h_code[i].char_code[j];}cout<<endl;}
}void Huffman_code::huffman_decode() {ifstream in(R"(..\Huffmancode.txt)");queue<char>decode_queue;char ch;while(in>>ch){decode_queue.push(ch);}p = &phead;//清空文件内容ofstream out(R"(..\Huffmandecode.txt)",ios::trunc);while(p&&!decode_queue.empty()){while(p->data == nochar){if(decode_queue.front() == '1'){p = p->prightchild;decode_queue.pop();}else{p = p->pleftchild;decode_queue.pop();}}//写入文本ofstream out(R"(..\huffmandecode.txt)",ios::app);{out<<p->data;}p = &phead; //读取到数据后指针重新回到头结点}
}int Huffman_code::Find_char(char input) {for(int i=0;i<char_size;i++){if(p_h_code[i].data == input){return i;}}return NOTFIND;
}void Huffman_code::huffman_encode() { //将生成的哈夫曼编码写入txt文件vector<string> huffman_encode; //存放编码的数组for (int i = 0; i < chartxt.size(); i++){int pos = Find_char(chartxt[i]);for(int j=0;j<p_h_code[pos].char_code.size();j++){huffman_encode.push_back(p_h_code[pos].char_code[j]);}}//清空文件内容ofstream in (R"(..\Huffmancode.txt)",ios::trunc);//写入ofstream out(R"(..\Huffmancode.txt)");for(int i=0;i<huffman_encode.size();i++){out<<huffman_encode[i];}
}
int have_char(vector<struct node>my_char,char ch){ //判断字符在不在结构体数组里面for(int i=0;i<my_char.size();i++){if(ch == my_char[i].data){return i; //找到了就返回下标}}return NOTFIND; //没有找到就返回-1
}void Huffman_code::char_code() {h_code *pnew = new h_code[char_size]; //申请空间p_h_code = pnew; //赋值给类的私有成员属性int charcode_pos = 0; //哈夫曼字符编码的下标p = &phead; //取哈夫曼树父节点地址stack<string>huffman_trailed; //保存哈夫曼编码010101010类型的stack<node *>huffman_stack; //用来先序遍历保存节点的栈while(!huffman_stack.empty()||p) //当栈不为空在的时候,执行循环{while(p){if(p->data != '#'){ //当是叶子节点的时候//cout<<"测试编码"<<p->data;p_h_code[charcode_pos].data = p->data;//****************栈的逆序输出(先输出栈底)***************************************stack<string>show;stack<string>copy=huffman_trailed;while(!copy.empty()){show.push(copy.top());copy.pop();}while(!show.empty()){p_h_code[charcode_pos].char_code.push_back(show.top());//cout<<show.top();show.pop();}//cout<<endl;charcode_pos++; //下标加一}huffman_stack.push(p); //头结点进栈if(p->pleftchild){p = p->pleftchild;huffman_trailed.push("0");}else{p = nullptr;}}if(!huffman_stack.empty()){ //此时左孩子已经遍历结束p = huffman_stack.top();while(huffman_trailed.size()>p->level-1){huffman_trailed.pop();}huffman_stack.pop();if(p->prightchild){p = p->prightchild;huffman_trailed.push("1");}else{p = nullptr;}}}
}Huffman_code::Huffman_code() {ifstream in(filepath); //打开文件in>>noskipws; //不跳过换行和空格char ch;vector<char>words;struct node *work_node = new struct node;while(in>>ch) //加入字符数组{words.push_back(ch);}//**********************统计字符出现的次数**************************vector<struct node>my_char; //存放字符出现次数的for(int i=0;i<words.size();i++){if(have_char(my_char,words[i]) == NOTFIND) //字符还没有统计{work_node->count = 1; //出现次数设置为1work_node->data = words[i]; //记录字符串work_node->pleftchild = nullptr; //左孩子置为空work_node->prightchild = nullptr; //右孩子置为空my_char.push_back(work_node[0]);}else{my_char[have_char(my_char,words[i])].count++; //字符统计次数加一}}char_size = my_char.size();//****************把统计结果添加到结构体优先队列中*****************priority_queue<node>node_priqueue;for(int i=0;i<my_char.size();i++){node_priqueue.push(my_char[i]);}//***************生成哈夫曼树*************************************while(node_priqueue.size()>1){node * left = new node ; //左孩子节点node * right = new node; //右孩子节点node * father = new node; //父节点left->pleftchild = node_priqueue.top().pleftchild; //接收优先队列队首的值left->prightchild = node_priqueue.top().prightchild;left->data = node_priqueue.top().data;left->count = node_priqueue.top().count;node_priqueue.pop(); //出队right->data = node_priqueue.top().data;right->count = node_priqueue.top().count;right->prightchild = node_priqueue.top().prightchild;right->pleftchild = node_priqueue.top().pleftchild;node_priqueue.pop();father->pleftchild = left; //把左右孩子连接到父节点去father->prightchild = right;father->count = left->count+right->count;father->data = nochar; //父节点的字符域设为默认值node_priqueue.push(*father); //父节点进队}phead = node_priqueue.top();p = &phead;chartxt = words;//*************设置哈夫曼树节点的层数**********************************Level_traversal(&phead);//************生成哈夫曼字符编码***************************************char_code();//**************编码*************************************************huffman_encode();
}int main() {Huffman_code().huffman_decode();
}
生成编码文件和解码文件在执行文件.exe的上层目录。
运行效果如下:
输入:
春江花月夜
【作者】张若虚 【朝代】唐译文对照
春江潮水连海平,海上明月共潮生。滟滟随波千万里,何处春江无月明!江流宛转绕芳甸,月照花林皆似霰;空里流霜不觉飞,汀上白沙看不见。江天一色无纤尘,皎皎空中孤月轮。江畔何人初见月?江月何年初照人?人生代代无穷已,江月年年望相似。不知江月待何人,但见长江送流水。白云一片去悠悠,青枫浦上不胜愁。谁家今夜扁舟子?何处相思明月楼?可怜楼上月裴回,应照离人妆镜台。玉户帘中卷不去,捣衣砧上拂还来。此时相望不相闻,愿逐月华流照君。鸿雁长飞光不度,鱼龙潜跃水成文。昨夜闲潭梦落花,可怜春半不还家。江水流春去欲尽,江潭落月复西斜。斜月沉沉藏海雾,碣石潇湘无限路。不知乘月几人归,落月摇情满江树。
编码:
01010001100110001011011000111100000000111101100101010111110100011111000101011101011001001110000010111001111111010110000011101101110110010011100010100000110010111100110000111011101001100100000010101111011111110111000110010011100000100101010100110111110001101010110011100100111000101000001001101000001010000110011010010100010101100011100001000111001101011111010100110111011101001101001010001100110001011011000111010111111001011101010111111001100100001001101001011001010111101100111000101111101011000000000100101100010101011110110011111100011000000110101000111110110010101011111010001110111011011001011111100101111010000110100011111001001110101101110101101001001101000111010011010001111111101110111111011110010101100000010010100011000101001111011100011001100001111110110000111000100000100101100011110011111111101010001111100010011111010100011001100010110110001110101100000111100101010101111101010100011111011000000100100111101101011010010110110001110101011110011110000100101110010001000011111101101110110100011010111010110000000011101100001010000110100110000000100101100010101010111110110100110111011101001000000001111011001000101101100000101001110111100100100111001001010010111110101011011111000001001000100011010110101010001101111101110111110110000111000101010111100111101111101010110101111000110010001010000111010010011101111101011001001011000000100101100010101101100111011100011000000111010000101011111110100110110001010110100101011110111011110001100100010100001110100011110110010011101011011101011010010110110001110001111100001101111111000110001110100001001110011011001011000001111001101001011101111000000110111111000110000010010110001101001110111111101101010011101111111011010100011011111011101110001100011111100010111111111100001010101111101100001111110010111110010011101011011101011010010110110001111010011101010011010111001111111110101111001011101011100001111101001101110000111010001111001010101111101000001001000111010110110001110101010111110111100111111111010100010111110100110000011111010011011101001101110111010011100101110101110000001001000111110101101011100101110101110101000011010001111110001101010110011110001101010110010101100000111100110100011011111100111000111001110110110000001001011000101011011000111010101011111010001011111010011000001011111010011000101010100100010100001000011001110010010100101100100111010110111010110101110001100100010101000011100110001011011000111010101011111010001001001101101110111001111111110101111001011101011100000010010110001111001111110010010010000111010001111011111011101011001101010110110001111111100111001111001010111100111100101011111100110011001001110101101110101101010100001010111111111100101110001010011100011000111010100100111011000010001111011001101001010110111110010101011011111001000001001011000111111000110111100110000100010110111011100101010111101101111111100011000000111110001100100010100001001111010101010100111110111101100100111010110111010110101000010111110111100001001011100100111111000110100000110001111100010101010100111001111010000111101001110001011111100001000000100100011111100111111111010100011111000100111111010000100001100010011100011011010100011111011001010101111101010001100100100000010010001111101011010000111011110110011010100111010101010001100100101110001100000011010101011111011000010110011001100000100100000101100000010010110001000110111000110101010011011101110100101001101111101101011100101110101110000111011111001001001111101110101101010001110111101011111110010011101011011101011010101001110110100111001011110111001110001011001000111110001100011111100011000101100111111000110010001000011110110011010000001001011000101010001010110011000011001100110110011010011110011110100111000110000001101011101110110110110000100110110001101000110110011001100100111010110111010110100100111111111100001011000000010011110100001000011000101010100100011100011001000101010000100001100111110110000001101000000100101100010101001111110011011111100111000001001010101111101000110001011101100101011110011110101001101110111010000010000100010001100100111010110111010110101111100110010011011111100010000111101111101110101100110111111010110010010110000111011101001110111000110010001000011011101101111100000100101100011111101101101001011111000100110001010101011111110101100001100111100111100101011111100110001011110100001001010110001110000111001001110101101110101101001010001101101110000011111000101011111101100000011011001011111101111110100010010111011111100000000101111111000000001111011000000100101100010001110111101100110101001110101010101000110011000001100010000011111000110010001010000100110110001100010010111001001111100100111010110111010110100101101100011101010111111001100010101111001111001010001100110000011110110011010010011011101011011000011011111111111000001001011000101011011000111010111111011111110000000010111111010101011111010001111100010001010000001100100110101010110001101011100100111010110111010110100101011000110101010101011111010100110110100111001001101101001110100001100000110111100101011110110011111111000100000100110000001001011000110100001001011011001101000011110110000010111111110000101001111101000110101100000111100111111000101010000101000011001111100110111001001110101101110101101011100011001000101010000111001100111000111110100011010101011111010001110000111110011110010111010111000011111111100110000000010010110001100000000101111110101010111110101000101001100001010100111101101110010011010110011001010110110001110101111001001010011001001110101101
解码就不展示了,和输入的一模一样。
链表哈夫曼树--编码--解码相关推荐
- 基于JavaGUI的哈夫曼树编码解码
资源下载地址:https://download.csdn.net/download/sheziqiong/85640300 资源下载地址:https://download.csdn.net/downl ...
- java哈夫曼树编码_哈夫曼树的编码实验
Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 建树,造树,编码,解码 一.哈夫曼树编码介绍 1.哈夫曼树: (1)定义:假设有n个权值{w1, w2, ..., wn},试构造一棵含有n个叶子 ...
- 赫夫曼树编码的算法及应用习题--数据结构
赫夫曼树编码的算法及应用习题 1.构造赫夫曼树的方法 1.根据给定的n个权值{w1,w2,---wn},构成n棵二叉树的集合F={T1,T2...,Tn},其中每棵二叉树中只有一个带权为Wi的根结点, ...
- 哈夫曼树的构建及哈夫曼树编码
哈夫曼树的构建: 注意:(1).首先把一组数3 5 6 8 9 12 15从小到大排列 (2).选取里面最小2个,顶点出为2个数的和 (3).新产生的顶点在与原先的数字进行比较,在里面选取2个最小的数 ...
- labview 霍夫曼树_哈夫曼树编码实验报告_信息论与编码实验2 实验报告_信息论与编码报告...
huffman编码C语言实验报告 今日推荐 180份文档 2014...4页 1下载券 安卓版100 doors 2攻略1... 3页 1下载券 <逃脱本色>doors....语文教育实习 ...
- 哈夫曼树的创建和哈夫曼树编码及解码
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string. ...
- 哈夫曼树和哈夫曼树编码
在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN) 树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如 JPEG中就应用了哈夫曼编码. 首先介绍什么 ...
- 哈夫曼树编码与译码(完整C/C++实现代码)
哈夫曼编码的设计与应用 问题需求分析 用哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种.Huffman于1952年提出一种编码方法 ...
- 哈夫曼树编码和译码c语言,C++哈夫曼树编码和译码的实现
78 /*-----------创建工作---------------------------*/ 79 int s1,s2; 80 for (int i = n + 1; i < ...
- 利用哈夫曼树编码与译码
#include<iostream> #include<string.h> #include<stdlib.h> using namespace std;typed ...
最新文章
- juery mobile select下来菜单选项提交form问题
- grails springboot_groovy 使用spring boot
- PLSQL DEVELOPER 使用的一些技巧【转】
- 微服务秒杀项目整合网关+feign+redis分离热点商品分别下单示例
- DIV中文字不换行解决办法
- Web笔记-session盗用安全问题(Spring Boot获取所有session及提高安全性)
- (转)Cesium教程系列汇总
- 课程《设计模式之美》笔记之关于java四大特性
- OpenCV-Python教程(7、Laplacian算子)
- Python Des加密与解密实现软件注册码、机器码
- 电脑怎么分区硬盘分区方法
- 在埋头写程序学技术的同时,有没有想到你们的老板和上司在搞什么?
- Android自定义SwitchButton左右滑动开关按钮控件
- 腾讯程序员与医生相恋,却被女方父母拆散,你们不能在一起
- linux下exec用法,linux下exec系列(一)
- 远程ubuntu桌面_如何在Ubuntu上设置远程桌面
- 爬虫爬取二次元网站美女图片
- 【深度学习】一个用于styleGAN图像处理的编码器
- suspend(挂起)和resume(继续执行)线程
- 50个经典的增长黑客策略高效实现增长
热门文章
- 电机与拖动matlab仿真,Matlab仿真软件在电机与拖动中的应用
- Python分析与处理---利用Python进行学生成绩分析
- 苹果MAC系统读写NTFS格式u盘硬盘方法
- Redis源码分析01——基本数据结构
- Qt QLabel文本框的使用
- vue + pdf.js实现浏览器查看pdf文件
- 19.丑数(UVa136)
- ios睡眠分析 卧床 睡眠_苹果ios14睡眠记录功能 让用户清楚的了解自己的睡眠
- 小程序tabBar设置
- 当BIM遇上GIS-无人机倾斜摄影三维建模(ContextCapture) 建设智慧城市方法详解