首页 > 编程语言 >用c#实现哈夫曼压缩算法

用c#实现哈夫曼压缩算法

时间:2024-05-31 17:56:19浏览次数:27  
标签:哈夫曼 c# codeTable public item var new 压缩算法 节点

    /// <summary>
    /// hash压缩算法
    /// </summary>
    /// <param name="file"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<IActionResult> HashCompressAsync(IFormFile file, CancellationToken cancellationToken)
    {
        try
        {
            // 读取传入文件的所有的数据
            byte[] fileData = new byte[file.Length];

            using (var stream = file.OpenReadStream())
            {
                await stream.ReadAsync(fileData, cancellationToken);
            }

            // 统计字符大小(字符频率)
            Dictionary<byte, int> dictionary = new Dictionary<byte, int>();

            foreach (var item in fileData)
            {
                // 判断字典中字符是否存在
                if (dictionary.ContainsKey(item))
                {
                    // 如果有就叠加
                    dictionary[item]++;
                }
                else
                {
                    dictionary[item] = 1;
                }
            }

            // 构建二叉树
            var towTree = BuildHuffmanTree(dictionary,cancellationToken);

            // 生成编码
            var codeTable = new Dictionary<byte,string>();
            GenerateCodeTable(towTree, "", codeTable);

            // 进行压缩
            var compressedData = CompressFileAsync(fileData,codeTable);

            Console.WriteLine(compressedData);

            /* if (compressedData != null)
             {
                 this.ResultEntity.Data = compressedData;
             }
             else
             {
                 this.ResultEntity.Result = false;
             }

             return this.ResultEntity;*/

            var fileStream = new MemoryStream(compressedData);
            return new FileStreamResult(fileStream, "application/octet-stream")
            {
                FileDownloadName = "compressed_data.bin"
            };
            fileStream.Close();
        }
        catch (Exception  ex)
        {
            throw ex;
        }
    }

    /// <summary>
    /// 构建二叉树
    /// </summary>
    /// <param name="dictionary"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    private  HuffmanNode BuildHuffmanTree(Dictionary<byte, int> dictionary, CancellationToken cancellationToken)
    {
        // 按照字符频率排序
        var hash = new PriorityQueue<HuffmanNode, int>(Comparer<int>.Create((x, y) => y - x));

        // 遍历字典,将每个字节及其频率作为节点加入优先队列
        foreach (var item in dictionary)
        {
            hash.Enqueue(new HuffmanNode { Value = item.Key, Frequency = item.Value }, item.Value);
        }

        // 构建树
        do
        {
            // 从优先队列中取出频率最小的两个节点作为左右子节点
            var Left = hash.Dequeue();
            var Right = hash.Dequeue();

            // 创建一个新的节点,其频率为左右子节点的频率之和,并将左右子节点分别设置为新节点的左右子节点
            var data = new HuffmanNode
            {
                Frequency = Left.Frequency + Right.Frequency,
                Left = Left,
                Right = Right
            };

            // 将新节点加入优先队列
            hash.Enqueue(data,data.Frequency);

            // 当优先队列中只剩下一个节点时,结束循环
        } while (hash.Count>1);

        return hash.Dequeue();
    }

    /// <summary>
    /// 生成编码表
    /// </summary>
    /// <param name="node"></param>
    /// <param name="code"></param>
    /// <param name="codeTable"></param>
    public void GenerateCodeTable(HuffmanNode node, string code, Dictionary<byte, string> codeTable)
    {
        // 如果节点的值存在
        if (node.Value.HasValue)
        {
            // 将节点的值作为键,编码作为值存储到编码表中
            codeTable[node.Value.Value] = code;
        }
        else
        {
            // 递归处理左右子树,编码加上"0","1"
            GenerateCodeTable(node.Left, code + "0", codeTable);
            GenerateCodeTable(node.Right, code + "1", codeTable);
        }
    }

    /// <summary>
    /// 用编码表对文件数据进行压缩
    /// </summary>
    /// <param name="data"></param>
    /// <param name="codeTable"></param>
    /// <returns></returns>
    public static byte[] CompressFileAsync(byte[] data, Dictionary<byte, string> codeTable)
    {
        var compressedBytes = new List<byte>();

        foreach (var item in data)
        {
            // 获取当前字节的编码
            var code = codeTable[item];

            // 将编码添加到 compressedBytes 中
            foreach (var c in code)
            {
                if (c == '0')
                {
                    compressedBytes.Add(0);
                }
                else if (c == '1')
                {
                    compressedBytes.Add(1);
                }
            }
        }

        // 返回压缩后的字节数组
        return compressedBytes.ToArray();
    }

}

