用C语言实现哈夫曼编码

本文详细介绍了如何使用C语言编写程序来构建哈夫曼树,通过字符频率计算生成哈夫曼编码,以实现数据压缩。程序包括定义哈夫曼树节点、优先队列节点以及创建、操作哈夫曼树和打印编码的函数。
摘要由CSDN通过智能技术生成

创作灵感: 哈夫曼编码是一种用于数据压缩的常用技术,它可以将字符集中的字符映射到不同长度的二进制编码,以实现高效的数据压缩。本文将介绍一个用C语言编写的程序,演示如何构建哈夫曼树并生成字符的哈夫曼编码。通过这个程序,我们可以学习哈夫曼编码的基本原理以及如何在C语言中实现。

技术笔记要点: 这个C语言程序包括了以下关键部分:

  1. 定义了哈夫曼树节点(Node)结构体,用于表示字符和频率,以及左右子树的指针。
  2. 定义了优先队列节点(QueueNode)结构体,用于构建优先队列,其中包含了指向哈夫曼树节点的指针和下一个节点的指针。
  3. 定义了哈夫曼树(HuffmanTree)结构体,包含指向根节点的指针。
  4. 实现了创建节点和队列节点的函数,以及创建和操作优先队列的函数。
  5. 使用优先队列构建哈夫曼树的函数createHuffmanTree,该函数接受字符集、频率和大小作为输入,并返回一个哈夫曼树。
  6. 实现了打印哈夫曼编码的函数printHuffmanCodes,该函数采用递归方式遍历哈夫曼树,生成字符的哈夫曼编码,并输出结果。

在主函数main中,程序首先获取用户输入的字符集和频率信息,并使用createHuffmanTree函数构建哈夫曼树。然后,使用printHuffmanCodes函数生成并打印字符的哈夫曼编码。

#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,例如内存分配函数
#include <string.h> // 引入字符串操作函数库

// 哈夫曼树节点
typedef struct Node {
    char symbol; // 存储字符
    int freq; // 存储字符出现的频率
    struct Node *left, *right; // 指向左右子树的指针
} Node;

// 优先队列节点
typedef struct QueueNode {
    Node *treeNode; // 哈夫曼树结点
    struct QueueNode *next; // 指向下一个节点的指针
} QueueNode;

// 哈夫曼树
typedef struct {
    Node *root; // 指向哈夫曼树的根的指针
} HuffmanTree;

// 优先队列
typedef struct {
    QueueNode *first; // 指向队列中的第一个节点的指针
    int size; // 队列的大小
} PriorityQueue;

Node* createNode(char symbol, int freq, Node *left, Node *right) {
    Node* node = (Node*)malloc(sizeof(Node)); // 为新的哈夫曼树节点分配内存
    node->symbol = symbol; // 设置节点的字符
    node->freq = freq; // 设置节点字符的频率
    node->left = left; // 设置左子树的指针
    node->right = right; // 设置右子树的指针
    return node; // 返回新创建的节点的指针
}

QueueNode* createQueueNode(Node *treeNode) {
    QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode)); // 为新队列节点分配内存
    node->treeNode = treeNode; // 设置哈夫曼树节点
    node->next = NULL; // 初始化下一个队列节点的指针
    return node; // 返回新创建的队列节点
}

PriorityQueue createPriorityQueue() {
    PriorityQueue pq; // 创建一个优先队列结构体变量
    pq.first = NULL; // 初始化第一个节点的指针
    pq.size = 0; // 初始化队列的大小
    return pq; // 返回新创建的优先队列
}

void insertPriorityQueue(PriorityQueue *pq, Node *treeNode) {
    QueueNode* newNode = createQueueNode(treeNode); // 创建新的优先队列节点
    if (pq->size == 0) { // 如果队列大小为0
        pq->first = newNode; // 设置新节点为队列的首个节点
    } else {
        QueueNode *temp = pq->first;
        while (temp->next != NULL && temp->next->treeNode->freq < treeNode->freq) {
            temp = temp->next; // 找到合适的插入位置
        }
        newNode->next = temp->next; 
        temp->next = newNode; // 插入新的节点
    }
    pq->size++; // 增加队列的大小
}

Node* dequeuePriorityQueue(PriorityQueue *pq) {
    QueueNode *oldFirst = pq->first; // 记住优先队列的头部节点
    Node *treeNode = NULL; // 初始化 treeNode
    if (oldFirst != NULL) { // 如果队列不为空
        treeNode = oldFirst->treeNode; // 提取哈夫曼树节点
        pq->first = oldFirst->next; // 更改队列头部为下一个节点
        free(oldFirst); // 释放旧的头部节点的内存
        pq->size--; // 减少队列的大小
    }
    return treeNode; // 返回被提取的哈夫曼树节点
}

HuffmanTree createHuffmanTree(char symbols[], int freq[], int size) {
    PriorityQueue pq = createPriorityQueue(); // 创建优先权队列
    Node *treeNode;

    for (int i = 0; i < size; i++) { // 对每个字符
        if (freq[i] > 0) { // 如果它在输入中存在(频率大于0)
            treeNode = createNode(symbols[i], freq[i], NULL, NULL); // 创建一个新的节点
            insertPriorityQueue(&pq, treeNode); // 插入优先队列
        }
    }

    while (pq.size > 1) { // 当优先权队列中有一个以上的节点
        Node *left = dequeuePriorityQueue(&pq); // 取出优先权最高的节点作为左子树
        Node *right = dequeuePriorityQueue(&pq); // 再取出优先权第二高的节点作为右子树
        treeNode = createNode('\0', left->freq + right->freq, left, right); // 创建一个新节点
        insertPriorityQueue(&pq, treeNode); // 把新的节点插入优先权队列
    }

    HuffmanTree ht;
    ht.root = dequeuePriorityQueue(&pq); // 最后剩下的节点就是哈夫曼树的根节点
    return ht; // 返回哈夫曼树
}

