数据结构与C

数据结构与C 知识量:8 - 24 - 99

5.6 最优二叉树><

哈夫曼树- 5.6.1 -

哈夫曼树(Huffman Tree),又称最优二叉树,是一种带权路径长度最短的树。树的路径长度:从树根到树中每一个节点的路径长度之和。结点之间的路径长度:从一个结点到另一个结点之间的分支数目。结点的带权路径长度:从该结点到树根之间的路径长度与节点上权的乘积。树的带权路径长度:Weighted Path Length of Tree,简称为WPL,树中所有叶子结点的带权路径长度之和,记作: WPL最小的二叉树就称作最有二叉树或哈夫曼树。

哈夫曼树的构造过程如下:

  1. 给定n个带有权值的结点,组成一个结点集合M;

  2. 从集合M中选出权值最小的两个结点A,B,权值分别为,构造一棵二叉树T,T的根结点C权值为;

  3. 删除结点A、B,将结点C加入到集合M中;

  4. 重复步骤2和3,直至M中只剩下一个结点为止。

哈夫曼树是一种优化后的二叉树结构,它在数据压缩等领域有广泛的应用。

哈夫曼树的构造算法- 5.6.2 -

以下是使用C语言实现哈夫曼树的构造算法的示例代码:

#include <stdio.h>  
#include <stdlib.h>  
  
// 定义二叉树结构体  
struct TreeNode {  
    int val;  
    struct TreeNode *left;  
    struct TreeNode *right;  
};  
  
// 定义比较函数,用于选取权值最小的两棵树  
int cmp(const void *a, const void *b) {  
    return (*(struct TreeNode*)a)->val - (*(struct TreeNode*)b)->val;  
}  
  
// 构造哈夫曼树  
struct TreeNode* buildHuffmanTree(int weights[], int n) {  
    // 构造n棵二叉树的森林  
    struct TreeNode **trees = (struct TreeNode**)malloc(n * sizeof(struct TreeNode*));  
    for (int i = 0; i < n; i++) {  
        trees[i] = (struct TreeNode*)malloc(sizeof(struct TreeNode));  
        trees[i]->val = weights[i];  
        trees[i]->left = NULL;  
        trees[i]->right = NULL;  
    }  
    // 选取权值最小的两棵树,构造新的二叉树,并更新森林  
    while (n > 1) {  
        int *temp = (int*)malloc(2 * sizeof(int));  
        for (int i = 0; i < 2; i++) {  
            temp[i] = trees[i]->val;  
        }  
        qsort(temp, 2, sizeof(int), cmp);  
        struct TreeNode *newTree = (struct TreeNode*)malloc(sizeof(struct TreeNode));  
        newTree->val = temp[0] + temp[1];  
        newTree->left = trees[temp[0]];  
        newTree->right = trees[temp[1]];  
        trees[temp[0]] = NULL;  
        trees[temp[1]] = NULL;  
        n--;  
        trees = (struct TreeNode**)realloc(trees, n * sizeof(struct TreeNode*));  
        trees[n] = newTree;  
    }  
    // 返回哈夫曼树的根节点  
    return trees[0];  
}

哈夫曼编码- 5.6.3 -

哈夫曼编码(Huffman Coding)是一种可变长度编码方法,它根据字符出现的概率来构造异字头的平均长度最短的码字。哈夫曼编码是一种前缀编码,即没有任何字符的编码是其他字符编码的前缀。

哈夫曼编码的原理是:首先,将待编码的字符按照其出现的概率由大到小排序;然后,从概率最小的两个字符开始,可选其中一个支路为0,另一支路为1,将已编码的两支路的概率合并,并重新排队;接着,重复上述步骤,直到合并概率归一时为止。这样得到的码字即为哈夫曼编码。

哈夫曼编码是一种高效的编码方法,其编码长度接近于最佳编码长度。在实际应用中,哈夫曼编码被广泛应用于数据压缩等领域。

哈夫曼编码的算法实现- 5.6.4 -

以下是使用C语言实现哈夫曼编码的算法示例:

#include <stdio.h>  
#include <stdlib.h>  
  
// 定义二叉树结构体  
struct TreeNode {  
    int val;  
    int freq;  
    struct TreeNode *left;  
    struct TreeNode *right;  
};  
  
// 构造二叉树  
struct TreeNode* createTreeNode(int val, int freq) {  
    struct TreeNode *node = (struct TreeNode*)malloc(sizeof(struct TreeNode));  
    node->val = val;  
    node->freq = freq;  
    node->left = NULL;  
    node->right = NULL;  
    return node;  
}  
  
// 构建哈夫曼树  
struct TreeNode* buildHuffmanTree(int weights[], int n) {  
    // 构造n棵二叉树的森林  
    struct TreeNode **trees = (struct TreeNode**)malloc(n * sizeof(struct TreeNode*));  
    for (int i = 0; i < n; i++) {  
        trees[i] = createTreeNode(weights[i], 1);  
    }  
    // 选取权值最小的两棵树,构造新的二叉树,并更新森林  
    while (n > 1) {  
        struct TreeNode **temp = (struct TreeNode**)malloc(2 * sizeof(struct TreeNode*));  
        temp[0] = trees[0];  
        temp[1] = trees[1];  
        int freq[2] = {temp[0]->freq, temp[1]->freq};  
        qsort(temp, 2, sizeof(struct TreeNode*), (int(*)(const void*, const void*))cmp);  
        qsort(freq, 2, sizeof(int), cmp);  
        struct TreeNode *newTree = createTreeNode(freq[0] + freq[1], 0);  
        newTree->left = temp[0];  
        newTree->right = temp[1];  
        trees[0] = NULL;  
        trees[1] = NULL;  
        n--;  
        trees = (struct TreeNode**)realloc(trees, n * sizeof(struct TreeNode*));  
        trees[n] = newTree;  
    }  
    // 返回哈夫曼树的根节点  
    return trees[0];  
}  
  
// 比较函数,用于选取权值最小的两棵树  
int cmp(const void *a, const void *b) {  
    return ((struct TreeNode*)a)->freq - ((struct TreeNode*)b)->freq;  
}  
  
// 打印哈夫曼编码树(前序遍历)  
void printHuffmanTree(struct TreeNode *root, int depth) {  
    if (root == NULL) {  
        return;  
    }  
    for (int i = 0; i < depth; i++) {  
        printf("\t");  
    }  
    printf("%d(%d)\n", root->val, root->freq);  
    printHuffmanTree(root->left, depth + 1);  
    printHuffmanTree(root->right, depth + 1);  
}