哈夫曼编码译码系统

实验目的

  1. 完成Huffman Tree 编码、译码系统的设计
  2. 自行设计测试数据
  3. 自行找一段本文,统计本文中每一个字符出现的频率。
  4. 理解建立Huffman Tree(编码)过程

实验设备与环境

Dev-C++ 5.11

实验过程及结果分析

1. 构造哈夫曼树

设已知n个结点的权值,根据这些权值构成森林F,森林中的每棵二叉树有且只有一个根结点,权值与之相对应,左右子树为空。
A. 在森林F中选取两颗二叉树根结点的权值最小、次小的树,把它们作为左右子树合成一棵新树,新树权值为左右子树权值的和。
B. 不断重复上述步骤,直到所有树合成一棵树为止。
C. 在合成新树的过程中,每次需要在森林中选取权值最小的两个根结点。因此,引入函数SelectSmall(least,less,i),在hufftree的前i个向量范围中,找到最小的根结点下标least和次小的根结点下标less。
D. 实现细节中,应注意为树中所有结点预留向量空间,初始化Hufftree,注意只有一个根结点。一共需要执行n - 1次合并根结点。

2. SelectSmall函数

A. 函数SelectSmall在于搜索当前森林中权值最小和次小的两个结点,并将下标分别记录到least、less中。
B. 每一次搜索前先找到当前下标值最小的的单结点(parent域为-1),将下标记录到least中。
C. 寻找最小least下标的过程,可以将将当前least下标的结点的权值与剩下的所有单结点权值作比较,每一次将更小的权值的结点下标赋值给least。
D. 寻找次小less下标的过程同寻找least下标的过程类似,需要在查找过程中加入判断条件,即下标值不等于least,这样查找的结果即为次小下标。

3. 哈夫曼编码

A. 每一个符号的Huffman编码是一个0/1串,因此采用串位储存的方式。本函数采用整数向量存储第i个符号的Huffman编码,并返回该编码串。
B. 第i个符号储存在Huffman树中第i个叶子结点中。为计算它的编码向量,需要向根结点追溯它的结点路径。在路径中左孩子关系记作编码0,右孩子关系记作编码1。由于编码是从叶子结点向根结点逐个读出,次序恰好逆置,因此每个编码数字应该添加在编码向量的首部,这样才能得到编码向量的正确次序。

4. 哈夫曼译码

A. 当已知编码文件,需要还原信息符号串时,需要依据编码时的原Huffman树进行译码。函数Decode(vector &source)中参数source是编码文件(0/1向量),返回值是原信息符号串。
B. 每个符号的译码工作都是从Huffman树的根向叶子结点的下行过程。逢0向左孩子下行,逢1向右孩子下行。当下行遇到叶子结点时,该叶子中的data域的值就是译码符号。
C. 每找到一个叶子结点并取其data域的值,再将当前结点再次置为根结点,直到找到最后一个叶子结点的data值。

5. 实验结果

原字符串以“good good study”为例子,实验结果如下:

01234567891011121314
datagodstuy
weight0.130.270.20.130.070.070.070.070.140.140.260.280.460.551.0
parent101312108899111112131414-1
lchild-1-1-1-1-1-1-1-146082112
rchild-1-1-1-1-1-1-1-15739101113

在这里插入图片描述

实验代码

main.cpp

#include <iostream>
#include "Huffman.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	char ss[]="good good study";
	//char ss[]="BACECDC";
	/*char data[] = {'w','h','e','r',' ','t','i','s','a','w','l',',','y'};
	double weight[] = {0.03,0.08,0.17,0.08,0.19,0.06,0.08,0.06,0.08,0.06,0.06,0.03,0.03};
	*/
	char data[] = {'g','o','d',' ','s','t','u','y'};
	double weight[] = {0.13,0.27,0.20,0.13,0.07,0.07,0.07,0.07};
	int len=strlen(data);
	HuffmanNode a[len] ;
	
	for(int i=0;i<len;i++)
	{
		a[i].data = data[i];
		a[i].weight = weight[i]; 
		a[i].lchild = a[i].rchild = -1;
		a[i].parent = -1;
	}
	vector<HuffmanNode> t(a,a+len);
	HuffmanTree hu(t);
	//print(hu.hufftree,2*len-1);
	cout<<"密码表:"<<endl;
	for(int j=0;j<len-1;j++)
	{
		vector<int>code = hu.GetCode(j);
		cout<<hu.hufftree[j].data<<":";
		for(int i=0;i<code.size();i++)
			cout<<code[i];
		cout<<endl;
	}
	cout<<"---------------"<<endl;
	cout<<"原字符串为:"<<endl<<ss<<endl;
	cout<<"---------------"<<endl;
	cout<<"编码后:"<<endl;
	vector<int>encode;
	for(int i=0;i<strlen(ss);i++)
	{
		int j;
		for(j=0;j<hu.hufftree.size();j++)
			if(ss[i] == hu.hufftree[j].data)
				break;
		vector<int>code = hu.GetCode(j);
		encode.insert(encode.end(),code.begin(),code.end());
	}
	for(int i=0;i<encode.size();i++)
		cout<<encode[i];
	cout<<endl<<"---------------"<<endl;
	cout<<"译码后:"<<endl<<hu.Decode(encode);
	return 0;
}

