C#,数值计算——哈夫曼编码与数据压缩技术(Huffman Coding and Compression of Data)源代码

news/2024/10/18 7:58:33/

1 霍夫曼编码导论

  • 霍夫曼编码是一种基于数据集中符号频率的无损数据压缩形式。
  • 它是一种前缀编码方案,这意味着编码的数据不包含任何冗余比特。
  • 霍夫曼编码广泛应用于各种应用,如图像和视频压缩、数据传输和数据存储。

2 霍夫曼编码的优点

以下是霍夫曼编码的5个优点:

  • 霍夫曼编码是一种有效的数据压缩方法,因为它将较短的代码分配给数据集中出现频率较高的符号。这导致了更高的压缩比。
  • 霍夫曼编码是一种前缀编码方案,这意味着它不需要任何特殊的标记来分隔不同的代码。这使得它易于实现和解码。
  • 霍夫曼编码是一种广泛使用的数据压缩方法,并得到许多软件库和工具的支持,使其易于集成到现有系统中。
  • 霍夫曼编码是一种无损压缩方法,这意味着可以从压缩数据中准确地重建原始数据。
  • 霍夫曼编码是一种简单有效的算法,可以很容易地在软件和硬件上实现。

3 霍夫曼编码的缺点

以下是霍夫曼编码的5个缺点:

  • 霍夫曼编码要求预先知道每个符号的频率,这使得它不太适合于符号分布未知或动态变化的情况。
  • 霍夫曼树可能很复杂,很难理解,这使得调试和维护代码变得更加困难。
  • 编码过程可能耗时且计算成本高昂,尤其是对于大型数据集。
  • 霍夫曼编码并不总是最有效的压缩方法,可能还有其他方法可以为给定的数据集提供更好的压缩比。
  • 在只有很少的唯一符号或符号已经被高度压缩的情况下,霍夫曼编码对数据的效果可能较差。

using System;

namespace Legalsoft.Truffer
{
    /// <summary>
    /// Huffman Coding and Compression of Data
    /// </summary>
    public class Huffcode
    {
        private int nch { get; set; }
        private int nodemax { get; set; }
        private int mq { get; set; }
        private int ilong { get; set; }
        private int nlong { get; set; }
        private int[] ncod { get; set; }
        private int[] left { get; set; }
        private int[] right { get; set; }
        private uint[] icod { get; set; }
        private uint[] setbit { get; set; } = new uint[32];

        /// <summary>
        /// Given the frequency of occurrence table nfreq[0..nnch - 1] for nnch charac-
        /// ters, constructs the Huffman code.Also sets ilong and nlong as the
        /// character number that produced the longest code symbol, and the length of
        /// that symbol.
        /// </summary>
        /// <param name="nnch"></param>
        /// <param name="nfreq"></param>
        /// <exception cref="Exception"></exception>
        public Huffcode(int nnch, int[] nfreq)
        {
            this.nch = nnch;
            this.mq = 2 * nch - 1;
            this.icod = new uint[mq];
            this.ncod = new int[mq];
            this.left = new int[mq];
            this.right = new int[mq];

            int[] index = new int[mq];
            int[] nprob = new int[mq];
            int[] up = new int[mq];
            for (int j = 0; j < 32; j++)
            {
                setbit[j] = (uint)(1 << j);
            }
            int nused = 0;
            for (int j = 0; j < nch; j++)
            {
                nprob[j] = nfreq[j];
                icod[j] = 0;
                ncod[j] = 0;
                if (nfreq[j] != 0)
                {
                    index[nused++] = j;
                }
            }
            for (int j = nused - 1; j >= 0; j--)
            {
                heep( index,  nprob, nused, j);
            }
            int k = nch;
            while (nused > 1)
            {
                int node = index[0];
                index[0] = index[(nused--) - 1];
                heep( index,  nprob, nused, 0);
                nprob[k] = nprob[index[0]] + nprob[node];
                left[k] = node;
                right[k++] = index[0];
                up[index[0]] = -(int)k;
                index[0] = k - 1;
                up[node] = k;
                heep( index,  nprob, nused, 0);
            }
            up[(nodemax = k) - 1] = 0;
            for (int j = 0; j < nch; j++)
            {
                if (nprob[j] != 0)
                {
                    int n = 0;
                    int ibit = 0;
                    for (int node = up[j]; node > 0; node = up[node - 1], ibit++)
                    {
                        if (node < 0)
                        {
                            n |= (int)setbit[ibit];
                            node = -node;
                        }
                    }
                    icod[j] = (uint)n;
                    ncod[j] = ibit;
                }
            }
            nlong = 0;
            for (int j = 0; j < nch; j++)
            {
                if (ncod[j] > nlong)
                {
                    nlong = ncod[j];
                    ilong = j;
                }
            }
            if (nlong > 16)// numeric_limits<uint>.digits)
            {
                throw new Exception("Code too long in Huffcode.  See text.");
            }
        }

