Huffman.h
#pragma once
#ifndef HUFFMAN_H
#define HUFFMAN_H
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(push)
#pragma warning(disable:6385)
#pragma warning(disable:6386)
#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct
{
int weight;
int parent, lchild, rchild;
}HTNode,*HuffmanTree;
typedef char** HuffmanCode;
#endif
Huffman.cpp
#include "huffman.h"
void Select(HuffmanTree& HT, int n, int s1, int s2)
{
}
void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n)
{
if (n <= 1)
return;
int m = 2 * n - 1;
//HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
HT = new HTNode[m+1]; //0号单元未用
int i;
HTNode* p;
int s1=1, s2=2;
for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++w)
*p = { *w,0,0,0 };
for (; i <= m; ++i, ++p)
*p = { 0,0,0,0 };
for (i = n + 1; i <= m; ++i)
{
Select(HT, i - 1, s1, s2); //在HT[1...i-1]找到parent为0权重最小的两个结点
HT[s1].parent = HT[s2].parent = i;
HT[i].lchild = s1; HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
//从叶子到根逆向求Huffman编码
HC = new char*;
char* cd = new char[n];
int c, f;
cd[n - 1] = '\0';
for (i = 1; i <= n; ++i)
{
int start = n - 1;
for (c = i, f = HT[i].parent; f != 0; c=f,f = HT[f].parent)
{
if (HT[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
}
HC[i] = new char;
strcpy(HC[i], &cd[start]);
}
delete[] cd;
}
void HuffmanCoding2(HuffmanTree& HT, HuffmanCode& HC, int* w, int n)
{
if (n <= 1)
return;
int m = 2 * n - 1;
//HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
HT = new HTNode[m + 1]; //0号单元未用
int i;
HTNode* p;
int s1 = 1, s2 = 2;
for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++w)
*p = { *w,0,0,0 };
for (; i <= m; ++i, ++p)
*p = { 0,0,0,0 };
for (i = n + 1; i <= m; ++i)
{
Select(HT, i - 1, s1, s2); //在HT[1...i-1]找到parent为0且权重最小的两个结点
HT[s1].parent = HT[s2].parent = i;
HT[i].lchild = s1; HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
//无栈非递归遍历Huffman树,从根结点开始遍历
HC = new char*;
int q = m, cdlen = 0;
char* cd = new char;
//cd = (char*)malloc(n * sizeof(char));
//cd[n - 1] = "\0";
for (i = 1; i <= m; ++i)
HT[i].weight = 0;
while (q)
{
if (HT[q].weight == 0) //向左
{
HT[q].weight = 1;
if (HT[q].lchild)
{
cd[cdlen++] = '0';
q = HT[q].lchild;
}
else
{
HC[q] = new char;
cd[cdlen] = '\0';
strcpy(HC[q], cd);
}
}
else if (HT[q].weight == 1)
{
HT[q].weight = 2;
if (HT[q].lchild)
{
q = HT[q].rchild;
cd[cdlen++] = '1';
}
}
else
{
HT[q].weight = 0;
q = HT[q].parent;
--cdlen;
}
}
}
注:在Visual Studio2019中,在进行编译时出现了这样的警告:
-
C6385:从…中读取的数据无效: 可读大小为…个字节,但可能读取了…个字节;
-
C6386:从…中写入到…时缓冲区溢出: 可写大小为…个字节,但可能写入了…个字节
微软在默认情况下强制对C和C++代码强制使用SAL分析,除了以上两种警告外,还有其他的一些误报(false positive)。
解决方法
#pragma warning(push)是保存当前的编译器警告状态;
#pragma warning(pop)是恢复原先的警告状态。
#pragma warning(push)
#pragma warning(disable:6385)
#pragma warning(disable:6386)
/*Source Code*/
#pragma warning(pop)
这样在编译Source Code部分的代码时,6385、6386警告将不会出现。
也可以不加#pragma warning(push)和#pragma warning(pop),这样#pragma warning(disable:6385)和#pragma warning(disable:6386)将在全局生效。
C6385,C6386警告的原文链接:https://www.cnblogs.com/csgo-416482145/p/13828845.html