Huffman实现

yizhihongxing

Huffman编码树

秒懂:【算法】Huffman编码_哔哩哔哩_bilibili

Huffman实现

约定:字符x的编码长度 就是其对应叶节点的深度;

在一个字符集中,每个字符出现的次数有多有少,那么若都采用固定长度编码的话,那么编码长度会非常大,并且搜索时间复杂度都非常高;若采用非固定编码,出现次数多的字符编码长度小一些,并且放在树深度小的地方,提高搜索时间效率;这样带权平均编码长度(weight average leaf depth)就会达到最优;同时为了避免歧义,任何字符不能是其他字符的编码前缀;还有一点就是没有度为1的节点,也就是说是一颗满二叉树;

个人理解:

没有前缀:在具体实现时,由 priority_queue 排序完成后的 节点权值树 再转存在map中时,不会存储根节点,只会存叶子节点,就能避免前缀相同的情况;还有一点就是第一个设置为0,而不是1,1的话就会成为其他字符的前缀;

没有度为1 的节点 和 无前缀相同编码 的不一定是Huffman,还需满足 ald 最短;

时间复杂度:对于出现次数多的字符,让它在靠近根节点位置,这样就能接近O(1)时间复杂度;而对于出现次数少的字符,就靠近树的最底部位置;

具体实现

代码参考:Canonical Huffman Coding - GeeksforGeeks

1、实现一个struct,保存字符出现的次数,以及字符本身,还有左右子节点;

2、写一个路径长度模块函数,create_code();

3、写一个Huffman编码函数,create_huffman(); 其中, 先按频率从小到大排列,然后取最小的两个合并为一大的,在继续合并直至成为一个根节点,再将字符树存进map中;接着实现Huffman编码;

  ①在编码时,利用路径长度信息,和bitset<32>类,实现位操作,并且利用成员函数to_string()转化为字符串,左边为高位,右边为低位;substr函数第二个参数长度设置为32,默认到头;

Huffman实现

  ②怎么利用路径长度信息的? 比如说代码中 给出的例子c,编码为0,假设还有叶子节点,那么当前编码值加上1,然后再左移(下一层的深度 - 当前层的深度)位,即 0 +1 = 12,再左移(2-1)位,变成102;在内层循环中,当是同一层的最后两个叶子节点时,即110 和 111 , 不做左移,只做值加一操作,代码这儿用了一个next_len 和 cur_len 相减实现左移的次数值;(非常巧妙);

  ③学到了一个next 函数,和 bitset 位操作;

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

/*Huffman codes : a lossless data compression algorithm; weighted average leaf depth(带权平均深度最小)*/
struct Node{
    int data;
    char c;
    Node* left, *right;
};

struct mycomp{
    bool operator()(Node* a, Node* b){
        return a->data > b->data;
    }
};

class huffman{
private:
    map<int, set<char>> data;
public:
    huffman(){}
    void create_code(Node* root, int code_len){
        if(root == nullptr){
            return;
        }
        /*only store leaf node*/
        if(root->left == nullptr && root->right == nullptr){
            data[code_len].insert(root->c);
        }
        create_code(root->left, code_len + 1);
        create_code(root->right, code_len + 1);
    }
    void create_huffman(int n, char arr_char[], int freq[]){
        /* 小顶堆  取堆顶 freq 小的两个合并*/
        priority_queue<Node*, vector<Node*>, mycomp>que;
        for(int i = 0;i < n;++i){
            Node* newnode = new Node();
            newnode->c = arr_char[i];
            newnode->data = freq[i];
            newnode->left = nullptr;
            newnode->right = nullptr;
            que.push(newnode);
        }
        /*Node Tree*/
        Node* root = nullptr;
        while(que.size() > 1){
            Node* tmp1 = que.top();
            que.pop();
            Node* tmp2 = que.top();
            que.pop();
            Node* mergeNode = new Node();
            mergeNode->data = tmp1->data + tmp2->data;
            mergeNode->c = '-';
            mergeNode->left = tmp1;
            mergeNode->right = tmp2;
            root = mergeNode;
            que.push(mergeNode);
        }
        huffman obj = huffman();
        create_code(root, 0);
        int cur_code = 0, cur_len = 0, next_len = 0;
        for(map<int, set<char>>::iterator it = data.begin(); it != data.end(); ++it){
            set<char> s = it->second;
            cur_len = it->first;
            for(auto i = s.begin(); i != s.end(); ++i){
                cout << *i << " : ";
                /* coding */
                cout << bitset<32>(cur_code).to_string().substr(32 - cur_len, 32) << endl;
                
                /* 相同长度 有一个以上叶子节点时 : 这种情况只出现在 尾部的那俩个元素*/
                if(next(i) != s.end() || next(it) == data.end()) next_len = cur_len;
                else next_len = next(it)->first;
                
                cur_code = (cur_code + 1) << (next_len - cur_len);
            }
        }
    }
};

