数据结构C语言版之赫夫曼编码

==此博客代码思想参考了严蔚敏老师的教材,特此声明==

【说明】这里以8个叶子结点为例.HT和HC的具体转变过程见书本P149页(有些结点左右孩子的顺序稍有不同,但是不影响)

【输出】  

HT[1]:  0  0  0  1

HT[2]:  1  0

HT[3]:  1  1  1  0

HT[4]:  1  1  1  1

HT[5]:  1  1  0

HT[6]:  0  1

HT[7]:  0  0  0  0

HT[8]:  0  0  1


#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <iostream>
#include <stack>
#define MAXSIZE 1000
#define N 8
using namespace std;

typedef struct {
    unsigned int weight;
    unsigned int parent,lchild,rchild;
}HTNode,* HuffmanTree; //动态分配数组存储赫夫曼树
typedef char** HuffmanCode; //动态分配数组存储赫夫曼编码表

void HuffmanCoding(HuffmanTree& HT,HuffmanCode& HC,int* w,int n);
void Select(HuffmanTree HT,int t,int& s1,int& s2);

int main(){
    HuffmanTree HT;
    HuffmanCode HC;
    int w[N] = {5,29,7,8,14,23,3,11}; //N个叶子结点的权值
    HuffmanCoding(HT,HC,w,N);

    for(int i=1;i<=N;++i){
        printf("HT[%d]:  ",i);
        int j = 0;
        while(HC[i][j] != '\0'){
            cout<<HC[i][j]<<"  ";
            j++;
        }
        cout<<endl;
    }

    return 0;
}
//w存放n个字符的权值(均>0),构造赫夫曼数HT,并求出n个字符的赫夫曼编码HC
void HuffmanCoding(HuffmanTree& HT,HuffmanCode& HC,int* w,int n){
    if(n <= 1) return;
    int m,i;
    m = 2*n-1;
    HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));  //0号单元未用
    HuffmanTree p;
    for(p = (HT+1),i = 1;i <= n;++i,++p,++w){  //初始化前n个结点的成员值
        //*p = {*w,0,0,0};
        p->weight = *w;
        p->parent = 0;
        p->lchild = 0;
        p->rchild = 0;
    }
    for(;i <= m;++i,++p){   //初始化后2n-1-n 个结点的成员值
        //*p = {0,0,0,0};
        p->weight = 0;
        p->parent = 0;
        p->lchild = 0;
        p->rchild = 0;
    }
    for(i = n + 1;i <= m;++i){ //建立赫夫曼树
        int s1;
        int s2;
        Select(HT,i-1,s1,s2);
//        cout<<s1<<"   "<<s2<<"   "<<i<<endl;
        HT[s1].parent = i;  //将s1和s2合并成为新的一颗树i,其左子树为s1,右子树为s2,权值为两者之和
        HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight + HT[s2].weight;

//        cout<<"==================="<<endl;
//        for(int i = 1; i <= 15; i++){
//            cout<<i<<"  "<<HT[i].weight<<"  "<<HT[i].parent<<"  "<<HT[i].lchild<<"  "<<HT[i].rchild<<endl;
//        }
//        cout<<"==================="<<endl;
    }

    //----从叶子到根逆向求每一个字符的赫夫曼编码-----
    HC = (HuffmanCode)malloc((n+1)*sizeof(char*));  //分配n个字符编码的头指针向量
    char* cd = (char*)malloc(n*sizeof(char));  //分配求编码的工作空间
    cd[n-1] = '\0';   //编码结束符
    for(i = 1; i <= n; ++i){  //逐个字符求赫夫曼编码
        int start = n-1;    //编码结束符位置
        //cout<<cd[start]<<"  ";
        int c,f;
        for(c = i,f = HT[i].parent; f != 0; c = f, f = HT[f].parent){ //从叶子到根逆向求编码
            if(HT[f].lchild == c){
                cd[--start] = '0';
            }
            else {
                cd[--start] = '1';
            }

            //cout<<cd[start]<<"  ";
        }
        HC[i] = (char*)malloc((n-start)*sizeof(char)); // 为第i个字符编码分配空间
        strcpy(HC[i], &cd[start]);     //从cd复制编码(串)到HC

//        for(int j = 0; j < (n-start); j++){
//            cout<<HC[i][j]<<"  ";
//        }
//
//        cout<<endl<<"==============="<<endl;
    }
    free(cd);
}
//在HT[1...t]选择parent为0且weight最小的两个结点,其序号分别为s1和s2,规定 HT[s1].weight < HT[s2].weight
void Select(HuffmanTree HT,int t,int& s1,int& s2){
    int i;
    int flag = 0;
    for(i = 1; i <= t; i++){
        if(HT[i].parent == 0){
            if(flag < 2){
                if(flag == 0){
                    flag++;
                    s1 = i;
                }else{
                    flag++;
                    s2 = i;
                    if(HT[s1].weight > HT[s2].weight){
                        int t = s1;
                        s1 = s2;
                        s2 = t;
                    }
                }
            }else{
                if(HT[i].weight < HT[s1].weight && HT[i].weight < HT[s2].weight){
                    s2 = s1;
                    s1 = i;
                }
                else if(HT[i].weight < HT[s2].weight && HT[i].weight > HT[s1].weight){
                    s2 = i;
                }
            }
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值