c++ 规范霍夫曼编码

        霍夫曼编码是一种无损数据压缩算法,其中数据中的每个字符都分配有可变长度的前缀代码。出现频率最低的字符获得最大代码,出现频率最高的字符获得最小代码。使用这种技术对数据进行编码非常简单且高效。但是,解码使用此技术生成的比特流效率低下。解码器(或解压缩器)需要了解所使用的编码机制,以便将编码数据解码回原始字符。 

        因此,需要将编码过程的信息与编码数据一起作为字符表及其对应代码传递给解码器。在对大量数据进行常规霍夫曼编码时,此表会占用大量内存空间,而且如果数据中存在大量唯一字符,则由于存在代码本,压缩(或编码)数据大小会增加。因此,为了使解码过程在计算上高效,同时仍保持良好的压缩率,引入了规范霍夫曼码。 

        在标准霍夫曼编码中,使用为每个符号生成的标准霍夫曼代码的位长。首先根据符号的位长按非递减顺序对符号进行排序,然后根据每个位长按字典顺序对符号进行排序。第一个符号获得一个全为零且长度与原始位长相同的代码。对于后续符号,如果符号的位长等于前一个符号的位长,则将前一个符号的代码加一并分配给当前符号。 

        否则,如果符号的位长大于前一个符号的位长,则在增加前一个符号的代码后,将零附加到该代码上,直到长度等于当前符号的位长,然后将代码分配给当前符号。 
此过程继续处理其余符号。 

以下示例说明了该过程:

考虑以下数据: 

特点频率
A10
b1
C15
d7

生成的标准霍夫曼码的位长度为:  

特点霍夫曼编码位长度
A112
b1003
C01
d1013
  • 步骤 1:根据位长对数据进行排序,然后根据每个位长度按字典顺序对符号进行排序。 
特点位长度
C1
A2
b3
d3
  • 步骤 2:为第一个符号的代码分配与位长相同数量的“0”。 
    ‘c’的代码:0
    下一个符号‘a’的位长为 2 > 前一个符号‘c’的位长为 1。将前一个符号的代码增加 1 并附加 (2-1)=1 个零并将代码分配给‘a’。 
    ‘a’的代码:10
    下一个符号‘b’的位长为 3 > 前一个符号‘a’的位长为 2。将前一个符号的代码增加 1 并附加 (3-2)=1 个零并将代码分配给‘b’。 
    ‘b’的代码:110
    下一个符号‘d’的位长为 3 = 前一个符号‘b’的位长为 3。将前一个符号的代码增加 1 并将其分配给‘d’。 
    ‘d’的代码:111
  • 步骤3:最终结果。  
特点规范霍夫曼编码
C0
A10
b110
d111

        该方法的基本优点是,传递给解码器的编码信息可以更紧凑、更节省内存。例如,可以简单地将字符或符号的位长度传递给解码器。由于长度是连续的,因此可以轻松根据长度生成规范代码。 
有关使用 Huffman 树生成 Huffman 代码的信息,请参阅之前的文章如下:

c语言:c语言 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪c语言-CSDN博客

c++:c++ 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪算法设计核心代码-CSDN博客

c#:C# 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

c++ STL:c++ STL 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

java:java 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

python:python 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

javascript:JavaScript 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客 

方法:一种简单有效的方法是为数据生成一棵哈夫曼树,并使用类似于 Java 中的 TreeMap 的数据结构来存储符号和位长,以使信息始终保持排序。然后可以使用增量和按位左移运算来获取规范代码。 

执行:

#include <bits/stdc++.h>
using namespace std;

// Nodes of Huffman tree
class Node {
public:
    int data;
    char c;
    Node* left;
    Node* right;
};

// Comparator class helps to compare the node
// on the basis of one of its attributes.
// Here we will be compared
// on the basis of data values of the nodes.
class Pq_compare {
public:
    int operator() (Node* a, Node* b) {
        return a->data - b->data;
    }
};

class Canonical_Huffman {
    // Treemap to store the
    // code lengths(sorted) as keys
    // and corresponding(sorted)
    // set of characters as values
public:
    static map<int, set<char>> data;

    Canonical_Huffman() {
        data = map<int, set<char>>();
    }
    
    // Recursive function
    // to generate code lengths
    // from regular Huffman codes
    static void code_gen(Node* root, int code_length) {
        if (root == nullptr)
            return;

        // base case; if the left and right are null
        // then its a leaf node.
        if (root->left == nullptr && root->right == nullptr) {
            // check if key is present or not.
            // If not present add a new treeset
            // as value along with the key
            data[code_length].insert(root->c);
            return;
        }

        // Add 1 when going left or right.
        code_gen(root->left, code_length + 1);
        code_gen(root->right, code_length + 1);
    }

    static void testCanonicalHC(int n, char chararr[], int freq[]) {
        // min-priority queue(min-heap).
        priority_queue<Node*, vector<Node*>, Pq_compare> q;

        for (int i = 0; i < n; i++) {
            // creating a node object
            // and adding it to the priority-queue.
            Node* node = new Node();
            node->c = chararr[i];
            node->data = freq[i];
            node->left = nullptr;
            node->right = nullptr;

            // add functions adds
            // the node to the queue.
            q.push(node);
        }

        // Create a root node
        Node* root = nullptr;

        // extract the two minimum values
        // from the heap each time until
        // its size reduces to 1, extract until
        // all the nodes are extracted.
        while (q.size() > 1) {
            // first min extract.
            Node* x = q.top();
            q.pop();

            // Second min extract
            Node* y = q.top();
            q.pop();

            // new node f which is equal
            Node* nodeobj = new Node();
            
            // to the sum of the frequency of the two nodes 
            // assigning values to the f node
            nodeobj->data = x->data + y->data;
            nodeobj->c = '-';
            // first extracted node as left child.
            nodeobj->left = x;
            // second extracted node as the right child.
            nodeobj->right = y;
            // marking the f node as the root node
            root = nodeobj;
            // add this node to the priority-queue.
            q.push(nodeobj);
        }

        // creating a canonical Huffman object
        Canonical_Huffman obj = Canonical_Huffman();
        
        // generate code lengths by traversing the tree
        code_gen(root, 0);

        // Object array to the store the keys
        auto arr = data;
        
        // Set initial canonical code = 0
        int c_code = 0, curr_len = 0, next_len = 0;

        for (auto it = arr.begin(); it != arr.end(); it++) {
            set<char> s = it->second;
            
            // code length of current character
            curr_len = it->first;

            for (auto i = s.begin(); i != s.end(); i++) {
                // Display the canonical codes
                cout << *i << ":" << bitset<32>(c_code).to_string().substr(32 - curr_len, 32) << endl;
                
                // if values set is not
                // completed or if it is
                // the last set set code length
                // of next character as current
                // code length
                if (next(i) != s.end() || next(it) == arr.end())
                    next_len = curr_len;
                else
                    next_len = next(it)->first;
                
                // Generate canonical code
                // for next character using
                // regular code length of next
                // character
                c_code = (c_code + 1) << (next_len - curr_len);
            }
        }
    }
};

map<int, set<char>> Canonical_Huffman::data;

// Driver code
int main() {
    int n = 4;
    char chararr[] = {'a', 'b', 'c', 'd'};
    int freq[] = {10, 1, 15, 7};
    Canonical_Huffman::testCanonicalHC(n, chararr, freq);
    return 0;
}

输出:
c:0
a:10
b:110
d:111 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值