精华内容
下载资源
问答
  • 数据压缩算法 - 数据压缩

    千次阅读 2020-11-02 17:58:48
    数据压缩算法,考虑点: 压缩比(压缩率的倒数) 压缩/解压缩需要资源(内存) 压缩/解压缩需要时间。 常用:https://www.cnblogs.com/tommyli/p/4350672.html 压缩:有损,无损,(可逆,非可逆) 压缩...

    数据压缩算法,考虑点:

    压缩比(压缩率的倒数)

    压缩/解压缩需要资源(内存)

    压缩/解压缩需要时间。

     

    常用:https://www.cnblogs.com/tommyli/p/4350672.html

     

    压缩:有损,无损,(可逆,非可逆)

    压缩解压:对称,非对称

     

    常见的图片格式,都是使用了特定压缩算法的应用。

    一般来说,JPEG格式的文件是非可逆压缩,因此还原后有部分图像信息比较模糊。GIF 是可逆压缩

    mpeg

    几种压缩算法的速度比较:https://blog.csdn.net/leilonghao/article/details/73200859

     

    常用的压缩算法:

    LZO一个开源的无损压缩C语言库,其优点压缩和解压缩比较迅速占用内存小等特点(网络传输希望的压缩和解压缩速度比较快,压缩率不用很高)。压缩率(0.5%~50%)

     

    说明:

    同一个压缩算法,(例如LZO),对于不同类型文件,压缩比范围很大(压缩比差异很大)。

    展开全文
  • json数据压缩

    千次阅读 2020-07-24 15:40:18
    同时为了提升性能、降低带宽,我们一般会对json数据进行压缩。今天我们就来谈谈各种压缩方法。 1、常规压缩: 默认的json数据是带有换行的,所以最简单的压缩方法是将json中的回车换行去掉,压缩成一行字符串。 ...

    json是一种非常简单、易读的数据结构。通常我们在做开发时,会选取json作为数据传输格式。同时为了提升性能、降低带宽,我们一般会对json数据进行压缩。今天我们就来谈谈各种压缩方法。

    1、常规压缩:

    默认的json数据是带有换行的,所以最简单的压缩方法是将json中的回车换行去掉,压缩成一行字符串。

    测试:找了一个大的json字符串,原始大小为1.1m,去掉回车换行压缩成一行后,大小变为了360k。

    在线压缩工具:https://www.bejson.com/

    其次,我们还可以将json中的key变短,设置可以是无意义的符号(只要我们规定好含义即可),这样也能减少json大小。

    2、使用gzip、deflate算法压缩:

    json本身就是一个文本信息,所以我们可以使用gzip、deflate等算法对其进行压缩,它们都是使用哈弗慢编码的一个无损数据压缩算法,对文本内容压缩的压缩比很高,基本在80%以上。大多数浏览器也都是使用这两种方式对http协议中的响应实体进行压缩。

    这里不过多举例子,有兴趣的同同学可以自行尝试。

    3、CJSON和HPack压缩算法:

    这两种都是针对json数据结构压缩的算法。其主要思路都是将原始json数据抽离成 Template 与 Value,节省掉重复的 "Key 值"。1)cjson压缩:

    例如,一个原始json:

    [
        {
            "x": 100,
            "y": 100
        },
        {
            "x": 100,
            "y": 100,
            "width": 200,
            "height": 150
        },
        {},
    ]
    

    使用cjson压缩后:

    {
        "templates": [
            [0,"x","y"],
            [1,"width","height"]
        ],
        "values": [
            {
                "values": [1,100,100 ] 
            },
            {
                "values": [2,100,100,200,150 ] 
            },
            {}
        ]
    }
    

    2)hpack压缩:

    hpack是一个无损、跨语言、注重性能的数据集压缩程序。它能够将用于表示泛型同构集合的字符数减少70%。此算法提供了多个级别的压缩(从0到4)。级别0压缩通过从结构中删除键(属性名)来执行最基本的压缩,该结构在索引0上创建一个具有每个属性名的头。下一个级别允许通过假设存在重复的条目来进一步减小JSON的大小。
    原始json:

    [{
     
      name : "Andrea",
     
      age : 31,
     
      gender : "Male",
     
      skilled : true
     
    }, {
     
      name : "Eva",
     
      age : 27,
     
      gender : "Female",
     
      skilled : true
     
    }, {
     
      name : "Daniele",
     
      age : 26,
     
      gender : "Male",
     
      skilled: false
     
    }]

    压缩后:

    [
        [ "name","age","gender","skilled"],
        ["Andrea",31,"Male", true],
        [ "Eva", 27,"Female",true],
        ["Daniele",26,"Male",false]
    ]
    

    结论:
    两种方法都是主要讲json 的 键抽出来统一建成索引,只是最后的格式不同,HPack 简化后的格式比CJSON 少了许多字符,所以HPack 的压缩效率比较高, 如果 JSON 内容太少, CJSON的资料可能反而会比较多。

    参考:

    https://blog.csdn.net/ZYC88888/article/details/104697362

    展开全文
  • 数据压缩的历史、常用算法原理

    万次阅读 2019-05-28 14:58:13
    数据压缩的概念相当古老,可以追溯到发明了摩尔斯码的19世纪中期。 摩尔斯码的发明,是为了使电报员能够通过电报系统,利用一系列可听到的脉冲信号传递字母信息,从而实现文字消息的传输。摩尔斯码的发明者意识到,...

    压缩,是为了减少存储空间而把数据转换成比原始格式更紧凑形式的过程。数据压缩的概念相当古老,可以追溯到发明了摩尔斯码的19世纪中期。

    摩尔斯码的发明,是为了使电报员能够通过电报系统,利用一系列可听到的脉冲信号传递字母信息,从而实现文字消息的传输。摩尔斯码的发明者意识到,某些字母比其他字母使用地更频繁(例如E比X更常见),因此决定使用短的脉冲信号来表示常用字母,而使用较长的脉冲信号表示非常用字母。这个基本的压缩方案有效地改善了系统的整体效率,因为它使电报员在更短的时间内传输了更多的信息。

    虽然现代的压缩流程比摩尔斯码要复杂地多,但是它们仍然使用着相同的基本原理,也就是我们这篇文章中将要讲述的内容。这些概念对我们如今的计算机世界高效运行至关重要——互联网上从本地与云端存储到数据流的一切东西都严重依赖压缩算法,离开了它很可能会变得非常低效。

    压缩管道

    下图展示了压缩方案的通用流程。原始的输入数据包含我们需要压缩或减小尺寸的符号序列。这些符号被压缩器编码,输出结果是编码过的数据。需要注意的是,虽然通常编码后的数据要比原始输入数据小,但是也有例外情况(我们后面会讲到)。

    这里写图片描述

    通常在之后的某个时间,编码后的数据会被输入到一个解压缩器,在这里数据被解码、重建,并以符号序列的形式输出原始数据。注意,本文我们会交替地使用“序列”和“串”来指一个符号序列集。

    如果输出数据和输入数据始终完全相同,那么这个压缩方案被称为无损的,也称无损编码器。否则,它就是一个有损的压缩方案。

    • 无损压缩方案通常被用来压缩文本,可执行程序,或者其他任何需要完全重建数据的地方。
    • 有损压缩方案在图像,音频,视频,或者其他为了提高压缩效率而可以接受某些程度信息丢失的场合很有用处。

    数据模型

    信息的定义是度量一个数据片段复杂度的量。一个数据集拥有越多的信息,它就越难被压缩。稀有的概念和信息的概念是相关的,因为稀有符号的出现比常见符号的出现提供了更多的信息。

    例如,“日本的一次地震”的出现比“月球的一次地震”提供的信息号少,因为月球上的地震很不常见。我们可以预期,大多数压缩算法在压缩一个符号时,能够仔细地考虑它出现的频率或几率。

    我们把压缩算法降低信息负载的有效性,称为它的效率。一个效率更高的压缩算法相比效率低的压缩算法,能够更多地降低特定数据集的大小。

    概率模型

    设计一个压缩方案的最重要一步,是为数据创建一个概率模型。这个模型允许我们测量数据的特征,达到有效的适应压缩算法的目的。为了使它更加清晰一些,让我们浏览一下建模过程的部分环节。

    假设我们有一个字母表G,它由数据集中所有可能出现的字符组成。在我们的例子中,G包含4个字符:从A到D。 
    这里写图片描述

    我们还有一个概率统计函数P,它定义了在输入数据串中,G中每个字符出现的概率。在输入数据串中,概率高的符号比概率低的符号更有可能出现。 
    这里写图片描述

    在这个例子中,我们假定符号是独立同分布的。在源数据串中,一个符号的出现与其他任何符号没有相关性。

    最小编码率

    B是最常见的符号,出现的概率是40%;而C是最不常见的符号,它的出现概率只有10%。我们的目标是设计一个压缩方案,它对于常见符号使所需存储空间最小化,同时它支持使用更多的必要空间来存储不常见符号。这个折衷是压缩的基本原理,并且已经存在于几乎所有的压缩算法中。

    有了字母表,我们可以小试身手,来定义一个基本的压缩方案。如果我们简单地把一个符号编码为8比特的ASCII值,那么我们的压缩效率,即编码率,将是8比特/符号。假定我们对只包含4个符号的字母表改进这个方案。如果我们为每个符号分配2个比特,我们仍然能够完全重建编码过的数据串,而只需要1/4的空间。

    ASCII 
    在计算机中,所有的数据在存储和运算时都要使用二进制数表示(因为计算机用高电平和低电平分别表示1和0),例如,像a、b、c、d这样的52个字母(包括大写)、以及0、1等数字还有一些常用的符号(例如*、#、@等)在计算机中存储时也要使用二进制数来表示,而具体用哪些二进制数字表示哪个符号,当然每个人都可以约定自己的一套(这就叫编码),而大家如果要想互相通信而不造成混乱,那么大家就必须使用相同的编码规则,于是美国有关的标准化组织就出台了ASCII编码,统一规定了上述常用符号用哪些二进制数来表示。 
    它是现今最通用的单字节编码系统

    这时候,我们已经显著地提升了编码率(从8到2比特/符号),但是完全忽视了我们的概率模型。正如前面提到的,我们可以结合模型发明一个策略,通过对常见符号(B和D)使用更少的比特,对不常见符号(A和C)使用更多的比特,以提高编码效率。

    这提出了一个在香农开创性论文中描述的重要观点——我们可以简单地基于符号(或事件)的概率,定义它的理论最小存储空间。我们如下定义一个符号的最小编码率: 
    这里写图片描述 
    例如,如果一个符号出现的概率是50%,那么它绝对最少需要一个字节来存储。

    熵和冗余

    更进一步,如果我们为字母表中的字符计算最小编码率的加权平均值,我们得到一个被称作香农熵的值,简单地称作模型的熵。熵被定义为给定模型的最小编码率。它建立在字母表和它的概率模型之上,如下描述。 
    这里写图片描述 
    正如你预料的一样,拥有更多罕见符号的模型,比拥有较少并且常见符号的模型的熵要高。更进一步,熵值更高的模型比熵值低的模型更难压缩。 
    这里写图片描述 
    在我们当前的例子中,我们模型的熵值是1.85比特/符号。编码率(2)和熵值(1.85)的差值被称作压缩方案的冗余。 
    这里写图片描述 
    在众多诸如加密和人工智能等不同的子领域,熵都是一个非常有用的话题。

    编码模型

    到目前为止,我们采取了一点点自由措施:自动地给出了我们符号的概率。在现实中,模型通常并不是容易得到的,我们可能通过分析源数据串(如在样例数据汇总统计符号概率),或者在压缩过程中自适应地学习,以得到这些概率值。不管是哪种情形,真实数据串的概率值不会完美地与模型匹配,而且我们会与这个差别正比例地损失压缩效率。基于这个原因,推导出(或恒定地保持)一个尽可能精确的模型是至关重要的。

    常见算法

    当我们为数据集定义了概率模型之后,我们就能够适当地利用这个模型设计出一个压缩方案。虽然开发一个新压缩算法的过程超出了本文的范围,但是我们可以利用已经存在的算法。下面我们回顾一些最流行的算法。

    下面的每一个算法都是一个顺序处理器,这就是说如果要重建已编码序列的第n个符号,必须先对第0..(n-1)个符号进行解码。由于编码后数据的不定长特性,寻找操作是不可能的——解码器在不解码前面的符号的情况下,无法直接跳转到符号n的正确偏移位置。另外,一些编码方案依赖于顺序处理每个符号时保持的内部历史状态。

    霍夫曼编码

    这是一个最为广泛知晓的压缩方案。它能够追溯到19世纪50年代,David Huffman在他的论文“一种构建极小多余编码的方法”中第一次描述了这种方法。霍夫曼编码通过得到给定字母表的最优前缀码工作。

    一个前缀码代表一个数值,并使字母表中的每个符号的前缀码不会成为另一个符号前缀码的前缀。例如,如果0是我们第一个符号A的前缀码,那么字母表中的其他符号都不能以0开始。由于前缀码使比特流解码变得清晰明确,因此很有用。

    字典方法

    这种类型的编码器使用一个字典来保存最近发现的符号。当遇到一个符号时,首先会在字典中查找它,检查是否已经存储过了。如果是,那么输出将只包含字典入口的引用(通常是一个偏移量),而不是整个符号。

    使用字典方法的压缩方案包括LZ77 and LZ78,它们是很多不同的无损压缩方案的基础。

    在一些情况下,会使用一个滑动窗口来自适应地追踪最近发现的符号。这种情况下,一个符号只在相对较近发现时才会保存在字典中。否则,符号被剔除(之后再出现可能会重新加入字典)。这个过程防止符号字典变得过大,并利用了一个事实,即序列中的符号会在相对短的窗口内重复出现。

    哥伦布指数编码

    假设你有一个由0到255范围内的整数组成的字母表,并且一个符号的出现概率与它到0的距离有关。这样,比较小的值是最常见的,而值越大出现的概率越小。

    和大多数压缩方案一样,哥伦布编码的效率非常依赖于输入序列中的特定符号。包含很多大值的序列与包含较少大值的序列相比,压缩效果更差一些;在某些情况下,经过哥伦布编码后的序列甚至可能比原始输入串的尺寸更大。

    算数编码

    算数编码是一个比较新的压缩算法,在最近(过去的15年里)得到了极大的普及,特别是媒体压缩方面。算数编码器是一种高效率,计算密集型,具有时序性的编码器。

    一个常见的算数编码变种,二进制算数编码,使用只包含两个符号(0和1)的字母表。这个变种特别有用处,因为它简化了编码器的设计,降低了运行时的计算代价,并且在编码器和解码器处理一个字母表和模型时,不需要任何显式的通讯。

    行程长度编码

    到现在为止,我们已经假设源符号是独立同分布的。我们的概率模型和编码率与熵的计算方法都依赖于这个事实。但是,如果我们的符号序列不满足这个要求呢?

    假设我们序列中符号的重复度很高,并且一个特定符号的出现有力地表明,它的重复实例即将跟随出现。这种情况下,我们可以选择使用另一个称作行程长度编码的编码方案。这种技术在符号重复度很高时表现良好,而在重复度低时表现较差。

    行程长度编码器预测数据串中连续重复符号的长度,并使用这个符号和重复次数来替代它们。

    常见的数据压缩算法

    (1).LZW压缩

            LZW压缩是一种无损压缩,应用于gif图片。适用于数据中存在大量重固子串的情况。

    原理:

           LZW算法中,首先建立一个字符串表,把每一个第一次出现的字符串放入串表中,并用一个数字来表示,这个数字与此字符串在串表中的位置有关,并将这个数字存入压缩文件中,如果这个字符串再次出现时,即可用表示它的数字来代替,并将这个数字存入文件中。压缩完成后将串表丢弃。如"print" 字符串,如果在压缩时用266表示,只要再次出现,均用266表示,并将"print"字符串存入串表中,在图象解码时遇到数字266,即可从串表中查出266所代表的字符串"print",在解压缩时,串表可以根据压缩数据重新生成。

    编码过程:

         编码后输出:41 42 52 41 43 41 44 81 83 82 88 41 80。输入为17个7位ASC字符,总共119位,输出为13个8位编码,总共104位,压缩比为87%。

    解码过程:

         对输出的41 42 52 41 43 41 44 81 83 82 88 41 80进行解码,如下表所示:

    解码后输出:

    ABRACADABRABRABRA

    特殊标记:
           随着新的串(string)不断被发现,标号也会不断地增长,如果原数据过大,生成的标号集(string table)会越来越大,这时候操作这个集合就会产生效率问题。如何避免这个问题呢?Gif在采用lzw算法的做法是当标号集足够大的时候,就不能增大了,干脆从头开始再来,在这个位置要插入一个标号,就是清除标志CLEAR,表示从这里我重新开始构造字典,以前的所有标记作废,开始使用新的标记。
          这时候又有一个问题出现,足够大是多大?这个标号集的大小为比较合适呢?理论上是标号集大小越大,则压缩比率就越高,但开销也越高。 一般根据处理速度和内存空间连个因素来选定。GIF规范规定的是12位,超过12位的表达范围就推倒重来,并且GIF为了提高压缩率,采用的是变长的字长。比如说原始数据是8位,那么一开始,先加上一位再说,开始的字长就成了9位,然后开始加标号,当标号加到512时,也就是超过9为所能表达的最大数据时,也就意味着后面的标号要用10位字长才能表示了,那么从这里开始,后面的字长就是10位了。依此类推,到了2^12也就是4096时,在这里插一个清除标志,从后面开始,从9位再来。

          GIF规定的清除标志CLEAR的数值是原始数据字长表示的最大值加1,如果原始数据字长是8,那么清除标志就是256,如果原始数据字长为4那么就是16。另外GIF还规定了一个结束标志END,它的值是清除标志CLEAR再加1。由于GIF规定的位数有1位(单色图),4位(16色)和8位(256色),而1位的情况下如果只扩展1位,只能表示4种状态,那么加上一个清除标志和结束标志就用完了,所以1位的情况下就必须扩充到3位。其它两种情况初始的字长就为5位和9位。

    代码示例:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <algorithm>
    #include <vector>
    using namespace std;
    long len=0;//原字符串的长度
    long loc=0;//去重之后字符串的长度
    map<string,long> dictionary;
    vector <long> result;
    #define MAX 100;
    void LZWcode(string a,string s)
    {
        //memset(&result,0,sizeof(int));
        string W,K;
        for(long i=0;i<loc;i++)
        {
            string s1;
            s1=s[i];//将单个字符转换为字符串
            dictionary[s1]=i+1;
        }
        W=a[0];
        loc+=1;
        for(int i=0;i<len-1;i++)
        {
            K=a[i+1];
            string firstT=W;
            string secontT=W;
            if(dictionary.count(firstT.append(K))!=0)//map的函数count(n),返回的是map容器中出现n的次数
                W=firstT;
            else
            {
                result.push_back(dictionary[W]);
                dictionary[secontT.append(K)]=loc++;
                W=K;
            }
        }
        if(!W.empty())
            result.push_back(dictionary[W]);
        for(int i=0;i<result.size();i++)
            cout<<result[i];
    }
     
    void LZWdecode(int *s,int n)
    {
        string nS;
        for(int i=0;i<n;i++)
            for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)
                if(it->second==s[i])
                {
                    cout<<it->first<<" ";
                }
        for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)//输出压缩编码的字典表
            cout<<it->first<<" "<<it->second<<endl;
    }
    int main(int argc, char const *argv[])
    {
        cout<<"本程序的解码是根据输入的编码字符进行的解码,并不是全256 的字符"<<endl;
        cout<<"选择序号:"<<endl;
        cout<<"1.压缩编码   2.解码"<<endl;
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            switch(n)
            {
                case 1:
                {
                    char s[100],a[100];
                    cout<<"输入一串字符:"<<endl;
                    cin>>s;
                    len=strlen(s);
                    for(int i=0;i<len;i++)
                        a[i]=s[i];
                    sort(s,s+len);//排序
                    loc=unique(s,s+len)-s;//去重
                    LZWcode(a,s);
                    break;
                }
                case 2:
                {
                    cout<<"输入解码数组的长度:"<<endl;
                    int changdu;
                    cin>>changdu;
                    cout<<"输入解码数串(每个数串以空格隔开):"<<endl;
                    int s[changdu];
                    for(int i=0;i<changdu;i++)
                        cin>>s[i];
                    LZWdecode(s, changdu);
                    break;
                }
                default:
                    cout<<"你的输入不正确,请从重新开始"<<endl;
            }
            if(n==2)
            {
                auto iter=result.begin();   // 每次正确输入结束后对结果进行清零
                while(iter!=result.end())
                    result.erase(iter++);
            }
        }
        return 0;
    }

    (2).霍夫曼压缩

          哈夫曼编码是无损压缩当中最好的方法。它使用预先二进制描述来替换每个符号,长度由特殊符号出现的频率决定。常见的符号需要很少的位来表示,而不常见的符号需要很多位来表示。哈夫曼算法在改变任何符号二进制编码引起少量密集表现方面是最佳的。然而,它并不处理符号的顺序和重复或序号的序列。

    原理:

         利用数据出现的次数构造Huffman二叉树,并且出现次数较多的数据在树的上层,出现次数较少的数据在树的下层。于是,我们就可以从根节点到每个数据的路径来进行编码并实现压缩。

    编码过程:


    假设有一个包含100000个字符的数据文件要压缩存储。各字符在该文件中的出现频度如下所示:

           在此,我会给出常规编码的方法和Huffman编码两种方法,这便于我们比较。

           常规编码方法:我们为每个字符赋予一个三位的编码,于是有:


           此时,100000个字符进行编码需要100000 * 3 = 300000位。

           Huffman编码:利用字符出现的频度构造二叉树,构造二叉树的过程也就是编码的过程。

    这种情况下,对100000个字符编码需要:(45 * 1 + (16 + 13 + 12 + 9)*3 + (9 + 5)*4) * 1000 = 224000

     

    孰好孰坏,例子说明了一切!好了,老规矩,下面我还是用上面的例子详细说明一下Huffman编码的过程。

           首先,我们需要统计出各个字符出现的次数,如下:

           接下来,我根据各个字符出现的次数对它们进行排序,如下:

           好了,一切准备工作就绪。

           在上文我提到,huffman编码的过程其实就是构造一颗二叉树的过程,那么我将各个字符看成树中将要构造的各个节点,将字符出现的频度看成权值。Ok,有了这个思想,here we go!

           构造huffman编码二叉树规则:

    从小到大,从底向上,依次排开,逐步构造。

           首先,根据构造规则,我将各个字符看成构造树的节点,即有节点a、b、c、d、e、f。那么,我先将节点f和节点e合并,如下图:

    于是就有:

    经过排序处理得:

            接下来,将节点b和节点c也合并,则有:

           于是有:

           经过排序处理得:

           第三步,将节点d和节点fe合并,得:

           于是有:

           继续,这次将节点fed和节点bc合并,得:

           于是有:

           最后,将节点a和节点bcfed合并,有:

           以上步骤就是huffman二叉树的构造过程,完整的树如下:

           二叉树成了,最后就剩下编码了,编码的规则为:左0右1

           于是根据编码规则得到我们最终想要的结果:

           从上图中我们得到各个字符编码后的编码位:


    代码示例:

    哈夫曼树结构:

    struct element
    {
        int weight;        // 权值域
        int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
    };


    weight保存结点权值;lchild保存该节点的左孩子在数组中的下标;rchild保存该节点的右孩子在数组中的下标;parent保存该节点的双亲孩子在数组中的下标。

    哈夫曼算法的C++实现:

    #include<iostream>
    #include <iomanip>
     
    using namespace std;
    // 哈夫曼树的结点结构
    struct element
    {
        int weight;        // 权值域
        int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
    };
    // 选取权值最小的两个结点
    void selectMin(element a[],int n, int &s1, int &s2)
    {
        for (int i = 0; i < n; i++)
        {
            if (a[i].parent == -1)// 初始化s1,s1的双亲为-1
            {
                s1 = i;
                break;
            }
        }
        for (int i = 0; i < n; i++)// s1为权值最小的下标
        {
            if (a[i].parent == -1 && a[s1].weight > a[i].weight)
                s1 = i;
        }
        for (int j = 0; j < n; j++)
        {
            if (a[j].parent == -1&&j!=s1)// 初始化s2,s2的双亲为-1
            {
                s2 = j;
                break;
            }
        }
        for (int j = 0; j < n; j++)// s2为另一个权值最小的结点
        {
            if (a[j].parent == -1 && a[s2].weight > a[j].weight&&j != s1)
                s2 = j;
        }
    }
    // 哈夫曼算法
    // n个叶子结点的权值保存在数组w中
    void HuffmanTree(element huftree[], int w[], int n)
    {
        for (int i = 0; i < 2*n-1; i++)    // 初始化,所有结点均没有双亲和孩子
        {
            huftree[i].parent = -1;
            huftree[i].lchild = -1;
            huftree[i].rchild = -1;
        }
        for (int i = 0; i < n; i++)    // 构造只有根节点的n棵二叉树
        {
            huftree[i].weight = w[i];
        }
        for (int k = n; k < 2 * n - 1; k++) // n-1次合并
        {
            int i1, i2; 
            selectMin(huftree, k, i1, i2); // 查找权值最小的俩个根节点,下标为i1,i2
            // 将i1,i2合并,且i1和i2的双亲为k
            huftree[i1].parent = k;
            huftree[i2].parent = k;
            huftree[k].lchild = i1;
            huftree[k].rchild = i2;
            huftree[k].weight = huftree[i1].weight + huftree[i2].weight;
        }
        
    }
      // 打印哈夫曼树
    void print(element hT[],int n)
    {
        cout << "index weight parent lChild rChild" << endl;
        cout << left;    // 左对齐输出 
        for (int i = 0; i < n; ++i) 
        {
            cout << setw(5) << i << " ";
            cout << setw(6) << hT[i].weight << " ";
            cout << setw(6) << hT[i].parent << " ";
            cout << setw(6) << hT[i].lchild << " ";
            cout << setw(6) << hT[i].rchild << endl;
        }
    }
    int main()
    {
        int x[] = { 5,29,7,8,14,23,3,11 };        // 权值集合
        element *hufftree=new element[2*8-1];    // 动态创建数组
        HuffmanTree(hufftree, x, 8);
        print(hufftree,15);
        system("pause");
        return 0;
    }


    说明:

          parent域值是判断结点是否写入哈夫曼树的唯一条件,parent的初始值为-1,当某结点加入时,parent域的值就设置为双亲结点在数组的下标。构造哈夫曼树时,首先将n个权值的叶子结点存放到数组haftree的前n个分量中,然后不断将两棵子树合并为一棵子树,并将新子树的根节点顺序存放到数组haftree的前n个分量的后面。

    (3).游程编码(RLC)

               游程编码又称“运行长度编码”或“行程编码”,是一种无损压缩编码,JPEG图片压缩就用此方法,很多栅格数据压缩也是采用这种方法。

               栅格数据如图3-1所示:

                                                       

                                                                         3-1 栅格数据

      原理:

             用一个符号值或串长代替具有相同值的连续符号(连续符号构成了一段连续的“行程”。行程编码因此而得名),使符号长度少于原始数据的长度。只在各行或者各列数据的代码发生变化时,一次记录该代码及相同代码重复的个数,从而实现数据的压缩。

            常见的游程编码格式包括TGA,Packbits,PCX以及ILBM。
    例如:5555557777733322221111111
    行程编码为:(5,6)(7,5)(3,3)(2,4)(1,7)。可见,行程编码的位数远远少于原始字符串的位数。
    并不是所有的行程编码都远远少于原始字符串的位数,但行程编码也成为了一种压缩工具。
    例如:555555 是6个字符 而(5,6)是5个字符,这也存在压缩量的问题,自然也会出现其他方式的压缩工具。
    在对图像数据进行编码时,沿一定方向排列的具有相同灰度值的像素可看成是连续符号,用字串代替这些连续符号,可大幅度减少数据量。

            游程编码记录方式有两种:①逐行记录每个游程的终点列号:②逐行记录每个游程的长度(像元数)

    第一种方式:

            

          上面的栅格图形可以记为:A,3  B,5  A,1  C,4  A,5

          第二种就记作:A,3  B,2  A,1  C,3   A,1

         行程编码是连续精确的编码,在传输过程中,如果其中一位符号发生错误,即可影响整个编码序列,使行程编码无法还原回原始数据。

    代码示例:

           根据输入的字符串,得到大小写不敏感压缩后的结果(即所有小写字母均视为相应的大写字母)。输入一个字符串,长度大于0,且不超过1000,全部由大写或小写字母组成。输出输出为一行,表示压缩结果,形式为:
    (A,3)(B,4)(C,1)(B,2)

          即每对括号内部分别为字符(都为大写)及重复出现的次数,不含任何空格。

    样例输入:aAABBbBCCCaaaaa

    样例输出:(A,3)(B,4)(C,3)(A,5)

    #include<stdio.h>
    #include<string.h>
    char a[1001];
    int main()
    {
        char t;
        int i;
    gets(a);
    int g=1;
    int k=strlen(a);
    if(a[0]>='a'&&a[0]<='z')
        a[0]-=32;
      t=a[0];
    for(i=1;i<=k;i++)
    {
      if(a[i]>='a'&&a[i]<='z')
      a[i]-=32;
      if(a[i]==t)
          g++;
    if(a[i]!=t)
      {
        printf("(%c,%d)",t,g);
         g=1;
           t=a[i];
      }
    }return 0;
    }


    应用场景:

    (1).区域单色影像图

    (2).红外识别图形

    (3).同色区块的彩色图形

     

    展开全文
  • 深入解析数据压缩算法

    万次阅读 多人点赞 2018-05-06 10:30:45
    1、为什么要做数据压缩? 数据压缩的主要目的还是减少数据传输或者转移过程中的数据量。2、什么是数据压缩? 是指在不丢失信息的前提下,缩减数据量以减少存储空间,提高传输、存储和处理效率的一种技术方法。或者...

    1、为什么要做数据压缩?

           数据压缩的主要目的还是减少数据传输或者转移过程中的数据量。

    2、什么是数据压缩?

            是指在不丢失信息的前提下,缩减数据量以减少存储空间,提高传输、存储和处理效率的一种技术方法。或者是按照一定的算法对数据进行重新组织,减少数据的冗余和存储的空间。

      3、常见的数据压缩算法

    (1).LZW压缩

            LZW压缩是一种无损压缩,应用于gif图片。适用于数据中存在大量重固子串的情况。

    原理:

           LZW算法中,首先建立一个字符串表,把每一个第一次出现的字符串放入串表中,并用一个数字来表示,这个数字与此字符串在串表中的位置有关,并将这个数字存入压缩文件中,如果这个字符串再次出现时,即可用表示它的数字来代替,并将这个数字存入文件中。压缩完成后将串表丢弃。如"print" 字符串,如果在压缩时用266表示,只要再次出现,均用266表示,并将"print"字符串存入串表中,在图象解码时遇到数字266,即可从串表中查出266所代表的字符串"print",在解压缩时,串表可以根据压缩数据重新生成。

    编码过程:


         编码后输出:41 42 52 41 43 41 44 81 83 82 88 41 80。输入为17个7位ASC字符,总共119位,输出为13个8位编码,总共104位,压缩比为87%。

    解码过程:

         对输出的41 42 52 41 43 41 44 81 83 82 88 41 80进行解码,如下表所示:


    解码后输出:

    ABRACADABRABRABRA

    特殊标记:
           随着新的串(string)不断被发现,标号也会不断地增长,如果原数据过大,生成的标号集(string table)会越来越大,这时候操作这个集合就会产生效率问题。如何避免这个问题呢?Gif在采用lzw算法的做法是当标号集足够大的时候,就不能增大了,干脆从头开始再来,在这个位置要插入一个标号,就是清除标志CLEAR,表示从这里我重新开始构造字典,以前的所有标记作废,开始使用新的标记。
          这时候又有一个问题出现,足够大是多大?这个标号集的大小为比较合适呢?理论上是标号集大小越大,则压缩比率就越高,但开销也越高。 一般根据处理速度和内存空间连个因素来选定。GIF规范规定的是12位,超过12位的表达范围就推倒重来,并且GIF为了提高压缩率,采用的是变长的字长。比如说原始数据是8位,那么一开始,先加上一位再说,开始的字长就成了9位,然后开始加标号,当标号加到512时,也就是超过9为所能表达的最大数据时,也就意味着后面的标号要用10位字长才能表示了,那么从这里开始,后面的字长就是10位了。依此类推,到了2^12也就是4096时,在这里插一个清除标志,从后面开始,从9位再来。

          GIF规定的清除标志CLEAR的数值是原始数据字长表示的最大值加1,如果原始数据字长是8,那么清除标志就是256,如果原始数据字长为4那么就是16。另外GIF还规定了一个结束标志END,它的值是清除标志CLEAR再加1。由于GIF规定的位数有1位(单色图),4位(16色)和8位(256色),而1位的情况下如果只扩展1位,只能表示4种状态,那么加上一个清除标志和结束标志就用完了,所以1位的情况下就必须扩充到3位。其它两种情况初始的字长就为5位和9位。

    代码示例:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <algorithm>
    #include <vector>
    using namespace std;
    long len=0;//原字符串的长度
    long loc=0;//去重之后字符串的长度
    map<string,long> dictionary;
    vector <long> result;
    #define MAX 100;
    void LZWcode(string a,string s)
    {
        //memset(&result,0,sizeof(int));
        string W,K;
        for(long i=0;i<loc;i++)
        {
            string s1;
            s1=s[i];//将单个字符转换为字符串
            dictionary[s1]=i+1;
        }
        W=a[0];
        loc+=1;
        for(int i=0;i<len-1;i++)
        {
            K=a[i+1];
            string firstT=W;
            string secontT=W;
            if(dictionary.count(firstT.append(K))!=0)//map的函数count(n),返回的是map容器中出现n的次数
                W=firstT;
            else
            {
                result.push_back(dictionary[W]);
                dictionary[secontT.append(K)]=loc++;
                W=K;
            }
        }
        if(!W.empty())
            result.push_back(dictionary[W]);
        for(int i=0;i<result.size();i++)
            cout<<result[i];
    }
    
    void LZWdecode(int *s,int n)
    {
        string nS;
        for(int i=0;i<n;i++)
            for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)
                if(it->second==s[i])
                {
                    cout<<it->first<<" ";
                }
        for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)//输出压缩编码的字典表
            cout<<it->first<<" "<<it->second<<endl;
    }
    int main(int argc, char const *argv[])
    {
        cout<<"本程序的解码是根据输入的编码字符进行的解码,并不是全256 的字符"<<endl;
        cout<<"选择序号:"<<endl;
        cout<<"1.压缩编码   2.解码"<<endl;
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            switch(n)
            {
                case 1:
                {
                    char s[100],a[100];
                    cout<<"输入一串字符:"<<endl;
                    cin>>s;
                    len=strlen(s);
                    for(int i=0;i<len;i++)
                        a[i]=s[i];
                    sort(s,s+len);//排序
                    loc=unique(s,s+len)-s;//去重
                    LZWcode(a,s);
                    break;
                }
                case 2:
                {
                    cout<<"输入解码数组的长度:"<<endl;
                    int changdu;
                    cin>>changdu;
                    cout<<"输入解码数串(每个数串以空格隔开):"<<endl;
                    int s[changdu];
                    for(int i=0;i<changdu;i++)
                        cin>>s[i];
                    LZWdecode(s, changdu);
                    break;
                }
                default:
                    cout<<"你的输入不正确,请从重新开始"<<endl;
            }
            if(n==2)
            {
                auto iter=result.begin();   // 每次正确输入结束后对结果进行清零
                while(iter!=result.end())
                    result.erase(iter++);
            }
        }
        return 0;
    }
    

    (2).霍夫曼压缩

          哈夫曼编码是无损压缩当中最好的方法。它使用预先二进制描述来替换每个符号,长度由特殊符号出现的频率决定。常见的符号需要很少的位来表示,而不常见的符号需要很多位来表示。哈夫曼算法在改变任何符号二进制编码引起少量密集表现方面是最佳的。然而,它并不处理符号的顺序和重复或序号的序列。

    原理:

         利用数据出现的次数构造Huffman二叉树,并且出现次数较多的数据在树的上层,出现次数较少的数据在树的下层。于是,我们就可以从根节点到每个数据的路径来进行编码并实现压缩。

    编码过程:

    假设有一个包含100000个字符的数据文件要压缩存储。各字符在该文件中的出现频度如下所示:

           在此,我会给出常规编码的方法和Huffman编码两种方法,这便于我们比较。

           常规编码方法:我们为每个字符赋予一个三位的编码,于是有:


           此时,100000个字符进行编码需要100000 * 3 = 300000位。


           Huffman编码:利用字符出现的频度构造二叉树,构造二叉树的过程也就是编码的过程。

    这种情况下,对100000个字符编码需要:(45 * 1 + (16 + 13 + 12 + 9)*3 + (9 + 5)*4) * 1000 = 224000

     

    孰好孰坏,例子说明了一切!好了,老规矩,下面我还是用上面的例子详细说明一下Huffman编码的过程。

           首先,我们需要统计出各个字符出现的次数,如下:

           接下来,我根据各个字符出现的次数对它们进行排序,如下:

           好了,一切准备工作就绪。

           在上文我提到,huffman编码的过程其实就是构造一颗二叉树的过程,那么我将各个字符看成树中将要构造的各个节点,将字符出现的频度看成权值。Ok,有了这个思想,here we go!

           构造huffman编码二叉树规则:

    从小到大,

    从底向上,

    依次排开,

    逐步构造。

           首先,根据构造规则,我将各个字符看成构造树的节点,即有节点a、b、c、d、e、f。那么,我先将节点f和节点e合并,如下图:

    于是就有:

    经过排序处理得:

     

            接下来,将节点b和节点c也合并,则有:

           于是有:

           经过排序处理得:

           第三步,将节点d和节点fe合并,得:

           于是有:

           继续,这次将节点fed和节点bc合并,得:

           于是有:

           最后,将节点a和节点bcfed合并,有:

           以上步骤就是huffman二叉树的构造过程,完整的树如下:

           二叉树成了,最后就剩下编码了,编码的规则为:01

           于是根据编码规则得到我们最终想要的结果:

           从上图中我们得到各个字符编码后的编码位:


    代码示例:

    哈夫曼树结构:

    struct element
    {
        int weight;        // 权值域
        int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
    };

    weight保存结点权值;lchild保存该节点的左孩子在数组中的下标;rchild保存该节点的右孩子在数组中的下标;parent保存该节点的双亲孩子在数组中的下标。

    哈夫曼算法的C++实现:

    #include<iostream>
    #include <iomanip>
    
    using namespace std;
    // 哈夫曼树的结点结构
    struct element
    {
        int weight;        // 权值域
        int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
    };
    // 选取权值最小的两个结点
    void selectMin(element a[],int n, int &s1, int &s2)
    {
        for (int i = 0; i < n; i++)
        {
            if (a[i].parent == -1)// 初始化s1,s1的双亲为-1
            {
                s1 = i;
                break;
            }
        }
        for (int i = 0; i < n; i++)// s1为权值最小的下标
        {
            if (a[i].parent == -1 && a[s1].weight > a[i].weight)
                s1 = i;
        }
        for (int j = 0; j < n; j++)
        {
            if (a[j].parent == -1&&j!=s1)// 初始化s2,s2的双亲为-1
            {
                s2 = j;
                break;
            }
        }
        for (int j = 0; j < n; j++)// s2为另一个权值最小的结点
        {
            if (a[j].parent == -1 && a[s2].weight > a[j].weight&&j != s1)
                s2 = j;
        }
    }
    // 哈夫曼算法
    // n个叶子结点的权值保存在数组w中
    void HuffmanTree(element huftree[], int w[], int n)
    {
        for (int i = 0; i < 2*n-1; i++)    // 初始化,所有结点均没有双亲和孩子
        {
            huftree[i].parent = -1;
            huftree[i].lchild = -1;
            huftree[i].rchild = -1;
        }
        for (int i = 0; i < n; i++)    // 构造只有根节点的n棵二叉树
        {
            huftree[i].weight = w[i];
        }
        for (int k = n; k < 2 * n - 1; k++) // n-1次合并
        {
            int i1, i2; 
            selectMin(huftree, k, i1, i2); // 查找权值最小的俩个根节点,下标为i1,i2
            // 将i1,i2合并,且i1和i2的双亲为k
            huftree[i1].parent = k;
            huftree[i2].parent = k;
            huftree[k].lchild = i1;
            huftree[k].rchild = i2;
            huftree[k].weight = huftree[i1].weight + huftree[i2].weight;
        }
        
    }
      // 打印哈夫曼树
    void print(element hT[],int n)
    {
        cout << "index weight parent lChild rChild" << endl;
        cout << left;    // 左对齐输出 
        for (int i = 0; i < n; ++i) 
        {
            cout << setw(5) << i << " ";
            cout << setw(6) << hT[i].weight << " ";
            cout << setw(6) << hT[i].parent << " ";
            cout << setw(6) << hT[i].lchild << " ";
            cout << setw(6) << hT[i].rchild << endl;
        }
    }
    int main()
    {
        int x[] = { 5,29,7,8,14,23,3,11 };        // 权值集合
        element *hufftree=new element[2*8-1];    // 动态创建数组
        HuffmanTree(hufftree, x, 8);
        print(hufftree,15);
        system("pause");
        return 0;
    }

    说明:

          parent域值是判断结点是否写入哈夫曼树的唯一条件,parent的初始值为-1,当某结点加入时,parent域的值就设置为双亲结点在数组的下标。构造哈夫曼树时,首先将n个权值的叶子结点存放到数组haftree的前n个分量中,然后不断将两棵子树合并为一棵子树,并将新子树的根节点顺序存放到数组haftree的前n个分量的后面。

    (3).游程编码(RLC)

               游程编码又称“运行长度编码”或“行程编码”,是一种无损压缩编码,JPEG图片压缩就用此方法,很多栅格数据压缩也是采用这种方法。

               栅格数据如图3-1所示:

                                                       

                                                                         3-1 栅格数据

      原理:

             用一个符号值或串长代替具有相同值的连续符号(连续符号构成了一段连续的“行程”。行程编码因此而得名),使符号长度少于原始数据的长度。只在各行或者各列数据的代码发生变化时,一次记录该代码及相同代码重复的个数,从而实现数据的压缩。

            常见的游程编码格式包括TGA,Packbits,PCX以及ILBM。
    例如:5555557777733322221111111
    行程编码为:(5,6)(7,5)(3,3)(2,4)(1,7)。可见,行程编码的位数远远少于原始字符串的位数。
    并不是所有的行程编码都远远少于原始字符串的位数,但行程编码也成为了一种压缩工具。
    例如:555555 是6个字符 而(5,6)是5个字符,这也存在压缩量的问题,自然也会出现其他方式的压缩工具。
    在对图像数据进行编码时,沿一定方向排列的具有相同灰度值的像素可看成是连续符号,用字串代替这些连续符号,可大幅度减少数据量。

            游程编码记录方式有两种:①逐行记录每个游程的终点列号:②逐行记录每个游程的长度(像元数)

    第一种方式:

            

          上面的栅格图形可以记为:A,3  B,5  A,1  C,4  A,5

          第二种就记作:A,3  B,2  A,1  C,3   A,1

         行程编码是连续精确的编码,在传输过程中,如果其中一位符号发生错误,即可影响整个编码序列,使行程编码无法还原回原始数据。

    代码示例:

           根据输入的字符串,得到大小写不敏感压缩后的结果(即所有小写字母均视为相应的大写字母)。输入一个字符串,长度大于0,且不超过1000,全部由大写或小写字母组成。输出输出为一行,表示压缩结果,形式为:
    (A,3)(B,4)(C,1)(B,2)

          即每对括号内部分别为字符(都为大写)及重复出现的次数,不含任何空格。

    样例输入:aAABBbBCCCaaaaa

    样例输出:(A,3)(B,4)(C,3)(A,5)

    #include<stdio.h>
    #include<string.h>
    char a[1001];
    int main()
    {
        char t;
        int i;
    gets(a);
    int g=1;
    int k=strlen(a);
    if(a[0]>='a'&&a[0]<='z')
        a[0]-=32;
      t=a[0];
    for(i=1;i<=k;i++)
    {
      if(a[i]>='a'&&a[i]<='z')
      a[i]-=32;
      if(a[i]==t)
          g++;
    if(a[i]!=t)
      {
        printf("(%c,%d)",t,g);
         g=1;
           t=a[i];
      }
    }return 0;
    }

    应用场景:

    (1).区域单色影像图

    (2).红外识别图形

    (3).同色区块的彩色图形

    参阅资料:

    https://blog.csdn.net/u012455213/article/details/45502573

    https://www.cnblogs.com/smile233/p/8184492.html

        说明:部分图源来自网络,感谢作者的分享。

    展开全文
  • 数据压缩算法该如何选择?

    万次阅读 热门讨论 2021-05-05 13:01:33
    写在前面 本文隶属于专栏《100个问题搞定大数据理论体系》,该专栏为笔者原创,引用请注明来源,...大数据需要处理海量数据,此时数据压缩非常重要。 在企业中存在的许多场景中,通常,数据源来自多种文本格式(CSV、TS
  • 基于哈夫曼树的数据压缩算法

    千次阅读 多人点赞 2019-05-13 13:14:40
    综合实验2 基于哈夫曼树的数据压缩算法 实验日期 2019.04.29 综合实验二 基于哈夫曼树的数据压缩算法 一、实验目的 1.掌握哈夫曼树的构造算法 2.掌握哈夫曼编码的构造算法 二、实验内容 输入一串字符串,根据给.....
  • 浅析数据压缩算法

    千次阅读 2017-05-17 15:51:17
    数据压缩是减少信息传输量最经济直接的办法,所以这篇文章将讲解一些经典的数据压缩算法。 一 热身:基因组 对于生物学的基因研究中,A、C、T、G是是用来表示生物DNA的四种碱基,对基因序列的处理实际上是对这四种...
  • HADOOP与HDFS数据压缩格式

    千次阅读 2018-10-17 18:20:11
    HADOOP与HDFS数据压缩格式 1、cloudera 数据压缩的一般准则 一般准则 是否压缩数据以及使用何种压缩格式对性能具有重要的影响。在数据压缩上,需要考虑的最重要的两个方面是 MapReduce 作业和存储在 HBase 中的...
  • 数据压缩知识点整理

    千次阅读 2017-04-27 16:57:20
    数据压缩 是指在不丢失有用信息的前提下, 缩减数据量 以减少存储空间, 提高传输、存储和处理效率, 或按照一定的算法对数据进行重新组织, 减少数据的冗余和存储的空间的一种技术.
  • 数据压缩算法—2无损压缩算法

    千次阅读 2018-12-12 20:55:43
      字典算法是最为简单的压缩算法之一。它是把文本中出现频率比较多的单词或词汇组合做成一个对应的字典列表,并用特殊代码来表示这个单词或词汇。例如:   有字典列表:   00=Chinese   01=People   02=...
  • 深入理解数据压缩与重复数据删除

    千次阅读 2016-10-28 17:23:48
     作 者 :中科院博士,长期从事存储领域研发工作,分式存储资深理论研究与实践者,GlusterFS 技术专家,当前专注于Server SAN。 ...[导读] 数据压缩与重复数据删除两种技术有何区别与...笔者之前对数据压缩
  • Hadoop 数据压缩

    千次阅读 2018-05-29 00:22:48
    在 Hadoop 下,尤其是数据规模很大和工作负载密集的情况下,使用数据压缩显得非常重要。在这种情况下, I/O 操作和网络数据传输要花大量的时间。还有, Shuffle与 Merge 过程同样也面临着巨大的 I/O 压力。 鉴于...
  • 数据压缩的历史、原理及常用算法

    万次阅读 2017-05-24 14:58:26
    数据压缩的概念相当古老,可以追溯到发明了摩尔斯码的19世纪中期。摩尔斯码的发明,是为了使电报员能够通过电报系统,利用一系列可听到的脉冲信号传递字母信息,从而实现文字消息的传输。摩尔斯码的发明者意识到,...
  • HBase数据压缩方式的介绍与实战

    千次阅读 2019-09-20 19:20:17
    1、HBase数据压缩方式的介绍 为了提高HBase存储的利用率,很多HBase使用者会对 HBase 表中的数据进行压缩。目前 HBase 可以支持的压缩方式有 GZ(GZIP)、LZO、LZ4 以及 Snappy。它们之间的区别如下: GZ:用于冷...
  • Hadoop:数据压缩、Yarn、企业优化

    万次阅读 2020-06-03 20:41:20
    Hadoop数据压缩、Yarn架构以及工作流程、Hadoop企业优化方案
  • 开启Map输出阶段压缩 ...1)开启hive中间传输数据压缩功能 hive (default)>set hive.exec.compress.intermediate=true; 2)开启mapreduce中map输出压缩功能 hive (default)>set mapredu...
  • Hive的数据压缩介绍及使用

    千次阅读 2019-11-30 12:33:04
    在实际工作当中,hive当中处理的数据,一般都需要经过压缩,前期我们在学习hadoop的时候,已经配置过hadoop的压缩,我们这里的hive也是一样的,可以使用压缩来节省我们的MR处理的网络带宽。     ...
  • 无损数据压缩LZW算法——C++实现

    千次阅读 多人点赞 2017-11-04 01:16:22
    兹于2017年11月,应《多媒体技术基础》课程实验的要求,本人就基于无损数据压缩LZW算法做了较为深入的理解,用C++语言实现无损数据压缩LZW算法。无损数据压缩LZW算法一、实验目的1.掌握LZW算法的编码过程;2.掌握...
  • Netty websocket 推送数据压缩以 js解压

    千次阅读 2017-11-24 12:03:11
    Netty websocket 推送数据压缩以 js解压 在项目开发的时候利用基于Netty 的websocket项目,有时会发现在推送过程中经常不推送了。经过研究调查发现服务器在高并发的情况下,推送的数据流量接近带宽流量峰值,会...
  • 第七章数据压缩技术

    千次阅读 2016-04-30 10:13:26
    第七章 数据压缩技术 转自:http://www.dataguru.cn/article-3856-1.html     本章导读 前面的章节已经介绍了海量数据的存储、查询、分区、容错等技术,这些技术对于海量数据的处理是必不可少的,但要进一步...
  • 音视频压缩技术是编解码中难点,常常会涉及很多算法...未经压缩的数字视频的数据量巨大 存储困难:一张DVD只能存储几秒钟的未压缩数字视频。 传输困难 : 1兆的带宽传输一秒的数字电视视频需要大约4分钟。 压缩编码的重
  • 作为GISer,处理空间数据才是主要任务,矢量数据压缩这一块要学习学习。 这里矢量数据压缩是指线的数据压缩,意思是假如某根线有n个点,现在如果删除一些点,这条线仍然性质良好,那么就实现了压缩,那么下面的算法...
  • 无损数据压缩算法发展史

    千次阅读 2015-05-11 22:26:41
    内容丰富,闲暇时可以细品 ...有损压缩主要用来存储图像和音频文件,同时通过移除数据可以达到一个比较高的压缩率,不过本文不讨论有损压缩。无损压缩,也使文件变小,但对应的解压缩功能可以精确的恢复原文件,
  • [译]无损数据压缩算法的历史

    千次阅读 2017-08-15 17:58:24
    原文地址:http://blog.csdn.net/kimylrong/article/details/39405981引言有两种主要的压缩算法: ...有损压缩主要用来存储图像和音频文件,同时通过移除数据可以达到一个比较高的压缩率,不过本文不讨论有损压缩。无
  • 生成tar包后,就可以用其它的程序来进行压缩了,tar命令本身不进行数据压缩,但可以在打包或解包的同时调用其它的压缩程序,比如调用gzip、bzip2 选项: -c 创建.tar格式包文件 -x 解开.tar格式包文件 -v显示详细...
  • mysql innodb 表数据压缩

    千次阅读 2016-05-24 17:03:54
    记得一次面试中,面试官问我是否知道表的压缩,这个时候...表压缩可以在创建表时开启,压缩表能够使表中的数据压缩格式存储,压缩能够显著提高原生性能和可伸缩性。压缩意味着在硬盘和内存之间传输的数据更小且占用相
  • 数据压缩算法,文本压缩算法 几种压缩算法原理介绍- https://blog.csdn.net/clevercode/article/details/46691645 文本压缩算法的对比和选择- https://blog.csdn.net/horkychen/article/details/75174035 数据压缩...
  • 实时数据库中的数据压缩技术

    千次阅读 2016-05-25 18:31:28
    实时数据库中的数据压缩技术 标签: 数据库算法磁盘网络图形工作 2009-09-21 11:22 2715人阅读 评论(0) 收藏 举报  分类:   实时数据库(4)  版权声明:本文为博主原创文章,未经博主允许不得转载...
  • 点云数据压缩 G-PCC综述

    千次阅读 2019-12-23 09:49:58
    用激光雷达或者摄像机矩阵将一个三维物体直接数字化,变成一个点的数据。每一个点会包括它的位置x、y、z和其他信息包括r、g、b和色彩信息y、u、v等,这样的描述方式我们称之为点云。 点云数据结构包括: 位置...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 838,903
精华内容 335,561
关键字:

数据压缩