哈夫曼树实现文本的压缩和解压
哈夫曼树这里就不在做相关介绍,网上也有很多哈夫曼树的介绍,这里主要介绍利用哈夫曼树进行文件的压缩与解压
首先是哈夫曼树的建立:ASCII 码一共有256个(常用的有128个)建立的时候可以选择一起将全部ASCII一起建立也可以选择按文档中出现的字符建立。虽然如果选择将所有字符一起建立的话可能会多很多,但由于在合并的之后所有0的点都会合并在一起所以对文件编码长度几乎没有影响。
下面是节点的结构与初始化
class HTNODE{
int weight;//权值
int lchid;
int rlight;
int parent;
int index;//下标
}
void InitHT(){
for (int i=0;i<2*N-1;i++){
htnode[i] = new HTNODE();
htnode[i].lchid = -1;
htnode[i].rlight = -1;
htnode[i].parent = -1;
htnode[i].weight = 0;
htnode[i].index = i;
}
}
这里增加了一个下标,方便解压时的转化
前256个节点即为字符ASCII对应的下标,这样在压缩和解压时即可通过下标直接由节点转化为相应的字符
首先是从文件中按字符读取文本内容,每读取到一个字符其ASCII数值的结点下标权值相应加1
void readfile(){
File file = new File("originalfile.txt");
Reader reader;
try {
// 一次读一个字符
reader = new InputStreamReader(new FileInputStream(file));
int tempchar;
while ((tempchar = reader.read()) != -1) {
// 对于windows下,\r\n这两个字符在一起时,表示一个换行。
// 但如果这两个字符分开显示时,会换两次行。
// 因此,屏蔽掉\r,或者屏蔽\n。否则,将会多出很多空行。
if (((char) tempchar) != '\r') {
oldfile += (char) tempchar;
htnode[tempchar].weight++;
}
}
reader.close();
}
catch (IOException e) {
System.out.println("打开文件失败\n");
}
}
接下来是寻找节点中权值最小的两个结点并返回下标
int[] findmin(int i){
int[] min = new int[2];
min[0] = Integer.MAX_VALUE;
min[1] = Integer.MAX_VALUE;
int[] index = {0,0};
for (int j=0; j<i; j++){
if((min[0]>htnode[j].weight)&&(htnode[j].parent == -1)){
min[1] = min[0];
min[0] = htnode[j].weight;
index[1] = index[0];
index[0] = j;
}
else if((min[1]>htnode[j].weight)&&(htnode[j].parent == -1)){
min[1] = htnode[j].weight;
index[1] = j;
}
}
return index;
}
接下来是对结点的合并,前N个节点为基础结点,所以合并从下标为N的结点开始,寻找所有结点中权值最小的两个结点进行合并
void CreatHT(){
int[] min;
for(int i=N;i<2*N-1;i++){
min = findmin(i);
htnode[min[0]].parent = i;
htnode[min[1]].parent = i;
htnode[i].lchid = min[0];
htnode[i].rlight = min[1];
htnode[i].weight = htnode[min[0]].weight + htnode[min[1]].weight;