编程练习——huffman编码
2008-10-25 08:56
162 查看
这个类的名字叫huffman Tree,但是不仅仅是生成huffman Tree,因为Huffman树的生成要使用优先队列,也就是堆。stl中其实有这个的实现。但是我机器里的vs2005这个堆的使用有点小bug(估计是stl中使用的就是数组存储,而且数组一旦固定大小,就再也无法改变,其实这样实现失去了堆的某些特性。所以我还是自己实现了一下。顺便练习下。)。刚开始的时候就采用int作为编码的存储单元。后来发现huffman是可变长编码。所以使用int作为编码单元就失去了huffman的特性。于是寻找bit数组。找到了bitset这个stl类,却发现这个是不可变的。无语。只得自己实现一个可变大小的bit vector。然后近乎重写了这个Huffman的编码和解码。不过也不是很难。在这之间又陆陆续续的发现了一系列的bug和编译错误。对以后的编程大有启发。
/* created by chico chen
* date 2008/10/25
*/
#ifndef _HUFFMAN_TREE_
#define _HUFFMAN_TREE_
#include "Heap.h"
#include "TreeNode.h"
#include "BinaryTree.h"
#include <map>
#include "../../ArithmeticTest/ArithmeticTest/BITVector.h"
using namespace std;
// this class is used for the combin function in huffmanTree class.
class IntCombin
{
public:
static int Add(int i, int j)
{
return i+j;
}
};
// this class for compare tree node
template<class T>
class TreeNodeCompare
{
public:
static bool Up(TreeNode<T>* d1, TreeNode<T>* d2)
{
return Lt(d1->getData(),d2->getData());
}
static bool Eq(T& d1, T& d2)
{
if(d1 == d2)
return true;
return false;
}
static bool Gt(T& d1, T& d2)
{
if(d1 > d2)
return true;
return false;
}
static bool Lt(T& d1, T& d2)
{
if(d1 < d2)
return true;
return false;
}
};
// this class is for storing huffman code.
// bits and the length of bits
class HuffmanCode
{
public:
BITVector bits;
int len;
HuffmanCode()
{
len = 0;
}
HuffmanCode(const HuffmanCode & codes):bits(codes.bits)
{
len = codes.len;
}
const HuffmanCode& operator=(const HuffmanCode & codes)
{
if(this != &codes)
{
this->len = codes.len;
this->bits = codes.bits;
}
return * this;
}
~HuffmanCode()
{
}
};
template<class T, class Cmp, class Combin>
class HuffmanTree:public BinaryTree<T>
{
private:
// store the data, and sort it, then for building a huffman tree
Heap<TreeNode<T>* ,Cmp> huffmanQueue;
const unsigned int mask;
// the max number can be shifted, if it is unsigned int then it will be 32.
const int maxShiftNum;
TreeNode<T>* initTree()
// init the huffman tree
{
TreeNode<T> * combinNode = NULL;
T tempData;
while(!this->huffmanQueue.IsEmpty())
{
// fetch two small data and generate a large data
TreeNode<T> * node1 = this->huffmanQueue.Top();
combinNode = node1;
this->huffmanQueue.RemoveTop();
if(!this->huffmanQueue.IsEmpty())
{
TreeNode<T> * node2 = this->huffmanQueue.Top();
this->huffmanQueue.RemoveTop();
tempData = Combin::Add(node1->getData(),node2->getData());
if(Cmp::Lt(node1->getData(),node2->getData()))
{
// here is comparing the data1 of node1 and the data2 of node2
// Cmp:Lt means '<' and Cmp:Gt means '>'
combinNode = new TreeNode<T>(tempData,node1,node2);
}
else
{
combinNode = new TreeNode<T>(tempData,node2,node1);
}
this->huffmanQueue.Insert(combinNode);
}
else
{
break;
}
}
return combinNode;
}
// the final huffman code
map<T,HuffmanCode> huffmanTable;
void SelfEncode(TreeNode<T>* subRoot,unsigned int bitcode,int num,map<T,HuffmanCode > &ht)
// encoding the data from a huffman tree.
// The left branch is 0, and the right branch is 1
{
if(subRoot != NULL)
{
if(subRoot->left == NULL && subRoot->right==NULL)
{
HuffmanCode hc;
hc.bits.SetInt(bitcode,0,maxShiftNum-num);
hc.len = maxShiftNum-num;
ht[subRoot->getData()] = hc;
return;
}
else
{
if(num<=0)
{
throw "the huffman is too deep!";
}
SelfEncode(subRoot->left,bitcode,num-1,ht);
bitcode = bitcode | (0x80000000 >> (maxShiftNum-num));
SelfEncode(subRoot->right,bitcode,num-1,ht);
}
}
}
void DecodeFromTree(TreeNode<T>* subRoot,BITVector& bits,int index,const int& len,vector<T>& decode)
// decoding the code. use the code to search the data from the huffmanTree.
// here you can create you own map<code,data> deHuffmanTable.
// but I can not analyze the space the table will use,
// so I find the data by searching huffman tree
{
if(index == len)
{
if(subRoot->getLeft()==NULL && subRoot->getRight() == NULL)
{
decode.push_back(subRoot->getData());
return;
}
throw "code length is not match the bits length. Huffman Tree construct error.";
}
if(subRoot == NULL)
{
throw "decode error!";
}
else if(subRoot->getLeft() == NULL && subRoot->getRight() == NULL)
{
decode.push_back(subRoot->getData());
return DecodeFromTree(this->root,bits,index,len,decode);
}
if(bits.Get(index) == 0)
{
return DecodeFromTree(subRoot->getLeft(),bits,index+1,len,decode);
}
else if(bits.Get(index)==1)
{
return DecodeFromTree(subRoot->getRight(),bits,index+1,len,decode);
}
else
{
throw "code error!";
}
}
unsigned int FindCodeFromTable(T& data)
// find the data code from huffman table
// may be not efficient.
{
return this->huffmanTable[data];
}
public:
HuffmanTree(T t[], int n):
BinaryTree<T>(),mask(0x80000000),maxShiftNum(sizeof(unsigned int)*8)
// the array t type is T, and the number is n
{
if(n == 0)
return;
TreeNode<T>* node;
for(int i = 0; i < n; i++)
{
node = new TreeNode<T>(t[i]);
this->huffmanQueue.Insert(node);
}
this->root = initTree();
}
~HuffmanTree()
{
// destroy
}
void SelfEncode()
// convert the huffmanTree into huffmanTable
// unsigned int code is 32 bits, so the huffman tree has only less than 33 layer.
{
string s="";
SelfEncode(this->root,0,maxShiftNum,this->huffmanTable);
}
void Decode(HuffmanCode& huffmanCode,vector<T>& decode)
// use bit to find the data node.
{
return DecodeFromTree(this->root,huffmanCode.bits,0,huffmanCode.len,decode);
}
HuffmanCode Encode(T info[], int n)
// n is size
{
HuffmanCode hc;
for(int i = 0; i < n; i++)
{
hc.bits.SetBitVector(((HuffmanCode)this->huffmanTable[info[i]]).bits,hc.len,((HuffmanCode)this->huffmanTable[info[i]]).len);
hc.len +=((HuffmanCode)this->huffmanTable[info[i]]).len;
}
return hc;
}
void PrintHuffmanTable()
// print the huffman table
// print the pair data<->code
{
int len = this->huffmanTable.size();
cout << "i/tdata/tcode/n";
int count = 0;
map<T,HuffmanCode>::iterator i= this->huffmanTable.begin();
for(; i != this->huffmanTable.end(); i++)
{
cout << count++<<"/t"<<(*i).first<<"/t";
(*i).second.bits.PrintfZeroOne(0,(*i).second.len);
cout<<endl;
}
}
};
#endif
这个类设计方面还有些不足之处。比如encode方法
测试一下:
int a[10] = {12,224,33,32,1,91,35,34,36,291};
HuffmanTree<int,TreeNodeCompare<int>,IntCombin> ht(a,10);
ht.SelfEncode();
ht.PrintHuffmanTable();
ht.printTree();
cout << endl;
int info[] = {33,34,33};
HuffmanCode hc = ht.Encode(info,3);
hc.bits.PrintfZeroOne(0,hc.len);
vector<int> code;
ht.Decode(hc,code);
for(int i = 0; i != code.size();i++)
{
cout<<code[i]<<endl;
}
return 0;
/* created by chico chen
* date 2008/10/25
*/
#ifndef _HUFFMAN_TREE_
#define _HUFFMAN_TREE_
#include "Heap.h"
#include "TreeNode.h"
#include "BinaryTree.h"
#include <map>
#include "../../ArithmeticTest/ArithmeticTest/BITVector.h"
using namespace std;
// this class is used for the combin function in huffmanTree class.
class IntCombin
{
public:
static int Add(int i, int j)
{
return i+j;
}
};
// this class for compare tree node
template<class T>
class TreeNodeCompare
{
public:
static bool Up(TreeNode<T>* d1, TreeNode<T>* d2)
{
return Lt(d1->getData(),d2->getData());
}
static bool Eq(T& d1, T& d2)
{
if(d1 == d2)
return true;
return false;
}
static bool Gt(T& d1, T& d2)
{
if(d1 > d2)
return true;
return false;
}
static bool Lt(T& d1, T& d2)
{
if(d1 < d2)
return true;
return false;
}
};
// this class is for storing huffman code.
// bits and the length of bits
class HuffmanCode
{
public:
BITVector bits;
int len;
HuffmanCode()
{
len = 0;
}
HuffmanCode(const HuffmanCode & codes):bits(codes.bits)
{
len = codes.len;
}
const HuffmanCode& operator=(const HuffmanCode & codes)
{
if(this != &codes)
{
this->len = codes.len;
this->bits = codes.bits;
}
return * this;
}
~HuffmanCode()
{
}
};
template<class T, class Cmp, class Combin>
class HuffmanTree:public BinaryTree<T>
{
private:
// store the data, and sort it, then for building a huffman tree
Heap<TreeNode<T>* ,Cmp> huffmanQueue;
const unsigned int mask;
// the max number can be shifted, if it is unsigned int then it will be 32.
const int maxShiftNum;
TreeNode<T>* initTree()
// init the huffman tree
{
TreeNode<T> * combinNode = NULL;
T tempData;
while(!this->huffmanQueue.IsEmpty())
{
// fetch two small data and generate a large data
TreeNode<T> * node1 = this->huffmanQueue.Top();
combinNode = node1;
this->huffmanQueue.RemoveTop();
if(!this->huffmanQueue.IsEmpty())
{
TreeNode<T> * node2 = this->huffmanQueue.Top();
this->huffmanQueue.RemoveTop();
tempData = Combin::Add(node1->getData(),node2->getData());
if(Cmp::Lt(node1->getData(),node2->getData()))
{
// here is comparing the data1 of node1 and the data2 of node2
// Cmp:Lt means '<' and Cmp:Gt means '>'
combinNode = new TreeNode<T>(tempData,node1,node2);
}
else
{
combinNode = new TreeNode<T>(tempData,node2,node1);
}
this->huffmanQueue.Insert(combinNode);
}
else
{
break;
}
}
return combinNode;
}
// the final huffman code
map<T,HuffmanCode> huffmanTable;
void SelfEncode(TreeNode<T>* subRoot,unsigned int bitcode,int num,map<T,HuffmanCode > &ht)
// encoding the data from a huffman tree.
// The left branch is 0, and the right branch is 1
{
if(subRoot != NULL)
{
if(subRoot->left == NULL && subRoot->right==NULL)
{
HuffmanCode hc;
hc.bits.SetInt(bitcode,0,maxShiftNum-num);
hc.len = maxShiftNum-num;
ht[subRoot->getData()] = hc;
return;
}
else
{
if(num<=0)
{
throw "the huffman is too deep!";
}
SelfEncode(subRoot->left,bitcode,num-1,ht);
bitcode = bitcode | (0x80000000 >> (maxShiftNum-num));
SelfEncode(subRoot->right,bitcode,num-1,ht);
}
}
}
void DecodeFromTree(TreeNode<T>* subRoot,BITVector& bits,int index,const int& len,vector<T>& decode)
// decoding the code. use the code to search the data from the huffmanTree.
// here you can create you own map<code,data> deHuffmanTable.
// but I can not analyze the space the table will use,
// so I find the data by searching huffman tree
{
if(index == len)
{
if(subRoot->getLeft()==NULL && subRoot->getRight() == NULL)
{
decode.push_back(subRoot->getData());
return;
}
throw "code length is not match the bits length. Huffman Tree construct error.";
}
if(subRoot == NULL)
{
throw "decode error!";
}
else if(subRoot->getLeft() == NULL && subRoot->getRight() == NULL)
{
decode.push_back(subRoot->getData());
return DecodeFromTree(this->root,bits,index,len,decode);
}
if(bits.Get(index) == 0)
{
return DecodeFromTree(subRoot->getLeft(),bits,index+1,len,decode);
}
else if(bits.Get(index)==1)
{
return DecodeFromTree(subRoot->getRight(),bits,index+1,len,decode);
}
else
{
throw "code error!";
}
}
unsigned int FindCodeFromTable(T& data)
// find the data code from huffman table
// may be not efficient.
{
return this->huffmanTable[data];
}
public:
HuffmanTree(T t[], int n):
BinaryTree<T>(),mask(0x80000000),maxShiftNum(sizeof(unsigned int)*8)
// the array t type is T, and the number is n
{
if(n == 0)
return;
TreeNode<T>* node;
for(int i = 0; i < n; i++)
{
node = new TreeNode<T>(t[i]);
this->huffmanQueue.Insert(node);
}
this->root = initTree();
}
~HuffmanTree()
{
// destroy
}
void SelfEncode()
// convert the huffmanTree into huffmanTable
// unsigned int code is 32 bits, so the huffman tree has only less than 33 layer.
{
string s="";
SelfEncode(this->root,0,maxShiftNum,this->huffmanTable);
}
void Decode(HuffmanCode& huffmanCode,vector<T>& decode)
// use bit to find the data node.
{
return DecodeFromTree(this->root,huffmanCode.bits,0,huffmanCode.len,decode);
}
HuffmanCode Encode(T info[], int n)
// n is size
{
HuffmanCode hc;
for(int i = 0; i < n; i++)
{
hc.bits.SetBitVector(((HuffmanCode)this->huffmanTable[info[i]]).bits,hc.len,((HuffmanCode)this->huffmanTable[info[i]]).len);
hc.len +=((HuffmanCode)this->huffmanTable[info[i]]).len;
}
return hc;
}
void PrintHuffmanTable()
// print the huffman table
// print the pair data<->code
{
int len = this->huffmanTable.size();
cout << "i/tdata/tcode/n";
int count = 0;
map<T,HuffmanCode>::iterator i= this->huffmanTable.begin();
for(; i != this->huffmanTable.end(); i++)
{
cout << count++<<"/t"<<(*i).first<<"/t";
(*i).second.bits.PrintfZeroOne(0,(*i).second.len);
cout<<endl;
}
}
};
#endif
这个类设计方面还有些不足之处。比如encode方法
测试一下:
int a[10] = {12,224,33,32,1,91,35,34,36,291};
HuffmanTree<int,TreeNodeCompare<int>,IntCombin> ht(a,10);
ht.SelfEncode();
ht.PrintHuffmanTable();
ht.printTree();
cout << endl;
int info[] = {33,34,33};
HuffmanCode hc = ht.Encode(info,3);
hc.bits.PrintfZeroOne(0,hc.len);
vector<int> code;
ht.Decode(hc,code);
for(int i = 0; i != code.size();i++)
{
cout<<code[i]<<endl;
}
return 0;
相关文章推荐
- (一三五)第十二章编程练习
- C和指针第四章编程练习
- 面向对象的编程练习
- 牛客网编程练习之网易2017校招题:数字翻转
- 剑指Offer编程练习014——链表中倒数第k个结点
- GEEK编程练习— —寻找单个数
- 牛客网编程练习之PAT乙级(Basic Level):1041 说反话
- 牛客网编程练习之编程马拉松:程序员日
- C语言编程练习(day of the year)
- 在线编程笔试练习1(京东)
- C语言编程练习(通过指针调换输入数字)
- 在线编程笔试练习2(京东)
- hihocoder编程练习:#1082 : 然而沼跃鱼早就看穿了一切
- 编程练习:赛车跑圈(走楼梯)问题
- 编程速度培养-快捷键练习1 IE快捷键
- C语言:指针的三道编程练习
- 编程练习(第十三周)
- 5个Shell脚本编程入门练习例子
- 编程练习:合并两个数组(包括三种快排程序)
- 第十一章编程练习(6)