字符串压缩算法

目录

RLE(游程长度编码)

算法原理

步骤说明

示例说明

代码示例

python语言:

C语言:

优缺点

Huffman编码

基本原理

构造Huffman树

编码与解码过程

代码示例

python语言:

C语言:

优缺点

LZW压缩

字典构建与压缩过程

步骤说明

代码示例

python语言:

C语言:

优缺点


字符串压缩算法用于减少字符串的存储空间,尤其是在需要传输或保存大量文本数据时。以下是三种常见的字符串压缩算法:RLE、Huffman编码和LZW压缩。

RLE(游程长度编码)

算法原理

游程长度编码(Run-Length Encoding,RLE)是一种简单的压缩算法,主要针对字符串中连续重复的字符。该算法通过记录每个字符的重复次数来实现压缩。

步骤说明

  1. 遍历字符串,记录每个字符及其连续出现的次数。
  2. 生成一个新的字符串,其中每个字符后面跟着其出现的次数。

示例说明

考虑字符串 "AAAABBBCCDAA"

  • 第1步:找到字符 A 连续出现了4次,记为 "4A"
  • 第2步:找到字符 B 连续出现了3次,记为 "3B"
  • 第3步:字符 C 连续出现2次,记为 "2C"
  • 第4步:字符 D 出现1次,记为 "1D"
  • 第5步:字符 A 连续出现2次,记为 "2A"

最终压缩结果为 "4A3B2C1D2A"

代码示例

python语言:

def rle_encode(data):encoding = ''i = 0while i < len(data):count = 1while i + 1 < len(data) and data[i] == data[i + 1]:i += 1count += 1encoding += str(count) + data[i]i += 1return encoding# 示例使用
input_string = "AAAABBBCCDAA"
encoded_string = rle_encode(input_string)
print(encoded_string)  # 输出: "4A3B2C1D2A"

C语言:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>char *rleEncode(const char *data) {int dataLength = strlen(data);char *encoding = (char *)malloc(2 * dataLength * sizeof(char));int encodingIndex = 0;int i = 0;while (i < dataLength) {int count = 1;while (i + 1 < dataLength && data[i] == data[i + 1]) {i++;count++;}int countDigits = 0;int tempCount = count;while (tempCount > 0) {tempCount /= 10;countDigits++;}int digitIndex = countDigits;tempCount = count;while (tempCount > 0) {encoding[encodingIndex + digitIndex--] = '0' + tempCount % 10;tempCount /= 10;}encoding[encodingIndex + countDigits] = data[i];encodingIndex += countDigits + 1;i++;}encoding[encodingIndex] = '\0';return encoding;
}int main() {const char *inputString = "AAAABBBCCDAA";char *encodedString = rleEncode(inputString);printf("%s\n", encodedString);free(encodedString);return 0;
}

优缺点

  • 优点:RLE算法实现简单,适用于字符重复较多的场景。
  • 缺点:对于字符重复较少的字符串,RLE可能会增加字符串的长度而非压缩。

Huffman编码

基本原理

Huffman编码是一种基于字符出现频率的无损压缩算法。它通过构建一棵Huffman树,为出现频率较高的字符分配较短的二进制编码,频率较低的字符分配较长的二进制编码,从而达到压缩的目的。

构造Huffman树

  1. 计算每个字符的出现频率。
  2. 创建一个优先队列,将每个字符及其频率作为一个叶节点插入队列。
  3. 取出队列中频率最低的两个节点,创建一个新的父节点,其频率为两个节点频率之和,并将该父节点插回队列。
  4. 重复步骤3,直到队列中只剩下一个节点,该节点即为Huffman树的根节点。

编码与解码过程

  • 编码:从根节点出发,沿着树向下遍历,每向左走一步,记为 0,向右走一步,记为 1,直到达到叶节点。这样,每个字符都有一个唯一的二进制编码。
  • 解码:从压缩后的二进制字符串出发,沿着Huffman树进行解码,直到恢复出原始字符串。

代码示例

python语言:

