Huffman编码C++实现

http://blog.chinaunix.net/uid-20546521-id-1927625.html

//*******************************huffman.h**********************
//*****************叶子结点为n的哈夫曼树共有2n-1个结点**********

#ifndef HUFFMAN_H
#define HUFFMAN_H

class HuffmanNode {
public:
    char info; //结点信息
    double weight; //结点权值
    int parent, lchild, rchild; //父亲结点,左右孩子结点
    HuffmanNode() {
        parent=lchild=rchild=-1;
    }
    HuffmanNode(const char &data, const double &wt, const int &pa=-1, const int &lch=-1, const int &rch=-1) {
        info=data;
        weight=wt;
        parent=pa;
        lchild=lch;
        rchild=rch;
    }
}; //class HuffmanNode end
       
class HuffmanTree {
public:
    HuffmanTree(const int &s=100) {
        maxSize=(s>100?s:100);
        arrayTree=new HuffmanNode[maxSize];
        currentSize=0;
        codeArray=0;
    }
    ~HuffmanTree() {
        delete[] arrayTree;
        if (codeArray!=0)
            delete[] codeArray;
    }
    void run(const char*, const char*, const char*);

private:
    HuffmanNode *arrayTree; //哈夫曼结点数组
    int maxSize; //数组最大值
    int currentSize; //当前数组大小
    void insert(const char&, const double&); //插入结点
    void createHuffmanTree(); //创建哈夫曼树
    void createHuffmanCode(); //创建哈夫曼编码
    int findPosition(const char &) const; //返回字符在arrayTree[]中的位置
    int getLongestCodeLength() const; //返回编码系统中长度最大的编码的位置
    int isEqual(const char *s) const; //判断s是否存在于编码系统中,若存在则返回s在编码系统中的位置,否则返回-1
    void print(); //打印huffman编码
private:
    class Code { //HuffmanTree的私有类,编码类
    public:
        Code():length(10) { ptr=new char[length]; }
        ~Code() { delete[] ptr; }
        char *ptr;
        const int length;
    };
    Code *codeArray; //数组大小为currentSize
    void reverse(char arr[]);
}; //class HuffmanTree end

#endif //huffman.h end


//**************************huffman.cpp**********************

#include <iostream>
#include <fstream> //for ofstream ifstream
#include <limits>  //for numeric_limits<double>::max()
#include <cstdlib> //for exit()
#include <cstring> //for strlen(), strcpy(), strcmp()
#include "huffman.h"
using namespace std;

void HuffmanTree::insert(const char &data, const double &wt) { //插入结点
    if (2*currentSize-1 >= maxSize) //叶子结点为n的哈夫曼树共有2n-1个结点
        return;
    arrayTree[currentSize].info=data;
    arrayTree[currentSize].weight=wt;
    currentSize++;
}

void HuffmanTree::reverse(char arr[]) { //反转字符串
    const int len=strlen(arr);
    char *p;
    p=new char[len+1];
    strcpy(p, arr);
    p[len]='\0';
    int k=0;
    for (int i=len-1; i>=0; i--)
        arr[i]=p[k++];
    arr[len]='\0';
    delete[] p;
}

int HuffmanTree::findPosition(const char &ch) const { //返回字符ch在arrayTree[]中的位置
    for (int i=0; i<currentSize; i++)
        if (arrayTree[i].info == ch)
            return i;
    return -1;
}

int HuffmanTree::getLongestCodeLength() const { //返回编码数组codeArray[]长度最长的编码的位置
    if (currentSize == 0)
        return -1;
    int len=strlen(codeArray[0].ptr);
    int i=1;
    while (i < currentSize) {
        int tmp=strlen(codeArray[i].ptr);
        if (tmp > len)
            len=tmp;
        i++;
    }
    return len;
}

int HuffmanTree::isEqual(const char *s) const { //判断s的编码是否存在,若存在返回编码在数组codeArray[]中的位置,否则返回-1
    for (int i=0; i<currentSize; i++)
        if (strlen(s) == strlen(codeArray[i].ptr)) //可以去掉此行
            if (strcmp(s, codeArray[i].ptr) == 0)
                return i;
    return -1;
}
   
void HuffmanTree::print() { //打印编码
    int k=0;
    while (k < currentSize) {
        cout<<arrayTree[k].info<<'('<<arrayTree[k].weight<<"): "<<codeArray[k].ptr<<endl;
        k++;
    }
}