Huffman.h

#include<bits/stdc++.h> 
using namespace std;

struct HuffmanNode 
{ 
    char data;	            // 待编码的符号
    double weight;	            // 符号出现的频率 
    int parent, lchild, rchild;       // 父结点、左, 右孩子结点的位置
};

class HuffmanTree
{ 
    //vector<HuffmanNode> hufftree;  // 树中所有结点的存储空间
    int n;			           // 叶子结点数
    void SelectSmall(int &least,int &less,int i);
public:
	vector<HuffmanNode> hufftree;
    HuffmanTree(vector<HuffmanNode> &leafs);
    vector<int> GetCode( int i );
    string Decode(vector<int> &source);
//    string Encode()
};

HuffmanTree::HuffmanTree(vector<HuffmanNode> &leafs)
{
	n = leafs.size();
	hufftree.resize(2*n-1);
	for(int i=0;i<n;i++)
	{
		hufftree[i].data = leafs[i].data;
		hufftree[i].weight = leafs[i].weight;
		hufftree[i].parent = hufftree[i].lchild 
						   = hufftree[i].rchild 
						   = -1;
	}
	for(int i=n;i<2*n-1;i++)
	{
		int least,less;
		SelectSmall(least,less,i);
		hufftree[least].parent = hufftree[less].parent = i;
		hufftree[i].parent = -1;
		hufftree[i].lchild = least;
		hufftree[i].rchild = less;
		hufftree[i].weight = hufftree[least].weight 
							+ hufftree[less].weight;
	}
}
//--------------------------
void HuffmanTree::SelectSmall(int &least,int &less,int i)
{
	for (int j = 0; j < i; j++)
        if (hufftree[j].parent == -1)
        {
            least = j;
            break;
        }
    for (int j = 0; j < i; j++)
        if (hufftree[j].parent == -1 && hufftree[least].weight > hufftree[j].weight)
            least = j;
    for (int j = 0; j < i; j++)
        if (hufftree[j].parent == -1&&j!=least)
        {
            less = j;
            break;
        }
    for (int j = 0; j < i; j++)
        if (hufftree[j].parent == -1 && hufftree[less].weight > hufftree[j].weight&&j != least)
            less = j;
}
//--------------------------
vector<int> HuffmanTree::GetCode( int i )
{
	vector<int>code;
	int p = i;
	int parent = hufftree[i].parent;
	while(parent!= -1)
	{
		if(hufftree[parent].lchild == p)
			code.insert(code.begin(),0);
		else
			code.insert(code.begin(),1);
		p = parent;
		parent = hufftree[parent].parent;
		//cout<<code[i];
	}
	return code;
 } 
