Huffman

来源:互联网 发布:中国是否允许持枪知乎 编辑:程序博客网 时间:2024/05/17 07:36

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 和 SwapT 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 和 SwapT 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);    }}
原创粉丝点击