void HuffmanTree::createHuffmanTree() { //构造huffmanTree
    int i=currentSize;
    int k;
    double wt1, wt2;
    int lnode, rnode;
    while (i < 2*currentSize-1) {
        wt1=wt2=numeric_limits<double>::max();
        k=0;
        while (k < i) {
            if (arrayTree[k].parent==-1) {
                if (arrayTree[k].weight<wt1) {
                    wt2=wt1;
                    rnode=lnode;
                    wt1=arrayTree[k].weight;
                    lnode=k;
                }
                else if (arrayTree[k].weight<wt2) {
                    wt2=arrayTree[k].weight;
                    rnode=k;
                }
            }
            k++;
        }
        arrayTree[i].weight = arrayTree[lnode].weight+arrayTree[rnode].weight;
        arrayTree[i].lchild=lnode;
        arrayTree[i].rchild=rnode;
        arrayTree[lnode].parent=arrayTree[rnode].parent=i;
        i++;
    }
}           

void HuffmanTree::createHuffmanCode() { //构造huffmanCode,即哈夫曼编码
    codeArray=new Code[currentSize];
    int i=0;
    int k, n, m;
    while (i < currentSize) {
        k = arrayTree[i].parent;
        n=0;
        m=i;
        while (k!=-1 && k<currentSize*2-1) {
            if (arrayTree[k].lchild==m)
                codeArray[i].ptr[n++]='0';
            else if (arrayTree[k].rchild==m)
                codeArray[i].ptr[n++]='1';
            m=k;
            k=arrayTree[m].parent;
        }
        codeArray[i].ptr[n]='\0';
        reverse(codeArray[i].ptr); //反转字符串,使之变成正确的编码
        i++;
    }
}

void HuffmanTree::run(const char *inFilename, const char *outFilename, const char *secondOutName) { //run函数的实现
    //打开inFilename提供输入
    ifstream fileIn(inFilename, ios::in);
    if (!fileIn) {
        cerr<<"\""<<inFilename<<"\" could not open."<<endl;
        exit(1);
    }
    char ch;
    int pos;

    //从文件中读入字符,并统计各个字符个数
    fileIn>>ch;
    while (fileIn && !fileIn.eof()) {
        pos = findPosition(ch);
        if (pos != -1)
            arrayTree[pos].weight++;
        else
            insert(ch, 1);
        fileIn>>ch;
    }

    createHuffmanTree(); //构造huffman树
    createHuffmanCode(); //对统计字符进行编码

    //打开outFilename提供输出
    ofstream fileOut(outFilename, ios::out);
    if (!fileOut) {
        cerr<<"\""<<outFilename<<"\" could not open."<<endl;
        exit(1);
    }
    fileIn.clear(); //刷新输入流, 注:ofstream没有flush()方法,而ifstream则有flush()方法
    fileIn.seekg(0, ios::beg);

    //把从inFilename文件中的字符进行编码,并写入outFilename文件
    fileIn>>ch;
    while (fileIn && !fileIn.eof()) {
        pos = findPosition(ch);
        if (pos != -1)
            fileOut<<codeArray[pos].ptr;
        fileIn>>ch;
    }
    fileIn.close();
    fileOut.close();

    //打开outFilename, secondOutName,分别提供输入输出
    fileIn.open(outFilename, ios::in);
    fileOut.open(secondOutName, ios::out);
    if (!fileIn || !fileOut) {
        cerr<<"File could not open."<<endl;
        exit(1);
    }

    //把outFileName文件中的编码进行译码,并把译码结果写入secondOutName文件
    const int longestLen = getLongestCodeLength();
    char *p = new char[longestLen+1];
    int k=0;
    fileIn>>ch;
    while (fileIn && !fileIn.eof()) {
        if (k < longestLen) {
            p[k++]=ch;
            p[k]='\0';
            pos = isEqual(p);
            if (pos != -1) {
                fileOut<<arrayTree[pos].info;
                k=0;
            }
        }
        else {
            cerr<<"The code is wrong."<<endl;
            exit(1);
        }
        fileIn>>ch;
    }

    fileIn.close();
    fileOut.close();
}
       
//huffman.cpp end


//*****************************main.cpp*************************

#include "huffman.h"

int main() {
    HuffmanTree tree;
    //const char *inFileName="in.txt";
    const char *inFileName="main.cpp";
    const char *outFileName="out1.txt";
    const char *secondOutName="out2.txt";
    tree.run(inFileName, outFileName, secondOutName);
    return 0;
} //main.cpp end

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值