深入理解Huffman编码:原理、代码示例与应用

news2025/7/9 12:46:30

目录

​编辑

介绍

Huffman编码的原理

信息理论背景

频率统计

Huffman树

Huffman编码的代码示例

数据结构

权重选择

Huffman编码生成

完整示例

完整代码

测试截图

Huffman编码的应用

总结


介绍

在这个数字时代,数据的有效压缩和传输变得至关重要。Huffman编码是一种经典的数据压缩算法,它通过将常见字符映射到短编码来降低数据大小,从而节省存储空间和带宽。本篇博客将深入介绍Huffman编码的原理、代码示例以及实际应用。

Huffman编码的原理
信息理论背景

首先,让我们了解为什么需要数据压缩。信息熵和编码理论是理解Huffman编码的基础。信息熵衡量了信息的不确定性,而编码理论涉及将信息编码为更紧凑的形式。

频率统计

在Huffman编码中,首先需要统计字符的出现频率。这些频率将成为构建Huffman树的基础,我们将使用它们来决定字符的编码。

Huffman树

Huffman树是一个二叉树,其中叶子节点对应于字符,而树中的路径对应于字符的编码。我们将详细解释如何构建Huffman树,选择最小权重的节点,并生成字符的编码。

Huffman编码的代码示例

现在,让我们深入研究Huffman编码的代码示例。以下是一个简化的示例代码,具体步骤包括:

数据结构

首先,我们定义Huffman树节点的数据结构以及编码数组。

typedef struct {
    int weight, parent, lchild, rchild;
} HTNode, * HuffmanTree;
typedef char** HuffmanCode;
权重选择

我们解释如何选择两个最小权重的节点来构建Huffman树。

void Select(HuffmanTree HT, int stop, int& s1, int& s2) {
    int min1, min2, i = 1;
    min1 = min2 = INT_MAX;  // 初始化最小值为最大可能值

    while (i <= stop) {
        if (HT[i].parent == 0) {
            if (HT[i].weight < min1) {
                min2 = min1;
                s2 = s1;
                min1 = HT[i].weight;
                s1 = i;
            } else if (HT[i].weight < min2) {
                min2 = HT[i].weight;
                s2 = i;
            }
        }
        i++;
    }
}

在这个示例中,我们对 min1min2 初始化为 INT_MAX,以确保第一个节点会成为 min1。然后,在循环中,我们根据节点的权重来更新 min1min2

Huffman编码生成

我们展示如何从Huffman树生成字符的编码。

void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int n) {
    char* temp;
    int i, c, f, start;
    HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
    temp = (char*)malloc(n * sizeof(char));
    temp[n - 1] = '\0';

    for (i = 1; i <= n; i++) {
        start = n - 1;
        for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) {
            if (HT[f].lchild == c) {
                temp[--start] = '0';
            } else {
                temp[--start] = '1';
            }
        }

        // 分配内存并复制编码到HuffmanCode数组
        HC[i] = (char*)malloc((n - start) * sizeof(char));
        strcpy(HC[i], temp + start);
    }
    
    free(temp);  // 释放临时内存
}

这个示例演示了如何为每个字符生成Huffman编码,将编码复制到 HuffmanCode 数组中,并在结束后释放临时内存。

完整示例

最后,我们提供完整的代码示例,包括输入样例和输出。

int main() {
    HuffmanTree HT;
    HuffmanCode HC;
    int* w, n, i;

    printf("请输入字符个数:");
    scanf("%d", &n);

    if (n > 1) {
        printf("\n请依次输入每个字符出现的次数,之间用空格隔开:");
        w = (int*)malloc((n + 1) * sizeof(int));
        
        for (i = 1; i <= n; i++) {
            scanf("%d", &w[i]);
        }

        CreateHuffmanTree(HT, w, n);
        HuffmanCoding(HT, HC, n);
        
        // 输出Huffman编码结果
        DispHuffmanCode(HT, HC, n);
        
        // 释放动态分配的内存
        for (i = 1; i <= n; i++) {
            free(HC[i]);
        }
        free(HC);
        free(HT);
        free(w);
    } else {
        printf("输入的字符个数非法!\n");
    }
}

 在 main 函数中,我们首先输入字符的个数和权重,然后生成Huffman编码,并输出编码结果。最后,我们确保释放了动态分配的内存,以避免内存泄漏。

