您的位置:首页 >> 软件资讯 >> 站长专栏 >> 文章正文

霍夫曼编码算法C++实现

2008-3-30 15:35:44 来源:本站原创 作者:李文鹏 点击:1253

霍夫曼编码的思路就是按照字符出现的概率(或权重)来构造一颗霍夫曼二叉树,然后通过遍历二叉树的节点对霍夫曼树进行编码,道理貌似不是很难.程序也写好了,不过在写好之后才发现这个算法其实还可以改进,在构建霍夫曼树的时候,我将所有出现过的字符全都压入vector,然后对其进行遍历将其中权重最小的两个字符读出然后,将其的父节点设为一空霍夫曼节点,并将此父节点的权重高为两 个字节点的权重之和,然后将此父节点压入vector,这个过程中我已经把两个取出的子节点从vector中删除,最后霍夫曼树构建完成的时候vector中只有一个节点,那就是霍夫曼树的根节点.这样在遍历的时候会影响效率,因为要从叶子节点开始遍历,而取得叶子节点需要先正向遍历一遍霍夫曼树,这样就带来了额外的开销.改进的方法是取出权重最小的两个节点后并不从vector中删除,而是将其父节点由NULL设为其它 节点,这样循环构造霍夫曼条件的结束条件就是vector中的父节点不空的节点只有一个,此节点也即霍夫曼树的根节点.在遍历的时候通过遍历vector就可以得到各叶子节点.这样就算完成了,算法我也懒得改进了,就先这样吧,还是我思维不够敏捷啊.

/***************************************************/
/*    项目名称:霍夫曼编码算法                                                 */
/*    测试平台:Linux,gcc4.1.2                                                       */
/*    程序员:通信工程2005级,李文鹏                                         */
/***************************************************/
#include <iostream.h>
#include <vector>
#include <string>