import heapq
from collections import defaultdict, Counterclass HuffmanNode:def __init__(self, char, freq):self.char = charself.freq = freqself.left = Noneself.right = Nonedef __lt__(self, other):return self.freq < other.freqdef build_huffman_tree(text):frequency = Counter(text)heap = [HuffmanNode(char, freq) for char, freq in frequency.items()]heapq.heapify(heap)while len(heap) > 1:node1 = heapq.heappop(heap)node2 = heapq.heappop(heap)merged = HuffmanNode(None, node1.freq + node2.freq)merged.left = node1merged.right = node2heapq.heappush(heap, merged)return heap[0]def build_codes(node, prefix='', codebook={}):if node is not None:if node.char is not None:codebook[node.char] = prefixbuild_codes(node.left, prefix + '0', codebook)build_codes(node.right, prefix + '1', codebook)return codebookdef huffman_encode(text):root = build_huffman_tree(text)codebook = build_codes(root)return ''.join(codebook[char] for char in text), codebook# 示例使用
text = "AAAABBBCCDAA"
encoded_text, huffman_codebook = huffman_encode(text)
print(f"Encoded: {encoded_text}")  # 输出压缩后的二进制字符串
print(f"Codebook: {huffman_codebook}")  # 输出字符到二进制的映射

C语言:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 哈夫曼树节点结构体
typedef struct HuffmanNode {char character;int frequency;struct HuffmanNode *left;struct HuffmanNode *right;
} HuffmanNode;// 创建新的哈夫曼节点
HuffmanNode *createHuffmanNode(char character, int frequency) {HuffmanNode *newNode = (HuffmanNode *)malloc(sizeof(HuffmanNode));newNode->character = character;newNode->frequency = frequency;newNode->left = NULL;newNode->right = NULL;return newNode;
}// 交换两个哈夫曼节点
void swapHuffmanNodes(HuffmanNode **a, HuffmanNode **b) {HuffmanNode *temp = *a;*a = *b;*b = temp;
}// 下调整个最小堆,保持堆的性质
void minHeapify(HuffmanNode **heap, int size, int index) {int smallest = index;int left = 2 * index + 1;int right = 2 * index + 2;if (left < size && heap[left]->frequency < heap[smallest]->frequency)smallest = left;if (right < size && heap[right]->frequency < heap[smallest]->frequency)smallest = right;if (smallest!= index) {swapHuffmanNodes(&heap[index], &heap[smallest]);minHeapify(heap, size, smallest);}
}// 构建最小堆
void buildMinHeap(HuffmanNode **heap, int size) {for (int i = (size / 2) - 1; i >= 0; i--)minHeapify(heap, size, i);
}// 提取最小频率的节点
HuffmanNode *extractMin(HuffmanNode **heap, int *size) {if (*size <= 0)return NULL;HuffmanNode *minNode = heap[0];heap[0] = heap[(*size) - 1];(*size)--;minHeapify(heap, *size, 0);return minNode;
}// 插入节点到最小堆
void insertNode(HuffmanNode **heap, int *size, HuffmanNode *node) {(*size)++;int i = (*size) - 1;while (i && node->frequency < heap[(i - 1) / 2]->frequency) {heap[i] = heap[(i - 1) / 2];i = (i - 1) / 2;}heap[i] = node;
}// 构建哈夫曼树
HuffmanNode *buildHuffmanTree(char *text) {int frequency[256] = {0};int length = strlen(text);for (int i = 0; i < length; i++)frequency[(int)text[i]]++;HuffmanNode **heap = (HuffmanNode **)malloc(length * sizeof(HuffmanNode *));int size = 0;for (int i = 0; i < 256; i++) {if (frequency[i] > 0) {heap[size++] = createHuffmanNode((char)i, frequency[i]);}}buildMinHeap(heap, size);while (size > 1) {HuffmanNode *left = extractMin(heap, &size);HuffmanNode *right = extractMin(heap, &size);HuffmanNode *merged = createHuffmanNode('\0', left->frequency + right->frequency);merged->left = left;merged->right = right;insertNode(heap, &size, merged);}HuffmanNode *root = extractMin(heap, &size);free(heap);return root;
}// 深度优先遍历构建编码表
void buildCodes(HuffmanNode *root, char *prefix, int prefixLength, char **codebook) {if (root->left) {prefix[prefixLength] = '0';buildCodes(root->left, prefix, prefixLength + 1, codebook);}if (root->right) {prefix[prefixLength] = '1';buildCodes(root->right, prefix, prefixLength + 1, codebook);}if (root->character!= '\0') {prefix[prefixLength] = '\0';codebook[(int)root->character] = strdup(prefix);}
}// 哈夫曼编码函数
void huffmanEncode(char *text) {HuffmanNode *root = buildHuffmanTree(text);char prefix[256] = {0};char **codebook = (char **)malloc(256 * sizeof(char *));buildCodes(root, prefix, 0, codebook);printf("Encoded: ");int length = strlen(text);for (int i = 0; i < length; i++) {printf("%s", codebook[(int)text[i]]);}printf("\n");printf("Codebook:\n");for (int i = 0; i < 256; i++) {if (codebook[i]!= NULL) {printf("%c: %s\n", (char)i, codebook[i]);free(codebook[i]);}}free(codebook);
}// 测试示例
int main() {char text[] = "AAAABBBCCDAA";huffmanEncode(text);return 0;
}

