哈夫曼树(Huffman Tree)

    哈夫曼树是一种特殊的二叉树,它是由美国计算机科学家David A.Huffman于1952年提出的。哈夫曼树广泛应用于数据压缩、编码等领域,因为它可以有效地减少数据的存储空间和传输时间。

一、预备知识:

1.结点的权:有某种现实含义的数值(如:表示结点的重要性等)
2.结点的带权路径长度:从树的根到该结点的路径长度(经过的边数〉与该结点上权值的乘积

3.树的带权路径长度:树中所有叶结点的带权路径长度之和(WPL, Weighted Path Length)
 

来看几个例子:

EX1:                  EX2:

EX3:                     EX4:

 在含有n个带权叶结点的二叉树中,其中带权路径长度(WPL)最小的二叉树称为哈夫曼树,也称最优二叉树.

二、哈夫曼树的构造:

给定n个权值分别为w,, w2..., w,的结点,构造哈夫曼树的算法描述如下:

1)将这n个结点分别作为n棵仅含一个结点的二叉树,构成森林F。
2)构造一个新结点,从F中选取两棵根结点权值最小的树作为新结点的左、右子树
并且将新结点的权值置为左、右子树上根结点的权值之和。
3)从F中删除刚才选出的两棵树,同时将新得到的树加入F中。

4)重复步骤2)和3),直至F中只剩下一棵树为止。
 

step1:    

step2:    

step3:    

tips:

 1)每个初始结点最终都成为叶结点,且权值越小的结点到根结点的路径长度越大

2)哈夫曼树的结点总数为2n -1
3)哈夫曼树中不存在度为1的结点。
4)哈夫曼树并不唯一,但WPL必然相同且为最优

还可以如下构造:

step1:    

step2:    

step3:    

 

 三、哈夫曼编码:

    哈夫曼编码是一种用于数据压缩的算法,它通过将频繁出现的字符用较短的二进制码表示,而将较少出现的字符用较长的二进制码表示,从而实现数据的压缩。
 

固定长度编码――每个字符用相等长度的二进制位表示

可变长度编码――允许对不同字符用不等长的二进制位表示
若没有一个编码是另一个编码的前缀,则称这样的编码为前缀编码
有哈夫曼树得到哈夫曼编码――字符集中的每个字符作为一个叶子结点,各个字符出现的频度作为结点的权值,根据之前介绍的方法构造哈夫曼树
 

相关代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node {
    char data; // 字符
    int weight; // 权值
    struct Node *left, *right; // 左右子节点
} Node;

// 创建新节点
Node* createNode(char data, int weight) {
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = data;
    node->weight = weight;
    node->left = node->right = NULL;
    return node;
}

// 构建哈夫曼树
Node* buildHuffmanTree(char *data, int *weight, int size) {
    Node **nodes = (Node **)malloc(size * sizeof(Node *));
    for (int i = 0; i < size; i++) {
        nodes[i] = createNode(data[i], weight[i]);
    }
    while (size > 1) {
        int min1 = -1, min2 = -1;
        for (int i = 0; i < size; i++) {
            if (min1 == -1 || nodes[i]->weight < nodes[min1]->weight) {
                min2 = min1;
                min1 = i;
            } else if (min2 == -1 || nodes[i]->weight < nodes[min2]->weight) {
                min2 = i;
            }
        }
        Node *newNode = createNode('\0', nodes[min1]->weight + nodes[min2]->weight);
        newNode->left = nodes[min1];
        newNode->right = nodes[min2];
        nodes[min1] = newNode;
        nodes[min2] = nodes[size - 1];
        size--;
    }
    return nodes[0];
}

