哈夫曼编解码的C++实现

21 篇文章 0 订阅
16 篇文章 0 订阅
#include <iostream>
#include <vector>
#include <string>
#include <map>

using namespace std;

// 哈夫曼编码
template<typename Type>
class CHaffumanCode
{
public:
    //哈夫曼树的结点结构
    typedef struct _HaffNode {
        typename Type symbol;       // 符号
        int weight;         //权值
        int flag;           //标记,是否存在父节点
        int parent;         //双亲结点下标
        int leftChild;      //左孩子下标
        int rightChild;     //右孩子下标
    }HaffNode;

    // 设置符号列表及权重列表
    void Set(const std::vector<Type> &symbolVec, const std::vector<int> &weightVec){
        m_symbolVec = symbolVec;
        m_weightVec = weightVec;
    }

    // 添加符号及相应的权重
    void Push(const Type &d, int weight){
        m_symbolVec.push_back(d);
        m_weightVec.push_back(weight);
    }

    // 由符号及权重建立基于数组的哈夫曼树
    void BuildHaffmanTree(){
        int iSymbolNum = m_weightVec.size();
        m_haffTree.clear(); //哈夫曼树haffTree初始化。n个叶结点的哈夫曼树共有2n-1个结点
        m_haffTree.reserve(2*iSymbolNum-1);
        for(int i = 0; i < 2 * iSymbolNum - 1 ; i++){
            HaffNode hNode;

            if(i < iSymbolNum) {
                hNode.weight = m_weightVec[i];
                hNode.symbol = m_symbolVec[i];
            }
            else    
                hNode.weight = 0;

            hNode.parent = 0;
            hNode.flag   = 0;
            hNode.leftChild = -1;
            hNode.rightChild = -1;

            m_haffTree.push_back(hNode);
        }

        //构造哈夫曼树haffTree的n-1个非叶结点
        for(int i = 0; i < iSymbolNum-1; i++)   {
            int iMin_1 = INT_MAX, iMin_2 = INT_MAX; // iMin_1 存放最小值,iMin_2存放次小值
            int iMin_1_pos = 0, iMin_2_pos = 0;    // iMin_1_pos指示最小值的位置,iMin_2_pos指示次小值的位置
            for(int j = 0; j < iSymbolNum+i; j++)   {
                if (m_haffTree[j].weight < iMin_1 && m_haffTree[j].flag == 0){
                    iMin_2 = iMin_1;
                    iMin_2_pos = iMin_1_pos;
                    iMin_1 = m_haffTree[j].weight;
                    iMin_1_pos = j;
                }
                else if(m_haffTree[j].weight < iMin_2 && m_haffTree[j].flag == 0){
                    iMin_2 = m_haffTree[j].weight;
                    iMin_2_pos = j;
                }
            }

            //将找出的两棵权值最小的子树合并为一棵子树
            m_haffTree[iMin_1_pos].parent  = iSymbolNum+i;   
            m_haffTree[iMin_2_pos].parent  = iSymbolNum+i;
            m_haffTree[iMin_1_pos].flag    = 1;
            m_haffTree[iMin_2_pos].flag    = 1;
            m_haffTree[iSymbolNum+i].weight = m_haffTree[iMin_1_pos].weight+m_haffTree[iMin_2_pos].weight;
            m_haffTree[iSymbolNum+i].leftChild = iMin_1_pos;
            m_haffTree[iSymbolNum+i].rightChild = iMin_2_pos;
        }
    }

    // 由哈夫曼树构建(符号,码)对
    void BuildHaffmanCode(){
        int n = m_haffTree.size()/2+1;

        for(int i = 0; i < n; i++)  { //求n个叶结点的哈夫曼编码
            typename Type symbol = m_haffTree[i].symbol;
            string szKey;

            int child = i;
            int parent = m_haffTree[child].parent;

            //由叶结点向上直到根结点
            while(parent != 0)
            {
                if(m_haffTree[parent].leftChild == child)
                    szKey.push_back('0');
                else                    
                    szKey.push_back('1');
                child = parent;
                parent = m_haffTree[child].parent;
            }

            m_codeMap[symbol] = string(szKey.rbegin(), szKey.rend());
        }
    }

    // 哈夫曼编码
    /*
     * @Parm begin [in]: 符号流的起始迭代位置
     * @Parm end [in]: 符号流的结束迭代位置
     * @Parm szCode [in/out]: 输出码流
     */
    template<typename IterateType>
    void Encode(IterateType begin, IterateType end, std::string &szCode){
        for (; begin != end; ++begin){
            if (m_codeMap.lower_bound(*begin) == m_codeMap.end()){
                std::cout << "Encode : 未知符号..." << endl;
                return;
            }
            szCode += m_codeMap[*begin];
        }
    }