//--------------------------
string HuffmanTree::Decode(vector<int> &source)
{
	string target ="";
	int root = hufftree.size() -1;
	int p = root;
	for(int i=0;i<source.size();i++)
	{
		if(source[i] == 0)
			p = hufftree[p].lchild;
		else
			p = hufftree[p].rchild;
		if(hufftree[p].lchild == -1 
			&& hufftree[p].rchild == -1)
		{
			target = target + hufftree[p].data;
			p = root;	
		}
	 }
	 return target;
}


 void print(vector<HuffmanNode> hT,int n)
 {
     cout << "index weight parent lChild rChild" << endl;
     cout << left;    // 左对齐输出 
     for (int i = 0; i < n; ++i) 
     {
        cout << setw(5) << i << " ";
        cout << setw(6) << hT[i].weight << " ";
        cout << setw(6) << hT[i].parent << " ";
        cout << setw(6) << hT[i].lchild << " ";
        cout << setw(6) << hT[i].rchild << endl;
    }
 }
  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈夫曼编码是一种基于二叉树的编码方式,可以实现无损压缩数据的功能。下面是C语言实现哈夫曼树编码和译码的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 哈夫曼树的节点结构体 typedef struct huffman_node { char data; // 数据 int freq; // 频率 struct huffman_node *left; // 左子节点 struct huffman_node *right; // 右子节点 } huffman_node_t; // 哈夫曼编码表的结构体 typedef struct huffman_table { char data; // 数据 char code[256]; // 编码 } huffman_table_t; // 构建哈夫曼树 huffman_node_t* build_huffman_tree(char* data, int* freq, int n) { huffman_node_t **nodes = (huffman_node_t**)malloc(n * sizeof(huffman_node_t*)); for (int i = 0; i < n; i++) { huffman_node_t *node = (huffman_node_t*)malloc(sizeof(huffman_node_t)); node->data = data[i]; node->freq = freq[i]; node->left = NULL; node->right = NULL; nodes[i] = node; } while (n > 1) { // 找出频率最小的两个节点 int min1 = 0, min2 = 1; if (nodes[0]->freq > nodes[1]->freq) { min1 = 1; min2 = 0; } for (int i = 2; i < n; i++) { if (nodes[i]->freq < nodes[min1]->freq) { min2 = min1; min1 = i; } else if (nodes[i]->freq < nodes[min2]->freq) { min2 = i; } } // 合并频率最小的两个节点 huffman_node_t *parent = (huffman_node_t*)malloc(sizeof(huffman_node_t)); parent->data = 0; parent->freq = nodes[min1]->freq + nodes[min2]->freq; parent->left = nodes[min1]; parent->right = nodes[min2]; if (min1 < min2) { nodes[min1] = parent; nodes[min2] = nodes[n - 1]; } else { nodes[min2] = parent; nodes[min1] = nodes[n - 1]; } n--; } return nodes[0]; } // 生成哈夫曼编码表 void generate_huffman_table(huffman_node_t *root, char* code, int depth, huffman_table_t* table) { if (root->left == NULL && root->right == NULL) { table[root->data].data = root->data; strcpy(table[root->data].code, code); return; } code[depth] = '0'; generate_huffman_table(root->left, code, depth + 1, table); code[depth] = '1'; generate_huffman_table(root->right, code, depth + 1, table); } // 哈夫曼编码 char* huffman_encode(char* data, huffman_table_t* table) { int n = strlen(data); char* code = (char*)malloc(n * 256 * sizeof(char)); int k = 0; for (int i = 0; i < n; i++) { strcat(code, table[data[i]].code); } return code; } // 哈夫曼解码 char* huffman_decode(char* code, huffman_node_t* root) { int n = strlen(code); char* data = (char*)malloc(n * sizeof(char)); huffman_node_t* p = root; int k = 0; for (int i = 0; i < n; i++) { if (code[i] == '0') { p = p->left; } else { p = p->right; } if (p->left == NULL && p->right == NULL) { data[k++] = p->data; p = root; } } return data; } int main() { char data[] = "ABCDAAAABBBCDEFG"; int freq[] = {3, 4, 3, 2, 2, 2, 1, 2, 1, 1}; int n = strlen(data); // 构建哈夫曼树 huffman_node_t* root = build_huffman_tree(data, freq, n); // 生成哈夫曼编码表 char code[256]; memset(code, 0, sizeof(code)); huffman_table_t table[256]; generate_huffman_table(root, code, 0, table); // 哈夫曼编码 char* encoded = huffman_encode(data, table); // 哈夫曼解码 char* decoded = huffman_decode(encoded, root); printf("原始数据:%s\n", data); printf("哈夫曼编码:%s\n", encoded); printf("哈夫曼解码:%s\n", decoded); return 0; } ``` 以上代码实现了哈夫曼树的构建、哈夫曼编码表的生成、哈夫曼编码和哈夫曼解码的功能。在实际应用中,需要根据具体的需求对代码进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值