求解哈夫曼树HuffmanTree以及C语言实现

哈夫曼树的实现思想是基于贪心算法。哈夫曼树的构建过程基于字符出现的频率或权重。在压缩数据时,出现频率较高的字符被编码为较短的二进制码,而出现频率较低的字符则被编码为较长的二进制码,以达到压缩数据的目的。
求解步骤: 创建一个优先队列(最小堆),用于存储待构建哈夫曼树的节点。对于每个字符,创建一个节点,并将该节点插入到优先队列中。节点的频率可以是字符在文本中出现的次数或者其他预定义的权重。从优先队列中提取出两个频率最小的节点作为左右子节点,并创建一个新节点作为它们的父节点。新节点的频率是左右子节点频率之和。将新节点插入优先队列中。重复上述操作,直到优先队列中只剩下一个节点,即根节点。

代码示例: Node表示哈夫曼树的节点,包含字符数据、频率和左右子节点指针;PriorityQueue表示优先队列,用于构建哈夫曼树,包含队列的大小、容量和节点指针数组。

c 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义哈夫曼树的节点结构
struct Node {
    char data;           // 节点存储的字符数据
    int freq;            // 节点对应字符的频率
    struct Node* left;   // 左子节点指针
    struct Node* right;  // 右子节点指针
};

// 定义优先队列结构,用于构建哈夫曼树
struct PriorityQueue {
    int size;               // 当前队列中的节点个数
    int capacity;           // 队列的最大容量
    struct Node** nodes;    // 节点指针数组
};

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

// 创建优先队列
struct PriorityQueue* createPriorityQueue(int capacity) {
    struct PriorityQueue* queue = (struct PriorityQueue*)malloc(sizeof(struct PriorityQueue));
    queue->size = 0;
    queue->capacity = capacity;
    queue->nodes = (struct Node**)malloc(capacity * sizeof(struct Node*));
    return queue;
}

// 交换两个节点的位置
void swap(struct Node** a, struct Node** b) {
    struct Node* temp = *a;
    *a = *b;
    *b = temp;
}

// 最小堆调整
void minHeapify(struct PriorityQueue* queue, int idx) {
    int smallest = idx;
    int left = 2 * idx + 1;
    int right = 2 * idx + 2;

    // 找到子节点中值最小的节点
    if (left < queue->size && queue->nodes[left]->freq < queue->nodes[smallest]->freq)
        smallest = left;

    if (right < queue->size && queue->nodes[right]->freq < queue->nodes[smallest]->freq)
        smallest = right;

    // 如果最小节点不是当前节点,则交换位置,并递归调整
    if (smallest != idx) {
        swap(&queue->nodes[idx], &queue->nodes[smallest]);
        minHeapify(queue, smallest);
    }
}

// 判断队列中是否只有一个节点
int isSizeOne(struct PriorityQueue* queue) {
    return queue->size == 1;
}

// 从队列中提取最小节点
struct Node* extractMin(struct PriorityQueue* queue) {
    struct Node* minNode = queue->nodes[0];
    queue->nodes[0] = queue->nodes[queue->size - 1];
    --queue->size;
    minHeapify(queue, 0);
    return minNode;
}

// 向队列中插入一个节点
void insert(struct PriorityQueue* queue, struct Node* node) {
    ++queue->size;
    int i = queue->size - 1;
    while (i && node->freq < queue->nodes[(i - 1) / 2]->freq) {
        queue->nodes[i] = queue->nodes[(i - 1) / 2];
        i = (i - 1) / 2;
    }
    queue->nodes[i] = node;
}

// 判断节点是否为叶节点
int isLeaf(struct Node* root) {
    return !(root->left) && !(root->right);
}

// 打印哈夫曼编码
void printCodes(struct Node* root, unsigned int code, unsigned int bitCount) {
    if (root) {
        // 如果是叶节点,则打印字符和对应的编码
        if (isLeaf(root)) {
            printf("%c: ", root->data);

            // 根据编码的位数逐位输出
            unsigned int mask = 1 << (bitCount - 1);
            while (mask) {
                if (code & mask)
                    printf("1");
                else
                    printf("0");
                mask >>= 1;
            }
            printf("\n");
        }

        // 递归打印左右子树的编码
        printCodes(root->left, code << 1, bitCount + 1);
        printCodes(root->right, (code << 1) | 1, bitCount + 1);
    }
    }

}

// 构建哈夫曼树
struct Node* buildHuffmanTree(char data[], int freq[], int size) {
    struct Node *left, *right, *top;
    struct PriorityQueue* queue = createPriorityQueue(size);

    // 将字符和频率作为节点插入优先队列
    for (int i = 0; i < size; ++i)
        insert(queue, createNode(data[i], freq[i]));

    // 从优先队列中取出两个最小频率的节点,合并成一个新节点
    // 直到队列中只剩下一个节点,即根节点
    while (!isSizeOne(queue)) {
        left = extractMin(queue);
        right = extractMin(queue);
        top = createNode('$', left->freq + right->freq);
        top->left = left;
        top->right = right;
        insert(queue, top);
    }

    return extractMin(queue);
}

// 打印哈夫曼编码
void huffmanCodes(char data[], int freq[], int size) {
    struct Node* root = buildHuffmanTree(data, freq, size);
    unsigned int code = 0;
    unsigned int bitCount = 0;
    printCodes(root, code, bitCount);
}

int main() {
    char data[] = { 'A', 'B', 'C', 'D', 'E' };
    int freq[] = { 5, 9, 12, 13, 16 };
    int size = sizeof(data) / sizeof(data[0]);

    huffmanCodes(data, freq, size);

    return 0;
}

最小堆是一种二叉树,其中每个节点的值都小于或等于其子节点的值。

相关推荐
钢琴上的汽车软件4 小时前
C 语言中const与指针:三种常见写法辨析
c语言·指针和const
ZK_H5 小时前
嵌入式c语言——关键字其6
c语言·开发语言·计算机网络·面试·职场和发展
ambition202425 小时前
从暴力搜索到理论最优:一道任务调度问题的完整算法演进历程
c语言·数据结构·c++·算法·贪心算法·深度优先
cmpxr_5 小时前
【C】原码和补码以及环形坐标取模算法
c语言·开发语言·算法
yashuk6 小时前
C语言实现PAT练习及算法学习笔记,还有SQLite介绍
c语言·sqlite·开源项目·算法学习·pat练习
ACP广源盛139246256736 小时前
破局 Type‑C 切换器痛点@ACP#GSV6155+LH3828/GSV2221+LH3828 黄金方案
c语言·开发语言·网络·人工智能·嵌入式硬件·计算机外设·电脑
爱编码的小八嘎7 小时前
C语言完美演绎7-10
c语言
hhh3u3u3u9 小时前
Visual C++ 6.0中文版安装包下载教程及win11安装教程
java·c语言·开发语言·c++·python·c#·vc-1
泛凡(Linyongui)9 小时前
PY32F002B实践之二--宠物腹背理疗仪项目介绍及头文件解析
c语言·keil·py32·32位单片机·腹背理疗仪项目实践
网域小星球11 小时前
C 语言从 0 入门(十四)|文件操作:读写文本、保存数据持久化
c语言·开发语言·文件操作·fopen·fprintf