【数据结构与算法】哈夫曼数与哈夫曼编码

来源:互联网 发布:画像素软件 编辑:程序博客网 时间:2024/06/14 08:42

这个代码实现了构造哈夫曼数及实现对输入的字符编码。

//file.h

/*
文件类


处理文件的打开,读取,写入功能


*/


#include<iostream>
#include <fstream>
#include <string>
#include <vector>


using namespace std;


class File
{


public:


char ch = '0';
vector<char> m_file;
string m_fileName = "";




File()
{
m_fileName = "test.txt";
m_file.resize(0);
}


void SetFileName(string fileName)
{
m_fileName = fileName;
}


vector<char>& Open()
{
ifstream in(m_fileName);//构造文件


if (!in.is_open())
{
cout << "Error opening file";
exit(1);
}


while (in>>ch)//从文件读入内存
{
m_file.push_back(ch);
}


return m_file;
}


void WriteOutFile(string outFileName, vector<char> code)
{
ofstream out(outFileName);//构造写出的文件


if (out.is_open())
{
vector<char>::iterator iter = code.begin();


while (iter != code.end())
{
out << (*iter);
iter++;
}
}
}


void PrintFile()
{
copy(m_file.begin(), m_file.end(), ostream_iterator<char>(cout));
cout << endl;
}
};


//huffman.h

/*


哈夫曼树类
定义哈夫曼树的ADT
定义了哈夫曼编码的ADT


实现哈夫曼数的创建
实现创建哈夫曼编码表
实现对数据的编码
实现对数据的解码
实现对开辟资源的释放


*/




#include<iostream>
#include <string.h>
#include <vector>


using namespace std;


struct HCode
{
char data;
char code[1000];
};


//Huffman树节点
struct HNode
{
int weight;  //节点权值
int parent;  //双亲指针
int lchild;  //左孩子指针
int rchild;  //右孩子指针
bool flag;   //标记是否使用过这个节点
};


class Huffman
{
public:
HNode*HTree;  //哈夫曼树
HCode*HCodeTable; //哈弗曼编码表
void CreateHTree(int *weight, int n);//创建哈夫曼树
void CreateTable(char *b, int n);//创建编码表
string Encoding(vector<char> data, int n);//编码
//void Decoding(char*s, char*d, int n);//解码
void Decoding(string strCode, int n);//解码
void DestroyTree(int n);//析构
};






void Huffman::DestroyTree(int n)
{
for (int i = 0; i < 2 * n - 3; i++)//析构哈夫曼树
{
HNode*p = HTree;
HTree++;
delete p;
}
for (int j = 0; j < n - 5; j++)//析构编码表
{
HCode*q = HCodeTable;
HCodeTable++;
delete q;
}
}






void Huffman::CreateTable(char *b, int n)
{
HCodeTable = new HCode[n];
for (int i = 0; i < n; i++)
{
HCodeTable[i].data = b[i];//生成编码表
int child = i;
int parent = HTree[i].parent;
int k = 0;
while (parent != -1)
{
if (child == HTree[parent].lchild)
{
HCodeTable[i].code[k] = '0';//左孩子标‘0’
}

else
{
HCodeTable[i].code[k] = '1';//右孩子标‘1’
}
k++;
child = parent;
parent = HTree[child].parent;
}
HCodeTable[i].code[k] = '\0';
char*b = new char[k];
for (int j = 0; j < k; j++)
{
b[j] = HCodeTable[i].code[k - 1 - j];
}
for (int t = 0; t < k; t++)
{
HCodeTable[i].code[t] = b[t];
}
}
}






string Huffman::Encoding(vector<char> data, int n)
{
vector<char>::iterator iter = data.begin();
string outFile = "";//保存用于返回的字符串




while (iter != data.end())
{
for (int i = 0; i < n; i++)
{
if (*iter == HCodeTable[i].data)
{
cout << HCodeTable[i].code;
outFile += (HCodeTable[i].code);
}
}
iter++;
}
cout << endl;
return outFile;
}


void Huffman::Decoding(string strCode, int n)//strCode为编码的01串
{
int  i = 0;
int parent = 2*n - 1 - 1;//根节点在HTree中的下标


while ( '\0' != strCode[i])
{
parent = 2 * n - 1 - 1;
while (-1 != HTree[parent].lchild)
{
if (strCode[i] == '0')
{
parent = HTree[parent].lchild;
}
else
{
parent = HTree[parent].rchild;
}
i++;
}
cout << HCodeTable[parent].data;
}


}






