《高级数据结构》-哈夫曼树与哈夫曼编码

《高级数据结构》-哈夫曼树与哈夫曼编码

思维导图

在这里插入图片描述

代码演示

测试

在这里插入图片描述

代码

/*************************************************************************
	> File Name: haffman_tree.cpp
	> Mail: 1136984246@qq.com
 ************************************************************************/
#include <stdlib.h>
#include <stdio.h>

#define swap(a, b) {\
    __typeof(a) __temp = a;\
    a = b; b = __temp;\
}

// 哈夫曼编码基于树
typedef struct Node {
    char ch; // 当前节点代表的字符
    double p; // 当前节点的概率值
    struct Node *lchild, *rchild;
}Node;

Node *getNewNode(char ch, double per) {
    Node *p = (Node *)malloc(sizeof(Node));
    p->ch = ch;
    p->p = per;
    p->lchild = p->rchild = NULL;
    return p;
}

// 合并节点[建立关系的关键]
Node *combineNode(Node *a, Node *b) {
    Node *p = getNewNode(0, a->p + b->p); // 节点的概率值进行累加
    p->lchild = a; // 左 :最小
    p->rchild = b; // 右 :次小
    return p;
}

// 找到最小值,放在第n位上
void pick_min(Node **arr, int n) {
    for (int j = n - 1; j >= 0; --j) {
        if (arr[j]->p < arr[n]->p) {
            swap(arr[n], arr[j]);
        }
    }
    return;
}

// ? 能保证所有的节点都在叶子节点上?
// 建树:返回树根节点地址
Node *getHaffmanTree(Node **arr, int n) {
    // n 个节点需要合并 n - 1次才能才能形成一棵树
    for (int i = 1; i < n; i++) {
        // 先找到两个概率最小的节点地址【可以用堆进行优化】 
        pick_min(arr, n - i); // 最后一位存放最小值
        pick_min(arr, n - i - 1); // 倒数第二位存放次小值
        // 更新倒数第二位的概率参加后续的合并[每轮循环比较的范围缩小1]
        arr[n - i - 1] = combineNode(arr[n - i], arr[n - i - 1]);
    }
    return arr[0]; // 根节点存在arr[0],节点之间的关系已经建立
}

// 递归:提取字符的编码
void __output_encode(Node *root, char *str, int k) {
    str[k] = 0; // 即字符串终止符'\0'
    // 如果是叶子节点,则对应一个字符
    if (root->lchild == NULL && root->rchild == NULL) {
        printf("%c %s\n", root->ch, str);
        return;
    }
    // 左0, 右1
    // ? '0' '1'之间不会混乱吗?
    str[k] = '0';
    __output_encode(root->lchild, str, k + 1);
    str[k] = '1';
    __output_encode(root->rchild, str, k + 1);
    return;
}

// 输出编码
void output_encode(Node *root) {
    char str[100]; // 编码数组
    __output_encode(root, str, 0); // k代表第k位上添加01编码
    return;
}

void clear(Node *root) {
    if (root == NULL) return;
    clear(root->lchild);
    clear(root->rchild);
    free(root);
    return;
}

int main() {
    int n;
    Node **arr;
    scanf("%d", &n);
    arr = (Node **)malloc(sizeof(Node *) *n);
    for (int i = 0; i < n; i++) {
        char ch[10];
        double p;
        scanf("%s%lf", ch, &p);
        arr[i] = getNewNode(ch[0], p);
    }
    Node *root = getHaffmanTree(arr, n);
    output_encode(root); 
    clear(root);
    free(arr);
    return 0;
}

参考文献

《高级数据结构》-哈夫曼树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值