Files
suanfa/public/c/ch3/image/imgcompress.c
T
2026-06-15 09:00:38 +08:00

96 lines
3.3 KiB
C

#include <stdio.h>
#include <math.h>
#define N 9 // 定义数组大小为9
// 计算一个整数在二进制中需要的位数
int length(int i) {
int k = 1; // 初始化位数计数器
i = i / 2; // 将整数除以2,开始计算
while (i > 0) { // 当i大于0时继续
k++; // 每次循环位数增加1
i = i / 2; // 继续除以2
}
return k; // 返回计算得到的位数
}
void Compress(int n, int p[], int s[], int l[], int b[]) {
int Lmax = 256, header = 11; // 定义最大段数和头部长度
s[0] = 0; // 初始化s数组
for (int i = 0; i <= n; i++) { // 遍历每个元素
b[i] = length(p[i]); // 计算当前元素的位数
int bmax = b[i]; // 记录当前最大位数
s[i] = (i > 0 ? s[i - 1] : 0) + bmax + header; //当前段的最小存储长度
l[i] = 1; // 初始段数为1
for (int j = 2; j <= i + 1 && j <= Lmax; j++) { // 遍历可能的段数
if (bmax < length(p[i - j + 1])) { // 更新最大位数
bmax = length(p[i - j + 1]);
}
// 判断是否需要更新存储长度
if (s[i] > s[i - j] + j * bmax + header) {
s[i] = s[i - j] + j * bmax + header; // 更新最小存储长度
l[i] = j; // 更新段数
b[i] = bmax; // 更新位数
}
}
printf("组 %d: L = %d, B = %d, S = %d\n", i, l[i], b[i], s[i]);
}
}
// 追溯函数,恢复最优分段信息
int TraceBack(int n, int l[], int b[]) {
int i = 0;
int temp_l[N], temp_b[N]; // 临时数组存储分段信息
// 从最后一个元素向前追溯
while (n >= 0) {
temp_l[i] = l[n]; // 记录段数
temp_b[i] = b[n]; // 记录位数
n = n - l[n]; // 更新n,向前移动
i++; // 增加索引
}
// 反转数组,恢复正确顺序
for (int j = 0; j < i; j++) {
b[j] = temp_b[i - j - 1]; // 反向赋值位数
l[j] = temp_l[i - j - 1]; // 反向赋值段数
}
return i; // 返回段数
}
// 输出函数,展示最终结果
void Out(int m, int min_len, int l[], int b[], int p[]) {
printf("最小长度:%d\n", min_len); // 输出最小存储长度
printf("共分成:%d段\n", m); // 输出段数
int index = 0; // 初始化索引
for (int i = 0; i < m; i++) {
// 输出每段的信息
printf("第%d段含有%d元素. 需要存储位数%d,", i + 1, l[i], b[i]);
printf("元素值:");
// 输出当前段的元素值
for (int j = 0; j < l[i]; j++) {
printf("%d ", p[index++]); // 逐个输出元素
}
printf("\n"); // 换行
}
}
// 主函数,程序入口
int main() {
int p[] = {4, 6,5, 7, 129, 138, 1,2,3}; // 输入的灰度序列
int s[N] = {0}, l[N] = {0}, b[N] = {0}; // 初始化存储长度、段数和位数的数组
// 输出输入序列
printf("图像的灰度序列为:\n");
for (int i = 0; i < N; i++) {
printf("%d ", p[i]);
}
printf("\n");
// 调用压缩函数
Compress(N - 1, p, s, l, b);
int m = TraceBack(N - 1, l, b); // 调用追溯函数获取段数
Out(m, s[N - 1], l, b, p); // 输出结果
return 0;
}