📜  Shannon-Fano数据压缩算法

📅  最后修改于: 2021-04-26 18:03:30             🧑  作者: Mango

数据压缩及其类型
数据压缩,也称为源编码,是一种编码或转换数据的过程,以使其占用较少的存储空间。数据压缩减少了存储和传输数据所需的资源数量。
它可以通过两种方式完成:无损压缩和有损压缩。有损压缩通过删除不必要的信息来减少数据大小,而无损压缩不会丢失任何数据。

什么是SHANNON FANO编码?
Shannon Fano算法是一种用于多媒体无损数据压缩的熵编码技术。它以克劳德·香农(Claude Shannon)和罗伯特·法诺(Robert Fano)的名字命名,根据每个符号的出现概率为其分配代码。这是一种可变长度编码方案,也就是说,分配给符号的代码将具有不同的长度。

它是如何工作的?
该算法的步骤如下:

  1. 为给定的一组符号创建概率或频率计数的列表,以便知道每个符号的相对出现频率。
  2. 按概率从大到小的顺序对符号列表进行排序,最可能的符号排在左边,最不可能的符号排在右边。
  3. 将列表分为两部分,两部分的总概率尽可能接近。
  4. 将值0分配给左侧,将值1分配给右侧。
  5. 对每个部分重复步骤3和4,直到将所有符号分成单独的子组。

如果每个符号的代码都是唯一的,则香农代码被认为是准确的。

例子:
给定的任务是使用Shannon-Fano无损压缩技术为给定的符号集构造Shannon码。

步:

树:

解决方案:

    令P(x)为符号x出现的概率:
  1. 以降序排列符号时:

    和,

    并且由于几乎均等地拆分了表,因此块引用表中的划分最多的是块引用

    并分别为其分配值0和1。

    步:

    树:

  2. 现在,在{D,B}组中,

    这意味着P(D)〜P(B) ,因此将{D,B}划分为{D}和{B},并将0分配给D,将1分配给B。

    步:

    树:

  3. 在{A,C,E}组中,

    因此,该组分为

    并分别为其分配了值0和1。

  4. 在{C,E}组中,

    因此,将它们分为{C}和{E}并将0分配给{C},将1分配给{E}

    步:

    树:

    注意:由于现在每个符号都已分离,因此拆分现在停止。

符号集的香农代码为:

可以看出,它们都是唯一的,并且长度各不相同。

下面是上述方法的实现:

// C++ program for Shannon Fano Algorithm
  
// include header files
#include 
using namespace std;
  
// declare structure node
struct node {
  
    // for storing symbol
    string sym;
  
    // for storing probability or frquency
    float pro;
    int arr[20];
    int top;
} p[20];
  
typedef struct node node;
  
// function to find shannon code
void shannon(int l, int h, node p[])
{
    float pack1 = 0, pack2 = 0, diff1 = 0, diff2 = 0;
    int i, d, k, j;
    if ((l + 1) == h || l == h || l > h) {
        if (l == h || l > h)
            return;
        p[h].arr[++(p[h].top)] = 0;
        p[l].arr[++(p[l].top)] = 1;
        return;
    }
    else {
        for (i = l; i <= h - 1; i++)
            pack1 = pack1 + p[i].pro;
        pack2 = pack2 + p[h].pro;
        diff1 = pack1 - pack2;
        if (diff1 < 0)
            diff1 = diff1 * -1;
        j = 2;
        while (j != h - l + 1) {
            k = h - j;
            pack1 = pack2 = 0;
            for (i = l; i <= k; i++)
                pack1 = pack1 + p[i].pro;
            for (i = h; i > k; i--)
                pack2 = pack2 + p[i].pro;
            diff2 = pack1 - pack2;
            if (diff2 < 0)
                diff2 = diff2 * -1;
            if (diff2 >= diff1)
                break;
            diff1 = diff2;
            j++;
        }
        k++;
        for (i = l; i <= k; i++)
            p[i].arr[++(p[i].top)] = 1;
        for (i = k + 1; i <= h; i++)
            p[i].arr[++(p[i].top)] = 0;
  
        // Invoke shannon function
        shannon(l, k, p);
        shannon(k + 1, h, p);
    }
}
  
// Function to sort the symbols
// based on their probability or frequency
void sortByProbability(int n, node p[])
{
    int i, j;
    node temp;
    for (j = 1; j <= n - 1; j++) {
        for (i = 0; i < n - 1; i++) {
            if ((p[i].pro) > (p[i + 1].pro)) {
                temp.pro = p[i].pro;
                temp.sym = p[i].sym;
  
                p[i].pro = p[i + 1].pro;
                p[i].sym = p[i + 1].sym;
  
                p[i + 1].pro = temp.pro;
                p[i + 1].sym = temp.sym;
            }
        }
    }
}
  
// function to display shannon codes
void display(int n, node p[])
{
    int i, j;
    cout << "\n\n\n\tSymbol\tProbability\tCode";
    for (i = n - 1; i >= 0; i--) {
        cout << "\n\t" << p[i].sym << "\t\t" << p[i].pro << "\t";
        for (j = 0; j <= p[i].top; j++)
            cout << p[i].arr[j];
    }
}
  
// Driver code
int main()
{
    int n, i, j;
    float total = 0;
    string ch;
    node temp;
  
    // Input number of symbols
    cout << "Enter number of symbols\t: ";
    n = 5;
    cout << n << endl;
  
    // Input symbols
    for (i = 0; i < n; i++) {
        cout << "Enter symbol " << i + 1 << " : ";
        ch = (char)(65 + i);
        cout << ch << endl;
  
        // Insert the symbol to node
        p[i].sym += ch;
    }
  
    // Input probability of symbols
    float x[] = { 0.22, 0.28, 0.15, 0.30, 0.05 };
    for (i = 0; i < n; i++) {
        cout << "\nEnter probability of " << p[i].sym << " : ";
        cout << x[i] << endl;
  
        // Insert the value to node
        p[i].pro = x[i];
        total = total + p[i].pro;
  
        // checking max probability
        if (total > 1) {
            cout << "Invalid. Enter new values";
            total = total - p[i].pro;
            i--;
        }
    }
  
    p[i].pro = 1 - total;
  
    // Sorting the symbols based on
    // their probability or frequency
    sortByProbability(n, p);
  
    for (i = 0; i < n; i++)
        p[i].top = -1;
  
    // Find the shannon code
    shannon(0, n - 1, p);
  
    // Display the codes
    display(n, p);
    return 0;
}
输出:
Enter number of symbols    : 5
Enter symbol 1 : A
Enter symbol 2 : B
Enter symbol 3 : C
Enter symbol 4 : D
Enter symbol 5 : E

Enter probability of A : 0.22

Enter probability of B : 0.28

Enter probability of C : 0.15

Enter probability of D : 0.3

Enter probability of E : 0.05



    Symbol    Probability    Code
    D        0.3    00
    B        0.28    01
    A        0.22    10
    C        0.15    110
    E        0.05    111