解码步骤:
1、读取按顺序读取文件中的字符使用次数、原文件字符长度、哈夫曼编码长度、哈夫曼编码
2、和编码步骤一样,通过字符使用次数构建哈夫曼树
3、根据哈夫曼树,对哈夫曼编码进行解码,把其解码出来的内容写入原文件字符大小的动态数组中
4、把数组写入新文件
代码实现
struct HufNode
{
unsigned char c;
char code;
int usetime;
//
HufNode *pParent;
HufNode *pLc;
HufNode *pRc;
};
//拷贝数组
struct HufArrayNode
{
int usetimes;
HufNode *pRoot;
};
//进行数组和树之间的转接
struct HufData
{
unsigned char c;
int usetime;
HufNode *pRoot;
};
bool FindMinHufDataInHufArray(HufArrayNode *pHufArray, HufData &hufdata)
{
hufdata.c = '\0';
hufdata.usetime = 0;
for (int i = 0; i < 256; ++i)
{
if (hufdata.usetime == 0)
{
if (pHufArray[i].usetimes> 0)
{
hufdata.c = i;
hufdata.usetime = pHufArray[i].usetimes;
hufdata.pRoot = pHufArray[i].pRoot;
}
}
else
{
if (pHufArray[i].usetimes > 0)
{
if (pHufArray[i].usetimes < hufdata.usetime)
{
hufdata.c = i;
hufdata.usetime = pHufArray[i].usetimes;
hufdata.pRoot = pHufArray[i].pRoot;
}
}
}
}
if (hufdata.usetime > 0)
{
pHufArray[hufdata.c].usetimes = 0;
pHufArray[hufdata.c].pRoot = nullptr;
return true;
}
else
{
return false;
}
}
bool FindMinOver(HufArrayNode const * const pHufArray)
{
int num = 0;
for (int i = 0; i < 256; ++i)
{
if (pHufArray[i].usetimes>0)
{
++num;
}
}
return num == 1;
}
void DestroyTree(HufNode *pRoot)
{
if (pRoot->pLc)
{
DestroyTree(pRoot->pLc);
}
if (pRoot->pRc)
{
DestroyTree(pRoot->pRc);
}
if (pRoot)
{
delete pRoot;
pRoot = nullptr;
}
}
HufNode *pRoot;
int _tmain(int argc, _TCHAR* argv[])
{
if (argc < 2)
{
printf("没有待解码文件\n");
getchar();
return 0;
}
FILE *fp = nullptr;
fopen_s(&fp, argv[1], "rb");
printf("读取文件\n");
if (fp)
{
int hufcodearray[256];
int orgfilesize;
int hufcodesize;
unsigned char *pHufCodeData;
fread(hufcodearray, sizeof(int), 256, fp);
fread(&orgfilesize, sizeof(int), 1, fp);
fread(&hufcodesize, sizeof(int), 1, fp);
pHufCodeData = new unsigned char[hufcodesize];
fread(pHufCodeData, sizeof(unsigned char), hufcodesize, fp);
fclose(fp);
fp = nullptr;
printf("读取成功\n");
HufArrayNode hufarray[256];
for (int i = 0; i < 256;++i)
{
hufarray[i].usetimes = hufcodearray[i];
hufarray[i].pRoot = nullptr;
}
printf("开始建树\n");
HufData hufdata;
while (!FindMinOver(hufarray))
{
HufNode *pTempRc;
HufNode *pTempLc;
HufNode *pTempRoot;
if (FindMinHufDataInHufArray(hufarray, hufdata))
{
if (hufdata.pRoot)
{
pTempRc = hufdata.pRoot;
pTempRc->c = 0;
pTempRc->code = 0;
}
else
{
pTempRc = new HufNode;
pTempRc->c = hufdata.c;
pTempRc->code = 0;
pTempRc->usetime = hufdata.usetime;
pTempRc->pParent = nullptr;
pTempRc->pLc = nullptr;
pTempRc->pRc = nullptr;
}
}
if (FindMinHufDataInHufArray(hufarray, hufdata))
{
if (hufdata.pRoot)
{
pTempLc = hufdata.pRoot;
pTempLc->c = 0;
pTempLc->code = 1;
}
else
{
pTempLc = new HufNode;
pTempLc->c = hufdata.c;
pTempLc->code = 1;
pTempLc->usetime = hufdata.usetime;
pTempLc->pParent = nullptr;
pTempLc->pLc = nullptr;
pTempLc->pRc = nullptr;
}
}
pTempRoot = new HufNode;
pTempRoot->code = 0;
pTempRoot->c = 0;
pTempRoot->usetime = pTempRc->usetime + pTempLc->usetime;
pTempRoot->pParent = nullptr;
pTempRoot->pLc = pTempLc;
pTempRoot->pRc = pTempRc;
pTempRc->pParent = pTempRoot;
pTempLc->pParent = pTempRoot;
for (int i = 0; i < 256;++i)
{
if (hufarray[i].usetimes == 0)
{
hufarray[i].usetimes = pTempRoot->usetime;
hufarray[i].pRoot = pTempRoot;
break;
}
}
}
if (FindMinHufDataInHufArray(hufarray,hufdata))
{
pRoot = hufdata.pRoot;
printf("建树完成\n");
}
HufNode *pCurrent = nullptr;
int ByteSit = 0;
int BitSit = 0;
unsigned char *pOutBuffer = new unsigned char[orgfilesize];
for (int o = 0; o < orgfilesize;++o)
{
pCurrent = pRoot;
while (pCurrent->pRc || pCurrent->pLc)
{
switch (BitSit)
{
case 0:
{
if (pHufCodeData[ByteSit] & 0x80)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
case 1:
{
if (pHufCodeData[ByteSit] & 0x40)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
case 2:
{
if (pHufCodeData[ByteSit] & 0x20)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
case 3:
{
if (pHufCodeData[ByteSit] & 0x10)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
case 4:
{
if (pHufCodeData[ByteSit] & 0x08)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
case 5:
{
if (pHufCodeData[ByteSit] & 0x04)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
case 6:
{
if (pHufCodeData[ByteSit] & 0x02)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
case 7:
{
if (pHufCodeData[ByteSit] & 0x01)
{
pCurrent = pCurrent->pLc;
}
else
{
pCurrent = pCurrent->pRc;
}
}
break;
default:
break;
}
++BitSit;
if (BitSit >= 8)
{
BitSit = 0;
++ByteSit;
}
}
pOutBuffer[o] = pCurrent->c;
}
string outfilename = argv[1];
outfilename.pop_back();
outfilename.pop_back();
outfilename.pop_back();
outfilename.pop_back();
outfilename += ".txt";
FILE *outfp = nullptr;
fopen_s(&outfp, outfilename.c_str(), "wb");
if (outfp)
{
fwrite(pOutBuffer, sizeof(unsigned char), orgfilesize, outfp);
fclose(outfp);
outfp = nullptr;
}
else
{
printf("解码文件暂时无法写入!");
}
SAFE_DELARR(pOutBuffer);
DestroyTree(pRoot);
SAFE_DELARR(pHufCodeData);
}
else
{
printf("待解码的文件不存在或暂时无法打开!\n");
}
getchar();
return 0;
}