        /// <summary>
        /// Huffman encode the single character ich(in the range 0..nch-1), write the
        /// result to the byte array code starting at bit nb(whose smallest valid
        /// value is zero), and increment nb to the first unused bit.This routine is
        /// called repeatedly to encode consecutive characters in a message. The user
        /// is responsible for monitoring that the value of nb does not overrun the
        /// length of code.
        /// </summary>
        /// <param name="ich"></param>
        /// <param name="code"></param>
        /// <param name="nb"></param>
        /// <exception cref="Exception"></exception>
        public void codeone(int ich, ref string code, ref int nb)
        {
            char[] cc = code.ToCharArray();

            if (ich >= nch)
            {
                throw new Exception("bad ich (out of range) in Huffcode");
            }
            if (ncod[ich] == 0)
            {
                throw new Exception("bad ich (zero prob) in Huffcode");
            }
            for (int n = ncod[ich] - 1; n >= 0; n--, ++nb)
            {
                int nc = nb >> 3;
                int m = nb & 7;
                if (m == 0)
                {
                    code = code.Substring(0, nc);
                }
                if ((icod[ich] & setbit[n]) != 0)
                {
                    //code[nc] |= setbit[m];
                    cc[nc] |= (char)setbit[m];
                }
            }

            code = new string(cc);
        }

        /// <summary>
        /// Starting at bit number nb in the byte array code, decode a single character
        /// (returned as ich in the range 0..nch-1) and increment nb appropriately.
        /// Repeated calls, starting with nb D 0, will return successive characters in
        /// a compressed message. The user is responsible for detecting EOM from the
        /// message content.
        /// </summary>
        /// <param name="code"></param>
        /// <param name="nb"></param>
        /// <returns></returns>
        public int decodeone(ref string code, ref int nb)
        {
            int node = nodemax - 1;
            for (; ; )
            {
                int nc = nb >> 3;
                node = ((code[nc] & setbit[7 & nb++]) != 0 ? right[node] : left[node]);
                if (node < nch)
                {
                    return node;
                }
            }
        }

        /// <summary>
        /// Used by the constructor to maintain a heap structure in the array
        /// index[0..m - 1].
        /// </summary>
        /// <param name="index"></param>
        /// <param name="nprob"></param>
        /// <param name="n"></param>
        /// <param name="m"></param>
        public void heep(int[] index, int[] nprob, int n, int m)
        {
            int i = m;
            int k = index[i];
            int j;
            while (i < (n >> 1))
            {
                if ((j = 2 * i + 1) < n - 1 && nprob[index[j]] > nprob[index[j + 1]])
                {
                    j++;
                }
                if (nprob[k] <= nprob[index[j]])
                {
                    break;
                }
                index[i] = index[j];
                i = j;
            }
            index[i] = k;
        }
    }
}
 


http://www.ppmy.cn/news/703139.html

相关文章

Linux 查找指定时间区间日志

Linux 查找指定时间区间日志 sed -n /2012-08-2510:57:46/,/2014-08-2511:03:49/p catalina-daemon.out

ASEMI整流桥GBU2510参数,GBU2510规格,GBU2510特性

编辑-Z ASEMI整流桥GBU2510参数&#xff1a; 型号&#xff1a;GBU2510 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;1000V 最大RMS电桥输入电压&#xff08;VRMS&#xff09;&#xff1a;700V 最大直流阻断电压&#xff08;VDC&#xff09;&#xff1a;…

JOJ 2510 Product

题目不难&#xff0c;深度优先搜索。代码是参考别人写的。 题目链接&#xff1a;http://acm.jlu.edu.cn/joj/showproblem.php?pid2510 #include <iostream> using namespace std; int a[50], vist[55], n; int sum 0; int MAXN 0; void dfs(int cur, int maxn) {…

A002-185-2510-李海鹏

计算机科学与工程学院实验报告 姓名 :李海鹏 学号 :1814080902510 日期 :2020年12月19日一、Excel查找档与项目结合 1.需求基线&#xff08;Requirement Baseline&#xff09; 官方理解&#xff1a; A requirements baseline is a snapshot in time that represents…

QCustomPlot 添加曲线、添加图例等常用功能

1、添加一条曲线 ui->customPlot->addGraph();QVector<double> x(2510), y0(2510);for (int i0; i<2500; i){x[i] i;y0[i] qExp(-i/1500.0)*qCos(i/100.0);}ui->customPlot->graph(0)->setData(x, y0);2、坐标轴自适应曲线 ui->customPlot->gr…

HDU 2510 符号三角形

链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2510 符号三角形 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1116 Accepted Submission(s): 578 Problem Description 符号三角形的 第1行有n个由…

A001-185-2510-李海鹏

我对需求分析与建模的认识与应有内容建议 作者&#xff1a;李海鹏 班级&#xff1a;18软件5班 学号&#xff1a;1814080902510 目录我对需求分析与建模的认识与应有内容建议 一、 摘要/关键字&#xff08;Abstract and Key words&#xff09; 二、 引言&#xff08;Introduc…

中山大学 计算机院博士录取名学,中山大学2021年博士研究生招生拟录取名单公示,2510人!...

原标题&#xff1a;中山大学2021年博士研究生招生拟录取名单公示&#xff0c;2510人&#xff01; 根据教育部与广东省教育考试院的统一工作部署&#xff0c;经校内各招生单位研究生招生工作领导小组审核&#xff0c;研究生院审定&#xff0c;现将我校2021年博士研究生拟录取名单…