using namespace std;
//存储霍夫曼树节点的数据结构
typedef struct treenode
{
    char data;                    //存储要编码的字符
    int weight;                    //存储要编码的字符的权重
    struct treenode* parent;    //父节点
    struct treenode* lchild;    //左子树
    struct treenode* rchild;    //右子树
}TreeNode;
/*******************************************************************/
/*函数功能:获得字符cc在文件中出现的次重,以此作为权重
/******************************************************************/
int GetCount(FILE* fp,char cc)
{
    int i=1;
    while(!feof(fp))
    {
        if(cc==fgetc(fp))
            i++;
    }
    rewind(fp);
    return i;
}
/******************************************************************************/
//函数功能:判断vector中是否已存在指定字符为cc的treenode
/******************************************************************************/
int IsExit(vector<TreeNode*> vec,char cc)
{
    for(int i=0;i<vec.size();i++)
    {
        if(cc==vec[i]->data)
            return 1;
    }
    return 0;
}
/******************************************************************************/
//函数功能:从vector中选择权重最小的两个节点lnode,
//         rnode,并将其从vector中移除
/******************************************************************************/
vector<TreeNode*> Select(vector<TreeNode*> vec,TreeNode** lnode,TreeNode** rnode)
{
    int temp=vec[0]->weight;
    vector<TreeNode*>::iterator iter=vec.begin();
    vector<TreeNode*>::iterator it=vec.begin();
    if(vec.size()==1)
        return vec;
    while(iter!=vec.end())
    {
        if(temp>=iter[0]->weight)
        {
            *lnode=iter[0];
            it=iter;
            temp=iter[0]->weight;
        }
        iter++;
    }
    vec.erase(it);//将取出的第一个节点从vector中删掉
    temp=vec[0]->weight;
    it=iter=vec.begin();
    while(iter!=vec.end())
    {
        if(temp>=iter[0]->weight)
        {
            *rnode=iter[0];
            it=iter;
            temp=iter[0]->weight;
        }
        iter++;
    }

    vec.erase(it);//将取出的第二个节点从vector中删掉

    return vec;
}
/******************************************************************************/
//函数功能:判断vector中是否只含有一个父节点为NULL的节点
//         则将此节点作为霍夫曼树的根节点返回
/******************************************************************************/
TreeNode* Top(vector<TreeNode*> vec)
{
    int flag=0;
    TreeNode* node;
    for(int i=0;i<vec.size();i++)
    {
        if(vec[i]->parent==NULL)
        {
            flag++;
            node=vec[i];
        }
    }
    if(flag>1)
        return NULL;
    return node;
}
/******************************************************************************/
//函数功能:初始化vector,将文件中的字符及其权重
//                  不重复的写入treenode,并将其压入vector
/******************************************************************************/
vector<TreeNode*> InitList(FILE *fp)
{
   
    int i=0,flag=0;
    char cc;
    TreeNode* node;
    vector<TreeNode*> vec;

    while(!feof(fp))
    {
        cc=fgetc(fp);
        //若数据重复则跳过此次循环
        if(IsExit(vec,cc))
        {
            continue;
        }
        //将本次循环取出的字符作为TreeNode的data,并计算其权重,将TreeNode
        //的左子树和右字树以及父节点初始化为NULL,其压入vector
        node=(TreeNode*)malloc(sizeof(TreeNode));
        node->data=cc;
        node->weight=GetCount(fp,node->data);
        node->lchild=node->rchild=node->parent=NULL;
        vec.push_back(node);

    }
    rewind(fp);//将文件指针重定向到文件头
    return vec;

}
/******************************************************************************/
//函数功能:构造霍夫曼树
/******************************************************************************/
TreeNode* CreateTree(vector<TreeNode*> vec)
{
    TreeNode* root;        //霍夫曼树的根节点
    TreeNode* lchild;    //霍夫曼树的左子树
    TreeNode* rchild;    //霍夫曼树的右子树
    tree=(TreeNode*)malloc(sizeof(TreeNode));
    int i=0;
    while(1)
    {
        lchild=rchild=(TreeNode*)malloc(sizeof(TreeNode));
        //从vector中选择权重最小的两个节点
        vec=Select(vec,&lchild,&rchild);
        //新建一个TreeNode节点
        TreeNode* node=(TreeNode*)malloc(sizeof(TreeNode));
        //将取出的节点作为TreeNode节点的的左子树和右子树
        node->parent=NULL;
        node->lchild=lchild;
        node->rchild=rchild;
        //新节点的权重为其左子树和右子树的权重之和
        node->weight=lchild->weight+rchild->weight;
        lchild->parent=rchild->parent=node;   
        //将新建的节点压入vector
        vec.push_back(node);

       
        if((root=Top(vec))!=NULL)
            break;
    }
    return root;

}
/******************************************************************************/
//函数功能:递归遍历某一支树,对某一字符进行编码
/******************************************************************************/
string Trace(TreeNode* Node,string cc)
{
    if(Node->parent)
    {
        if(Node->parent->lchild==Node)
        {
            cc="1"+cc;
        }
        if(Node->parent->rchild==Node)
        {
            cc="0"+cc;
        }
        cc=Trace(Node->parent,cc);
    }
    return cc;
}
/******************************************************************************/
//函数功能:对霍夫曼树的节点进行访问
/******************************************************************************/
void Visit(TreeNode* Node)
{
    string cc("");
    if(Node->lchild==NULL&&Node->rchild==NULL)
    {
        cout<<"the encoding of charactor '"<<Node->data<<"' is "<<Trace(Node,cc)<<endl;
    }
}
/******************************************************************************/
//函数功能:对霍夫曼树进行中序遍历
/******************************************************************************/
void Inorder(TreeNode* top,void (*Visit)(TreeNode* Node))
{
    if(top)
    {
        Inorder(top->lchild,Visit);
        Visit(top);
        Inorder(top->rchild,Visit);
    }
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        cout<<"Usage:"<<argv[0]<<" <input file> <output file>"<<endl;
        return -1;
    }
    vector<TreeNode*> vec;
    FILE* fp;
    TreeNode* top=(TreeNode*)malloc(sizeof(TreeNode));
    fp=fopen(argv[1],"r");
    vec=InitList(fp);
    vector<TreeNode*>::iterator iter=vec.begin();
    top=CreateTree(vec);
    Inorder(top,Visit);
   
    return 0;
}

上一篇: 没有了
下一篇:

文章评论[我要评论]

此文章暂无评论