void Huffman::CreateHTree(int *weight, int n)
{
HTree = new HNode[2 * n - 1];//计算需要的节点数


int i = 0;
int j = 0;
int min = 10000;//标定一个基准值,用来寻找最小的节点
int index_x = 0;//第一个最小节点的下标位置
int index_y = 0;//第二个最小节点的小标位置


for (i = 0; i < 2 * n - 1; i++)
{
HTree[i].flag = false;//标记所有的节点为没有使用过
}


for (i = 0; i < n; i++)
{
HTree[i].weight = weight[i];
HTree[i].lchild = -1;
HTree[i].rchild = -1;
HTree[i].parent = -1;
}


//根据HuffmanTree的定义构建
for (i = n; i < 2 * n - 1; i++)
{
min = 10000;


for (j = 0; j < i; j++)
{
if (true == HTree[j].flag)//这个节点使用过,直接跳过
{
continue;
}


if (HTree[j].weight < min)
{
min = HTree[j].weight;
index_x = j;
}
}
HTree[index_x].flag = true;


//找第二个较小的节点的方法同上
min = 10000;
for (j = 0; j < i; j++)
{
if (true == HTree[j].flag)
{
continue;
}


if (HTree[j].weight < min)
{
min = HTree[j].weight;
index_y = j;
}
}
HTree[index_y].flag = true;


//构造找到的两个较小的节点的父节点
HTree[index_x].parent = HTree[index_y].parent = i;
HTree[i].lchild = index_x;
HTree[i].rchild = index_y;
HTree[i].weight = HTree[index_x].weight + HTree[index_y].weight;
HTree[i].parent = -1;
}
}


//LinkList.h

/*


链表类
实现了循环链表的ADT


实现了循环链表的创建
实现统计链表中唯一节点的个数


*/




#include<iostream>
#include <string.h>
#include <vector>


using namespace std;


//链表节点
struct Node
{
char data; //节点数据
int weight; //节点权值
Node *next; //节点指针
};




class Linklist
{
public:
//构建环形链表,方便统计重复节点
Linklist()
{
rear = new Node;
rear = rear->next;
}
//void Construct(char *str);//构造链表
void Construct(vector<char>& source);
int GetCount();//获取不重复元素的个数
Node*rear;


};


//构建了一个循环链表
//每个节点都是唯一的元素,统计元素的权值




void Linklist::Construct(vector<char>& source)
{
rear = new Node;
rear->next = rear;//形成环形链表


Node *p = NULL;
Node* q = NULL;
Node* r = NULL;


int size = source.size();


for (int i = 0; i < size;i++)
{
if (rear->next == rear)
{
p = new Node;
p->data = source[0];
p->weight = 1;
p->next = rear->next;
rear->next = p;
rear = p;
}
else
{
q = rear->next->next;
while (q!=rear->next)
{
if (q->data == source[i])//这个点以前出现过,权值增加
{
q->weight++;
break;
}
else
{
q = q->next;
}
}
//当前的元素没有出现过,新创建一个节点
if (rear->next == q)
{
r = new Node;
r->data = source[i];
r->weight = 1;
r->next = rear->next;
rear ->next = r;
rear = r;
}
}
}


}




int Linklist::GetCount()
{
int n = 0;
Node*t = rear->next->next;
while (t != rear->next)
{
t = t->next;
n++;
}
return n;
}


//main.cpp



/*
fileName: huffmanTree
date: 2015.11.19
author:WalterZhao
finalAlter: 2015.11.21
s
*/




#include<iostream>
#include <string.h>
#include <windows.h>


#include"Huffman.h"
#include"Linklist.h"
#include"file.h"




using namespace std;


int main()
{
string sourceFileName = "";
vector<char> fileChar;//保存文件中的字符
string outFileCode = "";//保存要写到外部文件中的编码字符串
string decodeStr = "";//用于解码的字符串
int  i = 0;




cout << "请选择一个需要编码的文件" << endl;
cout << "可以选择的文件有:" << endl;


system("dir /b *.txt ");
cin >> sourceFileName;


File file;
file.SetFileName(sourceFileName);
fileChar =  file.Open();
file.PrintFile();


cout << "这个文件的哈夫曼编码情况:" << endl;


Linklist strLinkList;//创建保存文件字符的链表
strLinkList.Construct(fileChar);
int nPoint = strLinkList.GetCount();//得到哈夫曼树的子树个数


char* data = new char[nPoint];
int* power = new int[nPoint];
Node* p = strLinkList.rear->next->next;


//初始化哈夫曼树
for (i = 0; i < nPoint;i++)
{
data[i] = p->data;
power[i] = p->weight;
p = p->next;
}




Huffman huffTree;//定义哈夫曼树
huffTree.CreateHTree(power,nPoint);//创建哈弗曼树
huffTree.CreateTable(data, nPoint);//创建哈弗曼码表


cout << "码表:" << endl << endl;
cout << "letter" << "\t" << "Code" << "\t" << "weight" << endl << endl;




//打印编码表
for (i = 0; i < nPoint;i++)
{
cout << huffTree.HCodeTable[i].data << "\t" << huffTree.HCodeTable[i].code << "\t" << power[i] << endl;
}


cout << "文件压缩后的二进制编码为:" << endl;
//编码并输出
outFileCode = huffTree.Encoding(fileChar, nPoint);


//讲编码后源文件写入外部文件
ofstream out("codeFile.txt");
if (out.is_open())
{
out << outFileCode;
}
else
{
cout << "文件错误" << endl;
}


//解码
cout << "请输入一段0和1二进制码,用于解码" << endl;
cin >> decodeStr;


huffTree.Decoding(decodeStr, nPoint);


return 0;
}


欢迎交流

0 0