美文网首页
自底向上的哈夫曼编码

自底向上的哈夫曼编码

作者: Fgban | 来源:发表于2020-02-28 11:54 被阅读0次
    哈夫曼编码原理:哈夫曼编码原理
    练习题目:哈夫曼编码

    其中第一个即是自底向上的,另外还有几个练习题,可以进行相应练习。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<algorithm>
    
    
    using namespace std;
    //输入数字个数 
    const int maxn = 110;
    //输入的需编码的数字数组 
    int w[maxn];
    
    //哈夫曼树节点定义
    //每个节点包括其权值,父亲节点指针以及左右孩子结点指针 
    typedef struct{
        int wt;
        int parent, lchild, rchild;
    }hftree;
    
    /***************************************************************
    /*从已有的节点中选出权值最小的两个结点
    /*参数:hftree,根据节点权值建立后的哈夫曼树,n当前已有节点个数
    /*      a第一小的节点,b第二小的节点 
    *****************************************************************/
    void min_two(hftree* tree, int n, int &a, int &b){
        //m初始设置为一个很大的数 
        int m = 0x3fffffff;
        //在已有的节点中寻找两个权值最小的节点 
        for(int i = 1; i <= n; i++){
            if(tree[i].parent == 0 && m > tree[i].wt){
                m = tree[i].wt;
                a = i;
            }
        }
        //寻找第二个 
        m = 0x3fffffff;
        for(int i = 1; i <= n; i++){
            if(tree[i].parent == 0 && m > tree[i].wt && i != a){
                m = tree[i].wt;
                b = i;
            }
        }
        //由于当选出两个最小的节点之后,我们将两个节点所放的左右顺序不同时
        //得到的编码顺序也是不同的,为了得到一个固定的编码,同时为了能够
        //AC题目,将两个中更小的放在左边
        /****若无此步得到的编码将是不唯一的 ***/
        if(a > b)
            swap(a, b);
    }
    /*********************************************************************************
    /*         哈夫曼树的建立以及编码过程
    /* 根据输入的n个权值初始化n个叶子节点,再依次选择未合并的节点(包括新节点)中的最小
    /*的两个权值节点进行合并,直到只剩下一个未合并的节点即根结点时结束,
    /* 然后则进行自底向上的编码,每次都从某一个叶子节点出发,如果是其父节点的左孩子则添0 
    /*如果是右孩子则添1,直到碰到根结点结束 
    /********************************************************************************/
    void HuffmanCode(hftree* &t, char** &code, int w[], int n){
        //当输入的n为1或者0时无需编码 
        if(n <= 1)
            return ;
        //由于每次在找两个节点并合成时,都会生成一个新的节点,而n个结点则会生成n-1个
        //而生成的节点是哈夫曼树中的非叶子节点,因此需要定义足够的数组空间 
        int m = 2 * n - 1;
        //根据得到的节点个数为哈夫曼树分配空间,0号空间不使用 
        t = (hftree *)malloc((m+1)*sizeof(hftree));
        //使用初始的n个数初始化哈夫曼树,相当于初始化叶子节点 
        for(int i = 1; i <= n; i++){
            t[i].wt = w[i];
            t[i].parent = t[i].lchild = t[i].rchild = 0;
        }
        //对非叶子节点初始化信息,由于它们是之后生成的,因此没有初始化权值信息 
        for(int i = n+1; i <= m; i++)
            t[i].parent = t[i].lchild = t[i].rchild = 0;
        //生成n-1个非叶子节点,每次都选择已经存在的且未合并的节点中的两个最小节点
        //选出后将其合并,生成新的节点(此处当parent为0时可以代表还未合并) 
        for(int i = n+1; i <= m; i++){
            int a, b;
            min_two(t, i-1, a, b);
            //对合并的节点进行信息修改,包括权值,父节点指向,左右孩子指向 
            t[i].wt = t[a].wt + t[b].wt;
            t[i].lchild = a;
            t[i].rchild = b;
            t[a].parent = t[b].parent = i;
        }
        
        //以下进行编码操作
        //申请n个节点需要的编码串的空间,由于一个编码串可用一维指针表示
        //而n个时,便可用一个二维指针表示,它的每一维都对应一个数的编码 
        code = (char **)malloc((n+1)*sizeof(char *));
        //临时存储某个数的编码串 
        char *cd = (char *)malloc(n*sizeof(char));
        //由于是自底向上的,所以进行逆向编码,首先初始化末尾为字符串结束符 
        cd[n-1] = '\0';
        //对n个数进行编码
        for(int i = 1; i <= n; i++){
            int index = n - 1;
            //从每一个i所在的叶子节点开始向上,如果当前节点是其父节点的左孩子则添加一个0
            //否则添加1,当回溯到根结点则i所在的叶子节点编码完成 
            for(int c=i, f=t[i].parent; f != 0; c=f, f=t[f].parent){
                if(t[f].lchild == c)
                    cd[--index] = '0';
                else
                    cd[--index] = '1';
            }
            code[i] = (char*)malloc((n-index)*sizeof(char));
            //将i叶子节点的编码串赋值到code中,存储起来 
            strcpy(code[i], cd+index);
        }
        //释放空间 
        delete cd;
    }
    
    
    int main() {
        int n, a;
        while(scanf("%d", &n) != EOF){
            for(int i = 1; i <= n; i++)
                scanf("%d", &w[i]);
            hftree *ht;
            char** code;
            HuffmanCode(ht, code, w, n);
            for(int i = 1; i <= n; i++)
                printf("%s\n", code[i]);
            delete ht;
            delete code;
        }
        return 0;
    }
    
    

    相关文章

      网友评论

          本文标题:自底向上的哈夫曼编码

          本文链接:https://www.haomeiwen.com/subject/vnbkhhtx.html