/// <summary>
/// 哈夫曼树节点类
/// </summary>
public class HuffmanNode
{
    // 节点值
    public byte? Value { get; set; }

    // 节点频率
    public int Frequency { get; set; }

    // 左子节点
    public HuffmanNode Left { get; set; }

    // 右子节点
    public HuffmanNode Right { get; set; }
}

  

标签:哈夫曼,c#,codeTable,public,item,var,new,压缩算法,节点
From: https://www.cnblogs.com/stevenduxiang/p/18225023

相关文章

  • CH57x/CH58x/CH59x获取从机广播信息
    有时需要通过主机设备(MCU非手机)获取从设备的广播信息例如广播包,MAC地址,扫描应答包等以下的程序片段及功能实现是在WCH的CH59X的observer例程上实现的;1、获取广播包所有的函数在库函数中都可以找到,具体实现函数如下:caseGAP_DEVICE_INFO_EVENT:{Observ......
  • 发现了一个膨胀样式的css库
    众所周知,对于前端来说css是最难的了,如果你遇到了一个脑洞大奇思妙想的产品,那就更难了。很不巧,了不起就经受过这样的痛苦,产品经理看了HarmonyOS4的发布会,脑子一热就让设计师出了一套膨胀蓬松的UI了不起经过调研,查找了上百个样式组件库,终于找到了一款合适的样式库——clay.cssc......
  • nuxt3中$fetch方法delete请求不传body500报错
    后台delete请求参数写在query中,当只传query时报错500内部服务错误,后台断点进不去。但是当传入body请求体时接口正常进入。不知道什么原因多次尝试后发现。后台加入跨域或配置devProxy可解决问题.由于我是配置routeRules处理的跨域。如下nitro:{//devProxy:{//'/a......
  • GitLab clone 地址不对的解决办法
    1丶问题描述2丶解决方案解决方案:找到挂载到宿主机配置文件:gitlab.rbvigitlab.rb改成自己的ip 重启容器dockerrestartgitlab如果发现容器一直重启,可采用粗暴的方法,直接干掉当前容器,重新运行一个#停掉容器dockerstop容器id #删除容器 dockerrm容器id  重新运行......
  • k8s--service详解
    1:service详解1、每次访问pod的时候,ip地址都不是固定的2、service有一个虚拟ip和端口,可以使用这个来进行访问3、kube-proxy,apiserver将service的信息存入到etcd中,kube-proxy将其转换为一个访问规则,这个就是本质4、表象,就是标签,本质就是规则,通过标签,来进行要管理哪些pod,5......
  • 第2讲:static用法总结
    几句话总结static的用法。1、静态变量(1)静态变量统一放在特定内存区域中,在程序的整个生命周期内只有一份,所以函数在使用时共用静态变量的状态。(2)类中的静态变量为类的所有对象共享,而且不能在类内初始化静态变量。原因:每个对象是独立的,如果可以通过对象的方式初始化静态变......
  • L2-043 龙龙送外卖(C++, 记忆化搜索)
    龙龙是“饱了呀”外卖软件的注册骑手,负责送帕特小区的外卖。帕特小区的构造非常特别,都是双向道路且没有构成环——你可以简单地认为小区的路构成了一棵树,根结点是外卖站,树上的结点就是要送餐的地址。每到中午12点,帕特小区就进入了点餐高峰。一开始,只有一两个地方点外卖,龙......
  • Atcoder ABC355 C~F
    C出题人太善良了,加强到\(10^5\)都没问题。考虑维护每条横线竖线两条对角线上被标记的点的个数,每次标记点后,判断是否有线上点全被标记。再考虑如何将点编号转为坐标,记编号为\(t\),推柿子:\[(x-1)\timesn+y=t\]\[nx+y=t+n\]\[x=\frac{t+n-y}{n}\]等同于找到\(y\)使得:\[n......
  • 使用 Unity Sentis 和 Compute Shader,det_10g.onnx 进行高效人脸五官定位
    前言在计算机视觉领域,人脸五官定位是一个重要的任务。本文将介绍如何使用UnitySentis和ComputeShader,结合det_10g.onnx模型,实现高效的人脸五官定位。我们将详细讲解每一步骤,并提供完整的代码示例。模型分析输入值:模型的输入是我这边选择的是1x3x640x640;输出值:步......
  • docker使用镜像jms_all部署jumpserver
    创建容器需要挂载出来的服务器对应目录mkdir-p/data/redis/datamkdir-p/opt/mysql/{data,conf,logs}docker安装redisdockerrun-d-it--nameredis-p6379:6379-v/data/redis/data:/data--restart=always......