void printHuffmanCodes(Node *root, char *str, int top) {
    if (root->left) { // 如果有左子树
        str[top] = '0'; // 在编码中加入0
        printHuffmanCodes(root->left, str, top + 1); // 递归处理左子树
    }
    if (root->right) { // 如果有右子树
        str[top] = '1'; // 在编码中加入1
        printHuffmanCodes(root->right, str, top + 1); // 递归处理右子树
    }
    if (!(root->left) && !(root->right)) { // 如果是叶子节点(没有子树)
        str[top] = '\0'; // 结束编码字符串
        printf("%c:%s\n", root->symbol, str); // 输出字符及其哈夫曼编码
    }
}

int main() {
    int n;
    printf("请输入字符集的字符内容,每个元素以空格隔开:"); // 询问用户输入
    char line[1000];
    fgets(line, sizeof(line), stdin); // 获取用户输入
    char *ptr = strtok(line, " ");
    char symbols[100];
    int i = 0;
    while (ptr != NULL) { // 使用空格分割符号
        symbols[i++] = ptr[0];
        ptr = strtok(NULL, " "); // 继续处理下一个符号
    }
    n = i; // 计算符号总数
    
    printf("各个字符对应的出现次数为:"); // 询问出现频次
    int freq[100];
    for (i = 0; i < n; i++) { //对于每个符号
        scanf("%d", &freq[i]); // 读取频次
    }
    getchar();  // 清除后面的 '\n'

    HuffmanTree ht = createHuffmanTree(symbols, freq, n); // 创建哈夫曼树

    printf("各字符的哈夫曼编码是:\n"); // 输出哈夫曼编码
    char str[1000];
    printHuffmanCodes(ht.root, str, 0);

    return 0; // 返回,表示程序正常退出
}

 

 

 

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈夫曼编码是一种用于数据压缩的算法。下面是C语言实现哈夫曼编码的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_NODE_NUM 1000 typedef struct { int weight; int parent, lchild, rchild; } HuffmanNode; typedef struct { int bit[MAX_NODE_NUM]; int start; } HuffmanCode; void HuffmanCoding(HuffmanNode *huffmanTree, HuffmanCode *huffmanCode, int n) { int i, j, parent, left, right; for (i = 0; i < n; i++) { huffmanTree[i].parent = -1; huffmanTree[i].lchild = -1; huffmanTree[i].rchild = -1; } for (i = 0; i < n-1; i++) { int min1 = MAX_NODE_NUM, min2 = MAX_NODE_NUM; left = right = -1; for (j = 0; j < n+i; j++) { if (huffmanTree[j].parent == -1 && huffmanTree[j].weight < min1) { min2 = min1; right = left; min1 = huffmanTree[j].weight; left = j; } else if (huffmanTree[j].parent == -1 && huffmanTree[j].weight < min2) { min2 = huffmanTree[j].weight; right = j; } } huffmanTree[left].parent = n + i; huffmanTree[right].parent = n + i; huffmanTree[n + i].lchild = left; huffmanTree[n + i].rchild = right; huffmanTree[n + i].weight = min1 + min2; } for (i = 0; i < n; i++) { HuffmanCode *code = &huffmanCode[i]; code->start = n - 1; parent = huffmanTree[i].parent; while (parent != -1) { if (huffmanTree[parent].lchild == i) { code->bit[code->start] = 0; } else { code->bit[code->start] = 1; } code->start--; i = parent; parent = huffmanTree[parent].parent; } } } int main() { int i, n; HuffmanNode huffmanTree[MAX_NODE_NUM]; HuffmanCode huffmanCode[MAX_NODE_NUM]; printf("请输入叶子结点的个数:"); scanf("%d", &n); printf("请输入每个叶子结点的权重:"); for (i = 0; i < n; i++) { scanf("%d", &huffmanTree[i].weight); } HuffmanCoding(huffmanTree, huffmanCode, n); printf("哈夫曼编码表:\n"); for (i = 0; i < n; i++) { printf("结点%d的哈夫曼编码为:", i); int j; for (j = huffmanCode[i].start + 1; j < n; j++) { printf("%d", huffmanCode[i].bit[j]); } printf("\n"); } return 0; } ``` 该代码中定义了两个结构体:`HuffmanNode`表示哈夫曼树中的结点,包括权值、父结点、左孩子和右孩子;`HuffmanCode`表示哈夫曼编码,包括二进制位以及起始位置。 在`HuffmanCoding`函数中,首先初始化哈夫曼树的每个结点,然后依次求出每个非叶子结点,直到只剩下一个根结点。接着遍历每个叶子结点,求出其哈夫曼编码。最后输出哈夫曼编码表。 在主函数中,首先输入叶子结点的个数和权重,然后调用`HuffmanCoding`函数求出哈夫曼编码,最后输出哈夫曼编码表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值