贴代码
//最小堆.h
#include
using namespace std;
class Node
{
public:
int weigh;
Node *left;
Node *right;
Node *parent;
};
typedef Node* Nodeptr;
class MinHeap
{
private:
int size=10;
int usage=0; //heap[0]为哨兵
Nodeptr* heap;
public:
MinHeap(int size,Nodeptr a[],int usage)
{
//size = 10; //测试用 用完删除!
this->size = size;
heap = new Nodeptr[size];
heap[0] = new Node;
for (int i = 1; i <= usage; i++)
{
heap[i] = a[i-1];
}
this->usage = usage;
heap[0]->weigh = -1; // 建立最小堆 设为哨兵
//调整为最小堆
for (int i = usage / 2;i>0; i--)
{
Nodeptr tem = heap[i];
int Parent, Child;
for (Parent = i; Parent * 2 <= usage; Parent = Child) //判断有没有Parent(左)儿子
{
Child = Parent * 2; //假设左儿子更小
if ((Child != usage) && (heap[Child]->weigh > heap[Child + 1]->weigh))
Child++;
if (tem->weigh <= heap[Child]->weigh)
break;
else
heap[Parent] = heap[Child];
}
heap[Parent] = tem;
}
}
bool Add(Nodeptr e) //加入数据
{
if (IsFull())
{
cout << "+over flow" << endl;
return false;
}
else
{
usage++;
int i = usage;
for (; heap[i / 2]->weigh > e->weigh; i = i / 2)
{
heap[i] = heap[i / 2];
}
heap[i] = e;
}
return true;
}
bool Delete(Nodeptr& e) //一定要小心,建立哈夫曼树的时候如果出错,看看这里的指针拷贝有没有出错
{
if (Isempty())
{
cout << "-over flow" << endl;
return false;
}
e = heap[1];
Nodeptr tem=heap[usage--];
int Parent, Child;
for (Parent = 1; Parent * 2 <= usage; Parent = Child) //判断有没有Parent(左)儿子
{
Child = Parent * 2; //假设左儿子更小
if ((Child != usage) && (heap[Child]->weigh > heap[Child + 1]->weigh))
Child++;
if (tem->weigh <= heap[Child]->weigh)
break;
else
heap[Parent] = heap[Child];
}
heap[Parent] = tem;
return true;
}
bool IsFull()
{
return usage >= size-1;
}
bool Isempty()
{
return usage == 0;
}
//测试输出
void pf()
{
for (int i = 0; i <= usage; i++)
{
cout << i << ":" << heap[i]->weigh << endl;
}
}
};
小顶堆写完后,哈夫曼树就很容易构建了,把每个元素看成一棵树,每次取堆顶元素,即选取树根权重最小的两棵树,合并为一棵树,树根权重为两棵树的树根权重之和,n个元素,进行n-1次就构建了一棵哈夫曼数啦。开心啊
下面贴代码
//哈夫曼树.h
#include"最小堆.h"
class HfTree
{
private:
Nodeptr Head;
public:
HfTree(Nodeptr a[], int size)
{
MinHeap m(size, a, size); //建立小顶堆
Nodeptr t1, t2;
for (int i = 1; i < size; i++)
{
Nodeptr tem = new Node;
m.Delete(t1);
m.Delete(t2);
tem->left = t1;
tem->right = t2;
tem->weigh = t1->weigh + t2->weigh;
t1->parent = tem;
t2->parent = tem;
m.Add(tem);
}
m.Delete(Head);
}
//单元测试
void pf(Nodeptr a[], int size)
{
for (int i = 0; i < size; i++)
{
int length = 1;
Nodeptr tem = a[i];
while (tem->parent != Head)
{
length++;
tem = tem->parent;
}
cout << a[i]->content << ":" << length << endl;
}
}
};
下面是主函数(仅做测试)
#include "哈夫曼树.h"
int main()
{
/*小顶堆测试*/
// Nodeptr a[10];
// for (int i = 0; i < 7; i++)
// {
// a[i] = new Node;
// a[i]->weigh = 7 - i;
// }
// MinHeap t(10,a,7);
// t.pf();
/*哈夫曼数测试*/
Nodeptr a = new Node(2, 'a');
Nodeptr b = new Node(3, 'b');
Nodeptr c = new Node(4, 'c');
Nodeptr d = new Node(5, 'd');
Nodeptr e = new Node(6, 'e');
Nodeptr f = new Node(7, 'f');
Nodeptr arr[6];
arr[0] = a;
arr[1] = b;
arr[2] = c;
arr[3] = d;
arr[4] = e;
arr[5] = f;
HfTree testtree(arr, 6);
testtree.pf(arr, 6);
}
p.s 从文件里读取,进行压缩和解压缩还没完成,但程序主体大致完成了,周末有时间再写吧
这是分割线
贴代码:
#include
#include
#include
#include
using namespace std;
string readfile(int *a)
{
cout << "请输入要压缩的文件:";
string FilePath;
cin >> FilePath;
ifstream f(FilePath);
while(!f)
{
cout << "打开文件失败!" << endl;
cout << "请输入要压缩的文件:";
string FilePath;
cin >> FilePath;
f.open(FilePath);
}
string line;
char tem;
while (getline(f, line))
{
// istringstream s(line);
// while (s >> tem)
// a[tem]++;
for (int i = 0; i < line.length(); i++)
{
tem = line[i];
a[tem]++;
}
a['\n']++;
}
// cout << a['\n'] << endl;
// char tem;
// while (f>>tem)
// {
// //cout << tem << endl; //测试读入的字符
// a[tem]++;
// }
f.close();
return FilePath;
}
重写的主函数:
#include "哈夫曼树.h"
#include "readfile.h"
//传进来一个"10101001"的字符串,返回一个对应的ASCII字符
unsigned char StrToBin(string str)
{
int a = atoi(str.c_str());
int b = 1;
int ans = 0;
while (a != 0)
{
ans += a % 10 * b;
b *= 2;
a /= 10;
}
return (unsigned char)ans;
}
//把unsigned char类型转换为2进制字符串
string BinToStr(unsigned char c)
{
string ans;
while (c != 0)
{
ans.insert(ans.begin(), unsigned char(c % 2 + '0'));
c /= 2;
}
if (ans.length() < 8)
{
ans.insert(ans.begin(), 8 - ans.length(), '0');
}
return ans;
}
/*解码*/
char decode(Nodeptr t,string &code) //调试输出
{
int i;
for (i = 0; i < code.length(); i++)
{
if (t->content == 0)
{
if (t->left == nullptr&&t->right == nullptr)
{
code.erase(0, code.length());
return '\n';
}
t = (code[i] - '0') ? t->right : t->left;
}
else
{
code.erase(0, i);
//cout << t->content;
return t->content;
}
}
}
int main()
{
int num=0; //文本长度
int HashTable[256] = { 0 }; //hash表 快速查找相应字符权重
string FilePath = readfile(HashTable);//文件路径
Nodeptr CharArr[256]; //存储结点数据 最多256个字符
int size = 0; //存储文件中使用的字符个数
for (int i = 0; i < 256; i++) //建立读取的文件字符构建节点数据
{
if (HashTable[i] != 0)
{
CharArr[size] = new Node;
CharArr[size]->weigh = HashTable[i];
CharArr[size]->content = char(i);
size++;
}
}
/*建立最小堆和哈夫曼树*/
HfTree t(CharArr, size);
string BinCode[256]; //存储二进制code
t.setcode(BinCode, t.GTN());
/*开始写入文件*/
ifstream in(FilePath); //读取文件
ofstream out("out.myfile", ofstream::trunc); //压缩文件
/*首先写入哈夫曼数*/
cout << size << endl; //存储哈夫曼行数
for (int i = 0; i < size; i++)
{
if (CharArr[i]->content == '\n')
{
cout << CharArr[i]->code << ' ' << "\\n" << endl;
}
else
cout << CharArr[i]->code << ' ' << CharArr[i]->content << endl;
}
/**********************************************************************/
// out << size << endl; //存储哈夫曼行数
// for (int i = 0; i < size; i++)
// {
// if (CharArr[i]->content == '\n')
// {
// out << CharArr[i]->code << ' ' << "\\n" << endl;
// }
// else
// out << CharArr[i]->code << ' ' << CharArr[i]->content << endl;
// }
/**********************************************************************/
char c; //一次读入一个字符
string temBuf; //字符串缓存
temBuf.clear();
string line;
while (getline(in, line))
{
for (int i = 0; i <= line.length(); i++)
{
if (i == line.length())
c = '\n';
else
c = line[i];
temBuf.append(BinCode[c]);
if (temBuf.length() >= 8)
{
out << StrToBin(temBuf.substr(0, 8));
temBuf.erase(0, 8);//删除前八个字符
}
num++;
}
}
int appendZero = 0; //附加0的数量
if (!temBuf.empty())
{
appendZero = 8 - temBuf.length();
temBuf.append(appendZero, '0');
out << StrToBin(temBuf);
temBuf.erase(0, 8);
}
in.close();
out.close();
/*完成文件的压缩*/
/*解码*/
cout << "请输入要解码的文件:";
cin >> FilePath;
in.open(FilePath, ifstream::binary);
out.open("解压.txt", ofstream::trunc);
temBuf.clear();
// in.read((char *)& c,sizeof(char));
// cout << c;
// cout<
// while (1) //每次读取一个字符大小
// {
//cout << c << endl;
// if (temBuf.length() < 8)
// {
// if (in.read((char*)& c, sizeof(char)))
// temBuf.append(BinToStr(c)); //转化为code形式
// else
// {
// do {
// cout << decode(t.GTN(), temBuf);
// } while (!temBuf.empty());
// break;
// }
// }
while (in.read((char*)& c, sizeof(char)))
{
temBuf.append(BinToStr(c));
}
int temnum = 0; //临时计数变量
while (!temBuf.empty())
{
temnum++;
cout << decode(t.GTN(), temBuf);
if(temnum==num)
break;
}
getchar();
getchar();
}
写的有点凌乱,有时间再整理一下吧。