// 生成哈夫曼编码
void generateHuffmanCode(Node *root, char *code, int depth) {
    if (root == NULL) {
        return;
    }
    if (root->left == NULL && root->right == NULL) {
        printf("%c: %s
", root->data, code);
    }
    char leftCode[100], rightCode[100];
    strcpy(leftCode, code);
    strcat(leftCode, "0");
    strcpy(rightCode, code);
    strcat(rightCode, "1");
    generateHuffmanCode(root->left, leftCode, depth + 1);
    generateHuffmanCode(root->right, rightCode, depth + 1);
}

// 解码哈夫曼编码
void decodeHuffmanCode(Node *root, char *code) {
    Node *cur = root;
    while (*code != '\0') {
        if (*code == '0') {
            cur = cur->left;
        } else {
            cur = cur->right;
        }
        if (cur->left == NULL && cur->right == NULL) {
            printf("%c", cur->data);
            cur = root;
        }
        code++;
    }
    printf("
");
}

int main() {
    char data[] = {'A', 'B', 'C', 'D'};
    int weight[] = {8, 3, 3, 6};
    int size = sizeof(data) / sizeof(data[0]);
    Node *root = buildHuffmanTree(data, weight, size);
    printf("Huffman Code:
");
    generateHuffmanCode(root, "", 0);
    printf("Decode: ");
    decodeHuffmanCode(root, "1001011"); // 输出:ABCD
    return 0;
}

 

 

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C语言实现哈夫曼编码的代码,其中包含注释: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 1000 // 定义最大编码长度 typedef struct { int weight; // 权值 int parent, lchild, rchild; // 双亲和左右孩子结点 } HTNode, *HuffmanTree; typedef char **HuffmanCode; void Select(HuffmanTree HT, int n, int *s1, int *s2) { // 在前n个结点中选择权值最小的两个结点s1和s2 int i, min; for (i = 1; i <= n; i++) { if (HT[i].parent == 0) { min = i; break; } } for (i = 1; i <= n; i++) { if (HT[i].parent == 0 && HT[i].weight < HT[min].weight) { min = i; } } *s1 = min; for (i = 1; i <= n; i++) { if (HT[i].parent == 0 && i != *s1) { min = i; break; } } for (i = 1; i <= n; i++) { if (HT[i].parent == 0 && HT[i].weight < HT[min].weight && i != *s1) { min = i; } } *s2 = min; } void CreateHuffmanTree(HuffmanTree *HT, int n) { // 由n个权值为w的结点构建哈夫曼树HT if (n <= 1) { return; } int m = 2 * n - 1; *HT = (HuffmanTree) malloc((m + 1) * sizeof(HTNode)); int i; for (i = 1; i <= m; i++) { (*HT)[i].parent = 0; (*HT)[i].lchild = 0; (*HT)[i].rchild = 0; } for (i = 1; i <= n; i++) { scanf("%d", &((*HT)[i].weight)); } int s1, s2; for (i = n + 1; i <= m; i++) { Select(*HT, i - 1, &s1, &s2); (*HT)[s1].parent = i; (*HT)[s2].parent = i; (*HT)[i].lchild = s1; (*HT)[i].rchild = s2; (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight; } } void CreateHuffmanCode(HuffmanTree HT, HuffmanCode *HC, int n) { // 根据哈夫曼树HT求出n个字符的哈夫曼编码HC *HC = (HuffmanCode) malloc((n + 1) * sizeof(char *)); char *cd = (char *) malloc(n * sizeof(char)); cd[n - 1] = '\0'; int i, c, f; for (i = 1; i <= n; i++) { int start = n - 1; 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'; } } (*HC)[i] = (char *) malloc((n - start) * sizeof(char)); strcpy((*HC)[i], &cd[start]); } free(cd); } void HuffmanCoding(HuffmanTree HT, HuffmanCode HC, int n) { // 输入n个字符的权值,建立哈夫曼树HT,并求出n个字符的哈夫曼编码HC CreateHuffmanTree(&HT, n); CreateHuffmanCode(HT, &HC, n); } void HuffmanDecoding(HuffmanTree HT, int n) { // 将01序列翻译成原来的文本字符 printf("请输入01序列:\n"); char str[MAX]; scanf("%s", str); int i, c = 2 * n - 1; for (i = 0; str[i] != '\0'; i++) { if (str[i] == '0') { c = HT[c].lchild; } else { c = HT[c].rchild; } if (HT[c].lchild == 0 && HT[c].rchild == 0) { printf("%d", c); c = 2 * n - 1; } } } int main() { int n; printf("请输入字符的个数n:\n"); scanf("%d", &n); HuffmanTree HT; HuffmanCode HC; HuffmanCoding(HT, HC, n); int i; printf("各字符的哈夫曼编码如下:\n"); for (i = 1; i <= n; i++) { printf("%d %s\n", i, HC[i]); } HuffmanDecoding(HT, n); return 0; } ``` 以上是C语言实现哈夫曼编码的代码,可以根据输入的字符权值构建哈夫曼树,并输出各字符对应的哈夫曼编码。同时,可以将传输的文本转换成对应的哈夫曼编码01序列,并将哈夫曼编码01序列翻译成原来的文本字符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值