完整代码
#define _CRT_SECURE_NO_WARNINGS
#include<string.h>
#include<ctype.h>
#include<malloc.h>
#include<limits.h>
#include<stdio.h>
#include<stdlib.h>
#include<io.h>
#include<math.h>
#include<process.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status;
typedef struct {
	int weight, parent, lchild, rchild;
}HTNode, * HuffmanTree;
typedef char** HuffmanCode;
void Select(HuffmanTree HT, int stop, int& s1, int& s2) {
	int min1, min2, i = 1;
	min1 = min2 = 32767;
	while (i <= stop) {
		if (HT[i].parent == 0) {
			if (HT[i].weight < min1) {
				min2 = min1;
				s2 = s1;
				min1 = HT[i].weight;
				s1 = i;
			}
			else  if (HT[i].weight < min2) {
				min2 = HT[i].weight;
				s2 = i;
			}
		}
		i++;
	}
}
void CreateHuffmanTree(HuffmanTree& HT, int* w, int n) {
	int i, s1, s2;
	int m = 2 * n - 1;
	HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
	for (i = 1; i <= n; i++) {
		HT[i].weight = w[i];
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for (; i <= m; i++) {
		HT[i].weight = 0;
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for (i = n + 1; i <= m; i++) {
		Select(HT, i - 1, s1, s2);
		HT[s1].parent = i;
		HT[s2].parent = i;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
}
void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int n)
{
	char* temp;
	int i, c, f, start;
	HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
	temp = (char*)malloc(n * sizeof(char));
	temp[n - 1] = '\0';
	for (i = 1; i <= n; i++) {
		start = n - 1;
		for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
			if (HT[f].lchild == c)temp[--start] = '0';
			else temp[--start] = '1';
		HC[i] = (char*)malloc((n - start) * sizeof(char));
		strcpy(HC[i], temp + start);
	}
	free(temp);
}
void DispHuffmanCode(HuffmanTree& HT, HuffmanCode& HC, int n) {
	int i;
	for (i = 1; i <= n; i++) {
		printf("第%d个字符的编码是:", i);
		printf("%s\n", HC[i]);
	}
}
int  main() {
	HuffmanTree HT;
	HuffmanCode HC;
	int* w, n, i;
	printf("请输入字符个数:");
	scanf_s("%d", &n);
	if (n > 1) {
		printf("\n请依次输入每个字符出现的次数,之间用空格隔开:");
		w = (int*)malloc((n + 1) * sizeof(int));
		for (i = 1; i <= n; i++)
			scanf_s("%d", &w[i]);
		CreateHuffmanTree(HT, w, n);
		HuffmanCoding(HT, HC, n);
		DispHuffmanCode(HT, HC, n);
	}
	else printf("输入的字符个数非法!\n");
}
测试截图

这段代码的输入样例是用于构建Huffman树的字符及其权重。以下是一个示例输入:

请输入字符个数:5

请依次输入每个字符出现的次数,之间用空格隔开:
2 3 7 1 8

这个示例输入首先要求输入字符的总数,然后要求按照字符的顺序输入每个字符出现的次数(权重)。在上述示例中,有5个字符,它们的权重分别为2、3、7、1和8。 

根据这些输入,代码将构建Huffman树并生成每个字符的Huffman编码。

Huffman编码的应用

在这一部分,我们将探讨Huffman编码的实际应用,包括:

  • 数据压缩:我们解释如何使用Huffman编码来压缩文本数据,减小存储和传输开销。
  • 数据传输:介绍Huffman编码在网络通信和文件传输中的应用,以提高传输效率。
  • 数据加密:简要讨论Huffman编码在数据加密领域的潜在用途。
总结

在博客的结尾,我们总结了Huffman编码的重要性、原理、实现和应用领域。鼓励读者深入学习Huffman编码,并了解如何在实际项目中应用它,以提高数据处理效率和节省资源。

 

🌌点击下方个人名片,交流会更方便哦~(欢迎到博主主页加入我们的 CodeCrafters联盟一起交流学习↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1103516.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Ubunt20.04在vscode中使用Fira Code字体【教程】

【Linux】Ubunt20.04在vscode中使用Fira Code字体【教程】 文章目录 【Linux】Ubunt20.04在vscode中使用Fira Code字体【教程】1. 什么是Fira Code字体2. 安装Fira Code字体3. 配置vscodeReference 1. 什么是Fira Code字体 Fira Code&#xff1a;是一种带有编程连字的等宽字体。…

多组试验时正态分布标准差估计公式

本文介绍如何通过多组试验数据来估计正态总体的标准差. 一,各组试验次数相等 设正态总体X&#xff5e;N(μ,σ),其中均值μ和标准差σ未知.今有m组样本,每组样本大小n相等,其试验数据如下:求标准差σ的估计σ. 多组试验时正态分布标准差估计公式 - 百度学术

机器人制作开源方案 | 行星探测车概述

1. 功能描述 行星探测车&#xff08;Planetary Rover&#xff09;是一种用于进行科学探索和勘测任务的无人车辆&#xff0c;它们被设计成能够适应各种复杂的地形条件和极端环境&#xff0c;以便收集数据、拍摄照片、采集样本等。行星探测车通常包含以下主要组件和功能&#xff…

Ubuntu - 查看 IP 地址

要查看 Ubuntu 操作系统中的 IP 地址&#xff0c;可以使用 ip 命令或者 ifconfig 命令。以下是使用这两个命令的示例&#xff1a; 使用 ip 命令&#xff1a; 打开终端。 输入以下命令&#xff1a; ip a 这将显示网络接口信息&#xff0c;包括 IP 地址。通常&#xff0c;IP…

彩虹工具网程序开源未加密版源码_支持插件扩展 支持暗黑模式

2023全新UI彩虹站长在线工具箱系统源码下载 全开源版本 支持暗黑模式 支持高达72种站长工具、开发工具、娱乐工具等功能。本地调用API、自带免费API接口&#xff0c; 是一个多功能性工具程序支持后台管理、上传插件、添加增减删功能。 源码下载&#xff1a;https://download…

谈谈 Redis 主从复制模式

谈谈 Redis 主从复制模式 第一次主从节点同步是全量复制 接下来&#xff0c;我在具体介绍每一个阶段都做了什么。 第一阶段&#xff1a;建立链接、协商同步 执行了 replicaof 命令后&#xff0c;从服务器就会给主服务器发送 psync 命令&#xff0c;表示要进行数据同步。 psync…

推荐一下中国可看到当前就业形势统计的网站

推荐一下中国可看到当前就业形势统计的网站 要查看中国的就业形势统计&#xff0c;你可以考虑以下几个官方和主流的资源网站&#xff1a; 国家统计局 (National Bureau of Statistics of China): 网址&#xff1a;http://www.stats.gov.cn/国家统计局是中国官方发布各种统计数…

Jetpack:011-Jetpack中标题栏

文章目录 1. 概念介绍2. 使用方法2.1 标题与导航2.2 详情菜单 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中进度条相关的内容&#xff0c;本章回中主要介绍 标题栏。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff01; 1. 概念介绍 我们在本章回…

航天科技×辰安科技 打造智慧化工园区安全保障平台

近年来&#xff0c;国内化工园区安全事故频发&#xff0c;多起化工园区重特大事故造成了严重人员财产损失的同时&#xff0c;也重创了行业的整体发展。在智能制造和工业互联网的背景下&#xff0c;建设智慧化工园区&#xff0c;使用智能化手段实现安全生产是解决当前化工园区安…

2023年Q3季度国内手机大盘销额下滑2%,TOP品牌销售数据分析

根据Canalys机构发布的最新报告&#xff0c;2023年第三季度&#xff0c;全球智能手机市场出货量仅下跌1%&#xff0c;可以认为目前全球手机市场的下滑势头有所减缓。而国内线上市场的表现也类似。 根据鲸参谋数据显示&#xff0c;今年Q3京东平台手机累计销量约1100万件&#xf…

MYSQL学习笔记1-window安装mysql5.7

1.下载安装包 官网下载&#xff1a;MySQL :: Download MySQL Installer (Archived Versions) 第一个是在线安装&#xff0c;不下载这个&#xff1b;我们下载第二个 2. 安装mysql 1&#xff09;选择自定义安装 双击下载的msi文件 “Developer Default”是开发者默认 “Server o…

RK3568平台开发系列讲解(驱动篇)Linux 中断实验

🚀返回专栏总目录 文章目录 一、中断处理函数二、request_irq 函数三、中断号四、free_irq 函数五、中断使能与禁止函数沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 Linux 内核提供了完善的中断框架,我们只需要申请中断,然后注册中断处理函数即可,使用非常方便…

Spring核心扩展点BeanDefinitionRegistryPostProcessor源码分析

我们知道&#xff0c;只要在一个Java类上加上Component、Service、Controller等注解&#xff0c;就可以被加载到Spring容器中&#xff0c;除了以上方式&#xff0c;加了Bean和Import好像也可以将对象添加到Spring容器中&#xff0c;究竟Spring是如何实现这些功能的呢&#xff1…

YAPI介绍及Docker Compose部署指南

我们团队的项目最初前后端是同一个开发人员在做&#xff0c;因此并不存在提供详细接口文档等问题。随着项目的不断迭代&#xff0c;团队规模逐渐扩大&#xff0c;我们决定将前后端分开&#xff0c;专门由专业的前端和后端人员进行开发工作。然而&#xff0c;这样的改变也带来了…

多线程下的单例设计模式(新手必看!!!)

在项目中为了避免创建大量的对象&#xff0c;频繁出现gc的问题&#xff0c;单例设计模式闪亮登场。 一、饿汉式 1.1饿汉式 顾名思义就是我们比较饿&#xff0c;每次想吃的时候&#xff0c;都提前为我们创建好。其实我记了好久也没分清楚饿汉式和懒汉式的区别。这里给出我的一…

MyCat 2全套学习笔记(完整配置【主从+集群】+理论解析 + 大厂真实业务理解)

目录 入门概述 MyCat概念 MyCat的作用 读写分离 数据分片 多数据源整合 MyCat 解决问题的思路 MyCat 和MySQL的区别 MyCat原理 MyCAT2的安装 前言 下载压缩包和jar包 安装MyCAT2 创建/data/tools 进入/data/tools目录 下载 下载完成 解压并移动到data目录下 修改权限 把所需…

【工具】利用ffmpeg将网页中的.m3u8视频文件转化为.mp4格式

目录 0.环境 1.背景 2.前提 3.详细描述 1&#xff09;在网站上找到你想下载的视频的.m3u8链接 2&#xff09;打开命令行&#xff0c;用ffmpeg命令进行转化 3&#xff09;过程&结果截图 0.环境 windows64 ffmpeg 1.背景 网页上有个.m3u8格式的视频文件&#xff0c;…

ZKP3.2 Programming ZKPs (Arkworks Zokrates)

ZKP学习笔记 ZK-Learning MOOC课程笔记 Lecture 3: Programming ZKPs (Guest Lecturers: Pratyush Mishra and Alex Ozdemir) 3.3 Using a library ( tutorial) R1CS Libraries A library in a host language (Eg: Rust, OCaml, C, Go, …)Key type: constraint system Mai…

Jmeter —— 接口之间关联调用(获取上一个接口的返回值作为下一个接口的请求参数)

正则表达式&#xff1a; 具体如何操作&#xff1a; 1. 草稿保存&#xff0c; 此请求的响应数据的id 为发布总结的请求参数draft_id 2. 草稿保存的响应数据 3.在草稿保存的请求中&#xff0c;添加后置处理器- 正则表达式提取器&#xff0c; 提取响应数据的id信息 4. 发布总结请…

【vue2高德地图api】02-npm引入插件,在页面中展示效果

系列文章目录 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、安装高德地图二、在main.js中配置需要配置2个key值以及1个密钥 三、在页面中使用3.1 新建路由3.2新建vue页面3.2-1 index.vue3.2…