优缺点

  • 优点:Huffman编码能够显著减少高频字符的编码长度,实现高效压缩。
  • 缺点:构造Huffman树的过程相对复杂,对于频率较为均匀的字符,压缩效果有限。

LZW压缩

字典构建与压缩过程

LZW(Lempel-Ziv-Welch)是一种基于字典的无损压缩算法。它通过动态构建字典,将字符串中的重复模式编码为较短的二进制串,从而实现压缩。

步骤说明

  1. 初始化字典,包含所有可能的单字符模式。
  2. 从输入字符串中读取字符,寻找最长的已存在于字典中的模式。
  3. 将该模式的索引输出,并将新模式(即该模式加下一个字符)加入字典。
  4. 重复步骤2和3,直到字符串处理完毕。

示例说明

假设有字符串 "ABABABABABAB"

  • 初始字典包含所有单字符模式,如 'A': 1, 'B': 2
  • 读取字符 'A',最长匹配为 'A',输出其索引 1,并将 'AB' 加入字典。
  • 读取字符 'B',最长匹配为 'B',输出其索引 2,并将 'BA' 加入字典。
  • 继续匹配,最终压缩输出一系列索引代表原始字符串。

代码示例

python语言:

def lzw_compress(uncompressed):dict_size = 256dictionary = {chr(i): i for i in range(dict_size)}w = ""compressed_data = []for c in uncompressed:wc = w + cif wc in dictionary:w = wcelse:compressed_data.append(dictionary[w])dictionary[wc] = dict_sizedict_size += 1w = cif w:compressed_data.append(dictionary[w])return compressed_data# 示例使用
input_string = "ABABABABABAB"
compressed = lzw_compress(input_string)
print(compressed)  # 输出: [65, 66, 256, 258, 260, 262]

C语言:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define DICT_SIZE 256typedef struct {char *key;int value;
} DictionaryEntry;DictionaryEntry *createDictionaryEntry(char *key, int value) {DictionaryEntry *entry = (DictionaryEntry *)malloc(sizeof(DictionaryEntry));entry->key = strdup(key);entry->value = value;return entry;
}void freeDictionaryEntry(DictionaryEntry *entry) {free(entry->key);free(entry);
}int lzwCompress(char *uncompressed) {DictionaryEntry *dictionary[DICT_SIZE];for (int i = 0; i < DICT_SIZE; i++) {dictionary[i] = createDictionaryEntry((char *)&i, i);}char w[1000] = "";int compressedData[1000];int compressedDataIndex = 0;for (int i = 0; uncompressed[i]!= '\0'; i++) {char wc[1000];strcpy(wc, w);strncat(wc, &uncompressed[i], 1);int found = 0;for (int j = 0; j < DICT_SIZE; j++) {if (strcmp(dictionary[j]->key, wc) == 0) {found = 1;strcpy(w, wc);break;}}if (!found) {for (int j = 0; j < DICT_SIZE; j++) {if (strcmp(dictionary[j]->key, w) == 0) {compressedData[compressedDataIndex++] = dictionary[j]->value;break;}}dictionary[DICT_SIZE] = createDictionaryEntry(wc, DICT_SIZE);DICT_SIZE++;strcpy(w, &uncompressed[i]);}}if (strlen(w) > 0) {for (int j = 0; j < DICT_SIZE; j++) {if (strcmp(dictionary[j]->key, w) == 0) {compressedData[compressedDataIndex++] = dictionary[j]->value;break;}}}for (int i = 0; i < DICT_SIZE; i++) {freeDictionaryEntry(dictionary[i]);}for (int i = 0; i < compressedDataIndex; i++) {printf("%d ", compressedData[i]);}printf("\n");return compressedDataIndex;
}int main() {char inputString[] = "ABABABABABAB";lzwCompress(inputString);return 0;
}

