Huffman

Huffman编码是一种变长编码技术,通过构建霍夫曼树来根据字符出现频率进行编码,高频率字符使用短编码,低频率字符使用长编码,以减少编码后的平均长度,实现无损数据压缩。本文介绍了霍夫曼树的构造过程和编码方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Huffman算法

霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现概率的方法得到的,出现概率高的字母使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。

来自文库

演算过程
这里写图片描述
(一)进行霍夫曼编码前,我们先创建一个霍夫曼树。
⒈将每个英文字母依照出现频率由小排到大,最小在左.
这里写图片描述
⒉每个字母都代表一个终端节点(叶节点),比较F.O.R.G.E.T六个字母中每个字母的出现频率,将最小的两个字母频率相加合成一个新的节点。如Fig.2所示,发现F与O的频率最小,故相加2+3=5。
⒊比较5.R.G.E.T,发现R与G的频率最小,故相加4+4=8。
⒋比较5.8.E.T,发现5与E的频率最小,故相加5+5=10。
⒌比较8.10.T,发现8与T的频率最小,故相加8+7=15。
⒍最后剩10.15,没有可以比较的对象,相加10+15=25。
最后产生的树状图就是霍夫曼树
这里写图片描述
(二)进行编码
1.给霍夫曼树的所有左链接’0’与右链接’1’。
2.从树根至树叶依序记录所有字母的编码
这里写图片描述

在这里, 我们主程序其实是排序, 我选用的是堆排序, 因为用起来方便, 不需要每次新开辟空间 代码稍微有点变化
每次将最小的放在第一个, 将第一保存后再放在最后, 然后数组大小 -1;


//排序, 使用的是堆排序
void sort(int first, int last)
{
    int i = first * 2 + 1;
    node tmp = arr[first];
    for (; i < last; first = i, i = i * 2 + 1)
    {
        if (i < last - 1 && arr[i].num > arr[i + 1].num)
            i++;

        if (arr[first].num > arr[i].num)
            arr[first] = arr[i];
        else
            break;
    }
    arr[first] = tmp;
}

//交换, 堆排序里的必要步骤, 将第一个位置与最后一个位置的进行交换
void Swap(int i, int j)
{
    node tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

//进行sort 和 Swap
T sort_min(int &size_arr)
{
    //L : 存储arr[0]的链表
    T L = new Node;
    *L = arr[0];
    Swap(0, size_arr - 1);
    sort(0, size_arr - 2);

    size_arr--;

    return L;
}

源代码


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

typedef int Type;
struct Node;
typedef struct Node *T;
typedef struct Node node;

struct Node
{
    Type num;
    T Left;
    T Right;
    Node() : Left(NULL), Right(NULL) {}
};

void Swap(int i, int j);
void sort(int first, int last);
T sort_min(int &size_arr);
void Create(int a[], int size);
void Add(T L, T R, int size_arr);
void Print(T Huff);

int main()
{
    int a[] = { 10, 15, 13, 12, 3, 4, 1 };
    int size_arr = sizeof(a) / sizeof(a[0]);
    Create(a, size_arr);


    system("pause");
    return 0;
}

//arr是 Node 的数组;
node *arr;

//排序, 使用的是堆排序
void sort(int first, int last)
{
    int i = first * 2 + 1;
    node tmp = arr[first];
    for (; i < last; first = i, i = i * 2 + 1)
    {
        if (i < last - 1 && arr[i].num > arr[i + 1].num)
            i++;

        if (arr[first].num > arr[i].num)
            arr[first] = arr[i];
        else
            break;
    }
    arr[first] = tmp;
}

//交换, 堆排序里的必要步骤, 将第一个位置与最后一个位置的进行交换
void Swap(int i, int j)
{
    node tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

//进行sort 和 Swap
T sort_min(int &size_arr)
{
    //L : 存储arr[0]的链表
    T L = new Node;
    *L = arr[0];
    Swap(0, size_arr - 1);
    sort(0, size_arr - 2);

    size_arr--;

    return L;
}

//将两个最小的数相加, 得到新的链表
void Add(T L, T R, int size_arr)
{
    T tmp = new Node;
    tmp->num = L->num + R->num;
    tmp->Left = L;
    tmp->Right = R;

    arr[size_arr - 1] = *tmp;

}

//执行所有功能
void Create(int a[], int size)
{
    //size_arr : 数组的大小;
    int size_arr;
    size_arr = size;

    //初始化arr;
    arr = (T)malloc(sizeof(node) * size);
    for (int i = 0; i < size; i++)
    {
        arr[i].num = a[i];
        arr[i].Left = arr[i].Right = NULL;
    }

    //L : 左节点;
    //R : 右节点;
    T L = new Node, R = new Node;

    for (int i = 0; i < size - 1; i++)
    {
        //堆排序
        for (int j = size_arr / 2; j >= 0; j--)
            sort(i, size_arr);

        L = sort_min(size_arr);
        R = sort_min(size_arr);

        size_arr++;

        Add(L, R, size_arr);
    }

    T Huff = new Node;
    *Huff = arr[0];
    Print(Huff);
    /*
    当然也可以直接传 &arr[0]的地址;
    */
}

void Print(T Huff)
{
    if (Huff != NULL)
    {
        printf("%d ", Huff->num);
        Print(Huff->Left);
        Print(Huff->Right);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值