int main(){
    int n = 4;
    char arr[] = {'a', 'b', 'c', 'd'};
    int fre[] = {10, 1, 15, 7};
    huffman obj;
    obj.create_huffman(n,arr,fre); 
    system("pause");
    return 0;
}
/*
c : 0
a : 10
b : 110
d : 111
*/

 

原文链接:https://www.cnblogs.com/xuan01/p/17317584.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Huffman实现 - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • JavaScript 数据结构之集合创建(1)

    当我们在编写JavaScript程序时,有时需要使用数据结构来组织和表示数据。其中之一是集合,它是一组无序且唯一的项的集合。这里就介绍如何在JavaScript中创建集合。 1. 集合定义 集合是一种不同于数组或对象,由一组彼此无关的元素组成的数据结构。集合中的元素是唯一的,即不允许重复元素。 2. 集合的操作 JavaScript中的集合可以支持以下常见操…

    数据结构 2023年5月17日
    00
  • 带你了解Java数据结构和算法之数组

    带你了解Java数据结构和算法之数组 在本教程中,我们将学习Java中的数组数据结构和对应的算法。让我们先来了解什么是数组。 什么是数组? 数组是一个同类型数据元素的集合,在内存中连续存储。数组具有索引性,我们可以使用索引值来访问数组中的元素。 声明和初始化数组 在Java中,声明一个数组需要指定以下三个参数: 数组的类型 数组的名称 数组的大小 以下是一个…

    数据结构 2023年5月17日
    00
  • Java数据结构之单链表详解

    下面是单链表攻略的详细讲解。 什么是单链表? 单链表是一种线性数据结构,它由一系列结点组成,每个结点包含数据域和指针域。数据域用于存储数据,指针域用于指向下一个结点。单链表的优点是插入和删除操作的时间复杂度为O(1),缺点是随机访问的时间复杂度为O(n)。 单链表的基本操作 单链表的基本操作包括插入操作、删除操作、查找操作和遍历操作。下面将分别介绍这些操作。…

    数据结构 2023年5月17日
    00
  • Java数据结构之List的使用总结

    非常感谢您对本网站的关注。Java数据结构之List的使用总结是一个非常重要的主题,这里将为您详细介绍。 1. List是什么 在Java中,List是一种非常实用的数据结构,它代表了一个元素的有序集合,其中的每个元素都可以用一个整数索引来标识。List允许多个元素重复,同时还可以在集合的任意位置插入或者删除元素。 Java中的List主要分为两类:Arra…

    数据结构 2023年5月17日
    00
  • Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit Counting)

    Java数据结构及算法实例:快速计算二进制数中1的个数 简介 本文将介绍在Java中快速计算二进制数中1的个数的算法。本算法是一种基于位运算的算法,其核心思想是利用位运算的快捷性,将原问题转化为每次计算一位是否为1的问题,使得计算速度大大提升。 背景知识 在理解本算法之前,需要了解Java中的一些背景知识: 1. 位运算 Java中的位运算符有如下几个: &…

    数据结构 2023年5月17日
    00
  • golang中set数据结构的使用示例

    Golang中Set数据结构的使用示例 Set是一种无序的、元素不重复的数据结构。通过使用map来实现,map中的key即为Set中的元素,value则可以用来存储某种状态(比如计数)。 Set数据结构的定义 type Set struct { m map[interface{}]bool } Set数据结构的初始化 func NewSet() *Set {…

    数据结构 2023年5月17日
    00
  • Python3 常用数据标准化方法详解

    下面是详细讲解“Python3常用数据标准化方法详解”的完整攻略。 1. 什么是数据标准化 数据标准化指将数据转换特定范围内的标准值的过程。标准化可以使不同单位或不同量级的数据具有可比性,从而更易进行数据分析和处理。在数据分析和机学习中,数据标准化是一个重要的预处理步骤,可以提高模型准确性稳定性。 2. 常用的数据标准化方法 以下是常用的数据标准化方法: 2…

    python 2023年5月14日
    00
  • python算法学习之桶排序算法实例(分块排序)

    下面是详细讲解“python算法学习之桶排序算法实例(分块排序)”的完整攻略,包含两个示例说明。 桶排序算法简介 桶算法是一种线性排序算法,它的基本思想是将数据分到有限数量的桶中,然后对每个桶中的数据进行排序,最后将所有桶中的数据依次取出,即可得到有序序列。桶排序算法适用于数据分布均的情况,时间复杂度为O(n)。 Python实现桶排序算法 下面是Pytho…

    python 2023年5月14日
    00
合作推广
合作推广
分享本页
返回顶部