哈夫曼编码(数组,递归版)

前缀编码

每个字符的编码都不是另一个的前缀

比如:A: 01 B: 010这样就不行,如果是AABB字符集时,编出来的码是0101010,可能翻译成AAA

哈夫曼编码

哈夫曼树的特性非常适合前缀编码

因为字符集中的字符只会出现在树的叶子节点

树从上往下左按0右1读,只有当前节点的母节点会是它的前缀叶子节点之间不可能是谁的母节点

且哈夫曼树带权路径最小

思路

按权值构建哈夫曼树,字符权值长度为n,哈夫曼树节点数为2n-1。

创建一个长度为2n-1的数组,把原有的权值填到数组中,数组的长度设为n

w[]={7,9,6,12,35,1,2,6,47};

hf[]={7,9,6,12,35,1,2,6,47,0,0,....};

找出两个最小权值,相加赋值给到hf[n],并设置子节点为这两个最小权值的下标,相应的这两个权值的母节点为n,n+1,给一个标志表示这两数比较过,下次递归将不再比较。递归重复此操作直到n+1大于2n-1;

然后遍历所有叶子节点,依次从下往上读,读到根节点,左为0,右为1

代码

构建哈弗曼树

typedef struct Huffman {
    int w;
    int flag;//判断是否比较过
    int code[10];//伪码
    int k;//码长
    int lchild,rchild,parent;
}HuffmanNode;
typedef struct HuffmanT {
    HuffmanNode *hn;
    int len;
}HuffmanTree;

//初始化哈夫曼树
int init_HuffmanTree(HuffmanTree* root, int w[], int n) {
    root->hn = (HuffmanNode*)malloc(sizeof(HuffmanNode) * (2*n-1));
    if (root->hn == NULL) return 0;
    root->len = n;
    for (int i = 0; i < n; i++)
    {
        root->hn[i].w = w[i];
        root->hn[i].parent = -1;
        root->hn[i].flag = 0;
    }
    return 1;
}
//创建哈夫曼数
int creat_HuffmanTree(HuffmanTree *root,int n) {
    //最小数下标
    int min1 = 0, min2 = 0;
    //找两个最小的数
    for (int i = 0; i < n; i++)
    {
        if (root->hn[min1].flag == 1) min1++;
        if (root->hn[i].flag==0&&root->hn[min1].flag==0&&min1!=i) {
            if (root->hn[min1].w >= root->hn[i].w) min1 = i;
        }
    }
    root->hn[min1].flag = 1;
    for (int i = 0; i < n; i++)
    {
        if (root->hn[min2].flag == 1) min2++;
        if (root->hn[i].flag == 0 && root->hn[min2].flag == 0 && min2 != i) {
            if (root->hn[min2].w >= root->hn[i].w) min2 = i;
        }
    }
    root->hn[min2].flag = 1;
    //构建树
    root->hn[n].lchild = min1;
    root->hn[n].rchild = min2;
    root->hn[n].flag = 0;
    root->hn[n].parent = -1;
    root->hn[n].w = root->hn[min2].w + root->hn[min1].w;
    root->hn[min2].parent = root->hn[min1].parent = n;
    n = n + 1;

    //递归
    if (n < (root->len * 2) - 1) creat_HuffmanTree(root, n);

    return 1;    
}

 编码和读码

//生成码
void creat_HuffmanCode(HuffmanTree* root,int n) {
    int i,k;
    for (int j = 0; j < n; j++)
    {
        i = j;
        k = 0;
        while (i < 2*n-2) {
            if (root->hn[i].parent!=-1) {
                if (root->hn[root->hn[i].parent].lchild == i) {
                    root->hn[j].code[k] = 0;
                    k++;
                    i = root->hn[i].parent;
                }
                if (root->hn[root->hn[i].parent].rchild == i) {
                    root->hn[j].code[k] = 1;
                    k++;
                    i = root->hn[i].parent;
                }
            }
            
        }
        root->hn[j].k = k;
    }
}
//查看码
void look_Code(HuffmanNode hd[],int n) {
    for (int i = 0; i < n; i++)
    {
        printf("%d 的码为:",hd[i].w);
        for (int k = hd[i].k-1; k >= 0; k--)
        {
            printf("%d",hd[i].code[k]);
        }
        printf("\n");
    }
}

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是递归生成哈夫曼编码的C语言代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_TREE_HT 100 // 哈夫曼树结点 struct HuffmanNode { char data; // 数据 int freq; // 频率 struct HuffmanNode *left, *right; // 左右子树 }; // 哈夫曼编码表 struct HuffmanCode { char data; // 数据 char bits[MAX_TREE_HT]; // 编码 }; // 建立哈夫曼树 struct HuffmanNode* build_huffman_tree(char data[], int freq[], int n) { struct HuffmanNode *left, *right, *parent; int i; struct HuffmanNode *nodes[n]; for (i = 0; i < n; i++) { nodes[i] = (struct HuffmanNode*) malloc(sizeof(struct HuffmanNode)); nodes[i]->data = data[i]; nodes[i]->freq = freq[i]; nodes[i]->left = NULL; nodes[i]->right = NULL; } while (n > 1) { // 找到频率最小的两个结点 left = nodes[n - 1]; right = nodes[n - 2]; // 创建新结点作为它们的父结点 parent = (struct HuffmanNode*) malloc(sizeof(struct HuffmanNode)); parent->data = '\0'; parent->freq = left->freq + right->freq; parent->left = left; parent->right = right; // 将新结点插入结点数组中,并按照频率从小到大排序 nodes[n - 2] = parent; n--; for (i = n - 2; i >= 0; i--) { if (nodes[i]->freq > parent->freq) { nodes[i + 1] = nodes[i]; } else { break; } } nodes[i + 1] = parent; n++; } return nodes[0]; // 返回根结点 } // 生成哈夫曼编码表 void build_huffman_table(struct HuffmanNode* root, char *bits, int len, struct HuffmanCode huffman_table[]) { if (root->left == NULL && root->right == NULL) { int i; for (i = 0; i < len; i++) { huffman_table[(int) root->data].bits[i] = bits[i]; } huffman_table[(int) root->data].bits[len] = '\0'; huffman_table[(int) root->data].data = root->data; } else { bits[len] = '0'; build_huffman_table(root->left, bits, len + 1, huffman_table); bits[len] = '1'; build_huffman_table(root->right, bits, len + 1, huffman_table); } } int main() { char data[] = {'a', 'b', 'c', 'd'}; int freq[] = {4, 2, 1, 3}; int n = sizeof(data) / sizeof(data[0]); // 建立哈夫曼树 struct HuffmanNode* root = build_huffman_tree(data, freq, n); // 生成哈夫曼编码表 struct HuffmanCode huffman_table[256]; char bits[MAX_TREE_HT]; build_huffman_table(root, bits, 0, huffman_table); // 输出编码表 int i; for (i = 0; i < 256; i++) { if (huffman_table[i].bits[0] != '\0') { printf("%c: %s\n", huffman_table[i].data, huffman_table[i].bits); } } return 0; } ``` 在这个实现中,我们使用了结构体来表示哈夫曼树结点和哈夫曼编码表。递归生成哈夫曼编码表的函数build_huffman_table采用了类似树的前序遍历的方式,对于当前遍历到的结点,如果它是叶子结点,则将其对应的编码存入哈夫曼编码表中;如果不是叶子结点,则分别遍历它的左右子树,并将当前比特位的值分别设置为0和1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值