    /*
     * @Parm begin [in]: 符号流的起始迭代位置
     * @Parm end [in]: 符号流的结束迭代位置
     * @Parm szCode [in/out]: 输出码流
     */
    template<typename IterateType>
    std::string Encode(IterateType begin, IterateType end){
        std::string szCode;
        for (; begin != end; ++begin){
            if (m_codeMap.lower_bound(*begin) == m_codeMap.end()){
                std::cout << "Encode : 未知符号..." << endl;
                return szCode;
            }
            szCode += m_codeMap[*begin];
        }
        return szCode;
    }

    // 哈夫曼解码
    void Decode(const std::string &szCode, std::vector<Type> &symbolVec){
        int iPos = m_haffTree.size() - 1; // 解码前至于根节点处
        for (auto it = szCode.begin(); it != szCode.end(); ++it){
            if (*it == '0')
                iPos = m_haffTree[iPos].leftChild;
            else if (*it == '1')
                iPos = m_haffTree[iPos].rightChild;

            // 该节点为叶子节点
            if ((m_haffTree[iPos].leftChild == -1) && (m_haffTree[iPos].rightChild == -1)){ 
                symbolVec.push_back(m_haffTree[iPos].symbol);
                iPos =  m_haffTree.size() - 1;
            }
        }
    }

    std::vector<Type> Decode(const std::string &szCode){
        std::vector<Type> &symbolVec;
        int iPos = m_haffTree.size() - 1; // 解码前至于根节点处
        for (auto it = szCode.begin(); it != szCode.end(); ++it){
            if (*it == '0')
                iPos = m_haffTree[iPos].leftChild;
            else if (*it == '1')
                iPos = m_haffTree[iPos].rightChild;

            // 该节点为叶子节点
            if ((m_haffTree[iPos].leftChild == -1) && (m_haffTree[iPos].rightChild == -1)){ 
                symbolVec.push_back(m_haffTree[iPos].symbol);
                iPos =  m_haffTree.size() - 1;
            }
        }
    }

    // 打印编码信息
    void PrintCodeInfo(){
        for (auto it = m_codeMap.begin(); it != m_codeMap.end(); ++it){
            std::cout << it->first << ", ";
        }
        std::cout << endl;

        for (auto it = m_codeMap.begin(); it != m_codeMap.end(); ++it){
            std::cout << it->second.length() << ", ";
        }
        cout << endl;

        for (auto it = m_codeMap.begin(); it != m_codeMap.end(); ++it){
            std::cout << "<" << it->first << ", 长度为 " << it->second.length() << ", " << it->second << ">" << endl;
        }
    }

private:
    std::vector<Type> m_symbolVec; // 符号列表
    std::vector<int> m_weightVec;  // 符号对应的权重列表
    std::vector<HaffNode> m_haffTree; // 哈夫曼树
    std::map<Type, std::string> m_codeMap;
};

void main(void){
    int symbol[] =  {100, 1, 1, 1, 2, 3, 5, 7, 59,100, 1, 2, 3, 5, 7, 59,16, 20, 30, 99, 40,100, 1, 2, 3, 5, 7, 59, 8, 10, 12, 78, 14, 16, 20, 30, 99, 40, 50, 97, 120};
    int weight[] = {100, 1, 2, 3, 5, 7, 59, 8, 10, 12, 78, 14, 16, 20, 30, 99, 40, 50, 97, 120};

    CHaffumanCode<int> haff;
    haff.Set(vector<int>(weight, weight+sizeof(weight)/sizeof(int)), vector<int>(weight, weight+sizeof(weight)/sizeof(int)));
    haff.BuildHaffmanTree();
    haff.BuildHaffmanCode();

    haff.PrintCodeInfo();

    string szCode;
    haff.Encode(symbol, symbol+sizeof(symbol)/sizeof(int), szCode);
    cout << "码流:\n\n" << szCode << endl;

    cout << "编码前的符号:" << endl;
    ostream_iterator<int> out(cout, ", ");
    copy(symbol, symbol+sizeof(symbol)/sizeof(int), out);
    cout << "\n解码后的符号:" << endl;
    vector<int> symVec;
    haff.Decode(szCode, symVec);
    copy(symVec.begin(), symVec.end(), out);
    cout << endl;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值