【问题标题】:Using fwrite() with huffman encodings - Bit Shifting and Bit Manipulations将 fwrite() 与霍夫曼编码一起使用 - 位移和位操作
【发布时间】:2013-02-26 04:51:08
【问题描述】:

我正在做霍夫曼编码,但我无法理解如何使用 fwrite() 将我们的编码写入输出。

假设我有这些编码:

Character A (65) gets an encoding of 101
Character B (66) gets an encoding of 1100111

但是,这些编码被保存为整数,所以

101 actually has a decimal value of 5 which is saved in memory as 00000101
1100111 actually has a decimal value of 103 which is saved in memory as 01100111

所以,当我们想使用 fwrite() 写出它们时,假设我们使用了一个缓冲区

int buff[4]

开头是

buff[0]    buff[1]    buff[2]    buff[3]
XXXXXXXX - XXXXXXXX - XXXXXXXX - XXXXXXXX

(用X表示未初始化)为什么要用4个字节?因为我们需要考虑非常长的编码。如果我们有一个 27 位长的编码怎么办?我们需要完全填充其中三个字节和第四个字节。

现在,假设我们需要对这一系列字符进行编码并将它们写入输出文件:

“ABB”

首先,我们对 A 进行编码,我们的 buff[] 应该变成:

buff[0]    buff[1]    buff[2]    buff[3]
101XXXXX - XXXXXXXX - XXXXXXXX - XXXXXXXX

然后,我们需要对 B 进行编码,所以我们的 buff[] 应该变成:

buff[0]    buff[1]    buff[2]    buff[3]
10111001 - 11XXXXXX - XXXXXXXX - XXXXXXXX

现在,buff[] 的一个字节已满,所以我们需要对该字节进行编码并将 buff[] 的其他槽向下移动

fwrite(buff[0], 1, 1, fptOutput);
/* insert code to shift buff down */

所以现在我们的buff变成了:

buff[0]    buff[1]    buff[2]    buff[3]
11XXXXXX - XXXXXXXX - XXXXXXXX - XXXXXXXX

接下来,我们编码另一个“B”,我们的 buff[] 变成:

buff[0]    buff[1]    buff[2]    buff[3]
11110011 - 1XXXXXXX - XXXXXXXX - XXXXXXXX

然后,我们再次 fwrite() buff[0] 并再次执行移位。

但是,我们没有其他要编码的东西,所以我们必须用 0 填充其余字节,所以我们的 buff 现在是:

buff[0]    buff[1]    buff[2]    buff[3]
10000000 - XXXXXXXX - XXXXXXXX - XXXXXXXX

然后 fwrite 最后一个字节,然后我们就完成了。

问题是我完全不知道如何系统地编程。我理解位操作。例如,在我们的第一个“A”编码中,我们需要将“00000101”向左移动 5 个点,使其变为“101-----”,我理解这一步,但我不知道如何跟踪我们下一次编码的转移位置。

如果我手动完成,我可以弄清楚如何根据需要移动每个变量,但我不知道如何提出一系列方程,这些方程适用于 a 中的每个编码系列很长的文件。

【问题讨论】:

  • 基本上你只需将每个字符的编码附加到你的临时数组中,一旦你得到至少 8 位的编码数据,你写出这 8 位,将余数移动 8,然后继续附加,直到你得到另一个完整的字节。冲洗,重复。出于效率考虑,您可能希望使用大于 4 字节的缓冲区,因为一次写入一个字节的大文件非常慢。

标签: c algorithm function bit-manipulation bit-shift


【解决方案1】:

您需要存储每个字符的编码数组以及每个字符编码中的位数的数组,因为它们都是不同的。

然后你需要跟踪你的 buff 数组中还剩下多少位。

然后,每次您想添加一个字符时,您都将该字符编码复制到另一个临时缓冲区中。然后,您将该编码向上移动 buff 数组中已保留的位数。然后你按位或你的移位编码到你的 buff 数组上。

然后你从你的 buff 数组中写入数据并将剩余的 buff 数据向下移动并调整 buff 数组中剩余的位数。

以下是一个向上或向下按位移动 16 位整数(短整数)数组的函数。这有点矫枉过正,因为它会向上或向下移动位。您可以修改它以处理字节或长:

void 
shiftBits(unsigned short int *buffer, int bufferSize, int bitsToShiftUp)
{
int wordsToShift;
int bitsToShift;
int backBitsToShift;
int iTo;
int iFrom;

if (bitsToShiftUp > 0)
{
    //Shift up
    wordsToShift = bitsToShiftUp / 16;
    bitsToShift = bitsToShiftUp - (wordsToShift * 16);

    iTo = bufferSize - 1;
    iFrom = iTo - wordsToShift;

    if (bitsToShift == 0)
    {
        while (iFrom >= 0)
        {
            buffer[iTo] = buffer[iFrom];
            iTo--;
            iFrom--;
        }
        while (iTo >= 0)
        {
            buffer[iTo] = 0;
            iTo--;
        }
    }
    else
    {
        backBitsToShift = 16 - bitsToShift;
        while (iFrom >= 1)
        {
            buffer[iTo] = (buffer[iFrom] << bitsToShift) | (buffer[iFrom-1] >> backBitsToShift);
            iTo--;
            iFrom--;
        }
        if (iFrom >= 0)
        {
            buffer[iTo] = buffer[iFrom] << bitsToShift;
            iTo--;
        }
        while (iTo >= 0)
        {
            buffer[iTo] = 0;
            iTo--;
        }
    }
}
else if (bitsToShiftUp  < 0)
{
    //Shift down
    wordsToShift = (-bitsToShiftUp) / 16;
    bitsToShift = (-bitsToShiftUp) - (wordsToShift * 16);

    iTo = 0;
    iFrom = wordsToShift;

    if (bitsToShift == 0)
    {
        while (iFrom < bufferSize)
        {
            buffer[iTo] = buffer[iFrom];
            iTo++;
            iFrom++;
        }
        while (iTo < bufferSize)
        {
            buffer[iTo] = 0;
            iTo++;
        }
    }
    else
    {
        backBitsToShift = 16 - bitsToShift;
        while (iFrom < bufferSize - 1)
        {
            buffer[iTo] = (buffer[iFrom] >> bitsToShift) | (buffer[iFrom+1] << backBitsToShift);
            iTo++;
            iFrom++;
        }
        if (iFrom < bufferSize)
        {
            buffer[iTo] = buffer[iFrom] >> bitsToShift;
            iTo++;
        }
        while (iTo < bufferSize)
        {
            buffer[iTo] = 0;
            iTo++;
        }
    }
}
}

【讨论】:

  • 顺便说一句,你不能只用一堆零终止,因为一个或多个零可以是霍夫曼编码中的有效代码。您要么需要存储数据的大小(以位为单位),要么引入特定的终止编码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多