使用带有霍夫曼编码的fwrite() - 位移和位操作

时间:2013-02-26 04:51:09

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

我正在进行霍夫曼编码,我无法理解如何使用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

并写入最后一个字节,然后我们就完成了。

问题是我完全不知道如何系统地编程。我理解位操纵。例如,在我们的第一个“A”编码中,我们需要将“00000101”移到左边的5个点,这样就变成了“101 -----”,我理解了这一步,但后来我不知道如何跟踪我们下一次编码的转移位置。

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

1 个答案:

答案 0 :(得分:0)

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

然后你需要跟踪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++;
        }
    }
}
}