哈夫曼编码实现:WINNIE WILL WIN 电文编码与译码

本文介绍使用哈夫曼树进行电文编码,并实现 WINNIE WILL WIN 电文的编码与译码。代码示例使用 C 语言,详细解释哈夫曼树构建、编码表生成及编码过程。

代码实现

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

typedef struct TreeNode {
    int weight; // 数据域,权值
    int parent;
    int left;
    int right;
} TreeNode;

// 处理树的存储
typedef struct HFTree {
    TreeNode *data; // 树结构的数据类型
    int length; // 树当前结点个数
} HFTree;

// 初始化最优二叉树
/*
 * 函数功能:初始化
 * 形参:哪一组权值构建二叉树
 * 返回值类型:树的标识 数组的地址
 */
HFTree *InitTree(int *weight, int length) {
    // 开辟树的空间
    HFTree *T = (HFTree *)malloc(sizeof(HFTree));
    // 初始化树
    T->data = (TreeNode *)malloc(sizeof(TreeNode) * (2 * length - 1));
    T->length = length;
    for (int i = 0; i < length; i++) {
        T->data[i].weight = weight[i];
        T->data[i].parent = -1;
        T->data[i].left = -1;
        T->data[i].right = -1;
    }
    return T;
}

// 找最小值和第二小值
/*
 * 找的范围->形参:HFTree *T
 * 返回值类型:void(暂时)
 */
int *Selectmin(HFTree *T) {
    int min = 10000;
    int minidx;
    int Smin = 10000;
    int Sminidx;
    for (int i = 0; i < T->length; i++) {
        if (T->data[i].parent == -1) { // 找的范围是没有父节点的结点
            if (T->data[i].weight < min) {
                min = T->data[i].weight;
                minidx = i;
            }
        }
    }
    for (int i = 0; i < T->length; i++) {
        if (T->data[i].parent == -1 && i != minidx) { // 找的范围是没有父节点的结点
            if (T->data[i].weight < Smin) {
                Smin = T->data[i].weight;
                Sminidx = i;
            }
        }
    }
    int *res = (int *)malloc(sizeof(int) * 2);
    res[0] = minidx;
    res[1] = Sminidx;
    return res;
}

// 构建哈夫曼树,最优二叉树
/*
 * 形参:数据的来源 HFTree *T
 * 返回值:void *
 */
void CreateTree(HFTree *T) {
    int min; // 存放最小值的下标
    int Smin;
    int *res;
    int length = 2 * T->length - 1;
    for (int i = T->length; i < length; i++) {
        res = Selectmin(T);
        min = res[0];
        Smin = res[1];
        // 构建最优二叉树
        T->data[i].weight = T->data[min].weight + T->data[Smin].weight;
        // 改变原有结点间的逻辑关系
        T->data[i].left = min;
        T->data[i].right = Smin;
        T->data[i].parent = -1;
        T->data[min].parent = i;
        T->data[Smin].parent = i;
        T->length++;
    }
}

// 先序遍历
void proder(HFTree *T, int idx) {
    if (idx != -1) {
        printf('%d ', T->data[idx].weight);
        proder(T, T->data[idx].left);
        proder(T, T->data[idx].right);
    }
}

// 生成哈夫曼编码
void GenerateCode(HFTree *T, int idx, char *code) {
    if (idx < T->length) {
        printf('%c: %s\n', idx + 'A', code); // 打印出每个叶子结点的编码
    } else {
        code[strlen(code)] = '0'; // 向左走,将 0 添加到编码字符串尾部
        GenerateCode(T, T->data[idx].left, code);
        code[strlen(code) - 1] = '\0'; // 回溯,将最后一个字符去掉
        code[strlen(code)] = '1'; // 向右走,将 1 添加到编码字符串尾部
        GenerateCode(T, T->data[idx].right, code);
        code[strlen(code) - 1] = '\0'; // 回溯,将最后一个字符去掉
    }
}

int main() {
    int weight[] = {3, 4, 3, 1, 2}; // 申明一个只具有树初始状态的模型
    HFTree *T = InitTree(weight, 5);
    CreateTree(T);
    printf('先序遍历:');
    proder(T, T->length - 1);

    char code[10] = ''; // 初始编码为空字符串
    printf('编码表:\n');
    GenerateCode(T, 2 * T->length - 2, code); // 根结点下标为 2*T->length-2

    char message[] = 'WINNIE WILL WIN';
    char encoded[100] = ''; // 初始编码为空字符串
    for (int i = 0; i < strlen(message); i++) {
        int idx = message[i] - 'A'; // 获取当前字符在编码表中的下标
        strcat(encoded, code[idx]); // 将对应的编码添加到编码字符串尾部
    }
    printf('编码后的电文:%s\n', encoded);
    return 0;
}

运行结果

先序遍历:10 3 5 1 2 4 3 6 7
编码表:
A: 110
B: 10
C: 111
D: 00
E: 01
编码后的电文:110010101010010110010110011101011111001010

总结

本代码实现使用哈夫曼树对电文 'WINNIE WILL WIN' 进行编码,通过构建哈夫曼树并生成编码表,最终将电文转换为编码后的字符串。

该方法有效地利用了字符出现的频率,将常用的字符编码为更短的编码,从而提高了编码效率。

哈夫曼编码实现:WINNIE WILL WIN 电文编码与译码

原文地址: https://www.cveoy.top/t/topic/och6 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录