优缺点

  • 优点:LZW压缩在重复模式丰富的场景下能实现很好的压缩效果,且字典动态构建,使其适应性强。
  • 缺点:初始字典大小限制了压缩的灵活性,且当模式变化频繁时,压缩效果不佳。

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

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

相关文章

QT WIN11 FluentUI APP开发

代码 import QtQuick import QtQuick.Controls import FluentUIItem {property bool autoPlay: trueproperty int loopTime: 2000property var modelproperty Component delegateproperty bool showIndicator: trueproperty int indicatorGravity : Qt.AlignBottom | Qt.Align…

Gazebo Harmonic gz-harmonic 和 ROS2 Jazzy 注意事项

激光显示 点呈现 射线呈现 rviz2 新旧版本并存的混乱 本教程旨在为在Ubuntu Jammy&#xff08;最新支持Gazebo Classic包的Ubuntu版本&#xff09;上运行Gazebo Classic&#xff08;如Gazebo 11&#xff09;的用户提供指导&#xff0c;这些用户计划将其代码迁移到新的Gazebo版…

两个实用的Python编程技巧

一、变量类型声明技巧 虽然在Python中可以不用声明变量的类型&#xff0c;但是为了加快程序的运算速度&#xff0c;减少不必要的bug&#xff0c;我们可以在定义变量之初就把它的类型确定&#xff0c;这样可以更好地传输变量值。如下面的例子。 我们定义了两个变量&#xff0c…

基于STM32开发的智能家居语音控制系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化语音识别处理设备控制与状态显示Wi-Fi通信与远程控制应用场景 家庭环境的语音控制办公室的智能化管理常见问题及解决方案 常见问题解决方案结论 1. 引言 随着人工智能技术的发展&…

Centos 添加双网卡 (生产环境配置记录)

1、在虚拟机中添加网卡2 [rootntpserver network-scripts]# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo …

医疗器械法规笔记

目录 前言医疗器械法规体系医疗器械监管注册与备案前言 之前的文章中介绍了与软件开发过程中相关的法规(网络安全),同时介绍了如何查找相关行业标准,这些都是平时工作中遇到的细节问题,没有系统性的呈现出医疗器械法规相关的框架,一直想对法规与标准有一个全面的认识和总…

44-java自动拆箱和自动装箱

java自动拆箱和自动装箱 自动装箱是Java中的一个概念&#xff0c;它允许将一个基本类型直接赋值给对应的包装类。例如&#xff0c;将一个int值赋给Integer对象。 自动拆箱是将包装类对象直接赋值给基本类型变量。例如&#xff0c;将一个Integer对象赋给一个int值。 以下是Ja…

系统分析师---UML图的七种图形

UML&#xff08;统一建模语言&#xff09;是一种用于软件设计和文档编写的标准图形化语言&#xff0c;它提供了多种图形来帮助开发人员和架构师在不同阶段理解和传达系统的结构和行为。以下是UML的七种主要图形及其含义&#xff0c;以及在需求分析、概念设计和详细设计中的使用…

Redis中的 大/热 key问题 ,如何解决(面试版)

big key 什么是 big key? big key&#xff1a;就是指一个内存空间占用比较大的键(Key) 造成的问题&#xff1a; 内存分布不均。在集群模式下&#xff0c;不同 slot分配到不同实例中&#xff0c;如果大 key 都映射到一个实例&#xff0c;则分布不均&#xff0c;查询效率也…

常见错误导引 不锈钢螺钉的正确选购和使用分析

紧固件或螺钉是用于固定物体的机械工具。它们用于各种场景&#xff0c;从建造房屋、用具、玩具等。紧固件由多种材料制成&#xff0c;所有这些材料都有特定用途紧固件和用途。一些用于制造螺丝的材料包括不锈钢、铁、铜、铝和塑料。它通常会进行某种表面处理以提高其防锈性和/或…

(亲测解决)Couldn‘t open file /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9

1、报错 Extra Packages for Enterprise Linux 9 - x86_64 0.0 B/s | 0 B 00:00 Curl error (37): Couldnt read a file:// file for file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 [Couldnt open…

K8S持久化存储数据volumeMountsvolumes

环境&#xff1a; Ubuntu-1:192.168.114.110作为主 Ubuntu-2:192.168.114.120作为从1&#xff0c;node节点1 Ubuntu-3:192.168.114.130作为从2&#xff0c;node节点2 持久化volumeMounts pod里面&#xff1a;emptyDir和hostPath。存储在node&#xff0c;NFS...&#xff0c;Clo…

OD C卷 - 寻找最优的路测线路

寻找最优的路测线路&#xff08;200&#xff09; 给定一个m行、n列的数组&#xff08;路线网络&#xff09;&#xff0c;每个值代表当前位置的信号质量&#xff0c;越大信号越好&#xff1b;从 [0, 0] 到 [m-1, n-1]位置的路线中&#xff0c;最小值代表当前路线的评分&#xf…

高斯混合模型原理及Python实践

高斯混合模型&#xff08;Gaussian Mixture Model&#xff0c;简称GMM&#xff09;是一种统计学中的概率模型&#xff0c;用于表示由多个高斯分布&#xff08;正态分布&#xff09;混合组成的数据集合。其核心原理基于假设数据集中的每个数据点都是由多个潜在的高斯分布之一生成…

springboot项目使用本地依赖项,打包后出现NoClassDefFoundError的一种解决方法

可以把本地依赖项上传到本地仓库后再引用 建立 Maven 本地仓库并将依赖上传到本地仓库 要建立 Maven 本地仓库并将依赖上传到本地仓库&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 配置 Maven 本地仓库路径 Maven 默认会在用户的主目录下的 .m2/repository 目录创…

基于Modbus的MFC智能控制

1. 系统概述 利用LabVIEW通过Modbus 485协议实现对七星&#xff08;Sevenstar&#xff09;品牌质量流量控制器&#xff08;MFC&#xff09;的智能化控制。该系统将自动控制多个MFC的流速&#xff0c;实时监控其状态&#xff0c;并根据需要进行调整。 2. 硬件配置 MFCs: 七星品…

JavaScript学习文档(7):Web API、获取DOM对象、操作元素内容、元素属性、定时器-间歇函数

目录 一、Web API 1、作用和分类 2、DOM是什么 3、DOM树 4、DOM对象 &#xff08;1&#xff09;DOM对象如何创建的? &#xff08;2&#xff09;DOM对象怎么创建的? 二、获取DOM对象 1、根据CSS选择器来获取DOM元素 &#xff08;1&#xff09;选择匹配的第一个元素 …

Spring(2)

目录 一、使用注解开发 1.1 主要注解 1.2 衍生注解 1.3 xml与注解 二、使用Java的方式配置Spring 三、代理模式 3.1 静态代理 3.1.1 角色分析 3.1.2 代码步骤 3.1.3 优点 3.1.4 缺点 3.2 动态代理 3.2.1 代码步骤 四、AOP 4.1 使用Spring的API接口 4.2 使用自定义…

8月15日

上午开会 rag继续 异构大模型 狂野飙车9之前的账号终于找回来了 下午 关于minicpm的代码 minicpm-v 大模型预训练论文&方法总结 - 知乎 (zhihu.com) 这里有讲解的代码 发现还是先推荐把llava的掌握好了之后再看minicpm 多模态大模型LLaVA模型讲解——transformers源…

YoloV8改进策略:卷积篇|ACConv2d模块在YoloV9中的创新应用与显著性能提升|简单易用_即插即用

摘要 在本文中&#xff0c;我们创新性地将ACConv2d模块引入到YoloV9目标检测模型中&#xff0c;通过对YoloV9中原有的Conv卷积层进行替换&#xff0c;实现了模型性能的大幅提升。ACConv2d模块基于不对称卷积块&#xff08;ACB&#xff09;的设计思想&#xff0c;利用1D非对称卷…