哈夫曼解码

解码步骤:

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;
}

### Java实现哈夫曼解码的方法 在Java中实现哈夫曼解码的过程主要包括以下几个方面:构建哈夫曼树、生成编码映射关系以及基于该映射关系完成解码操作。以下是详细的说明和代码示例。 #### 1. 构建哈夫曼哈夫曼树的构建过程依赖于输入数据中各字符的频率统计结果。通常会先创建一个节点类 `HuffmanNode` 来表示树中的每一个节点,随后通过优先队列(PriorityQueue)按照权重从小到大依次合并节点直到形成完整的二叉树结构[^1]。 ```java class HuffmanNode implements Comparable<HuffmanNode> { char character; int frequency; HuffmanNode left, right; public HuffmanNode(char character, int frequency) { this.character = character; this.frequency = frequency; } @Override public int compareTo(HuffmanNode other) { return this.frequency - other.frequency; } } ``` #### 2. 创建哈夫曼树并生成编码表 通过对哈夫曼树进行深度优先搜索可以获取每个叶子节点所代表字符对应的唯一路径作为其编码值。此部分可以通过递归方式实现,并将最终的结果存入HashMap以便快速查找匹配[^3]。 ```java import java.util.*; public class HuffmanDecoding { private static Map<Character, Integer> buildFrequencyMap(String text) { Map<Character, Integer> freqMap = new HashMap<>(); for (char c : text.toCharArray()) { freqMap.put(c, freqMap.getOrDefault(c, 0) + 1); } return freqMap; } private static HuffmanNode buildTree(Map<Character, Integer> freqMap) { PriorityQueue<HuffmanNode> pq = new PriorityQueue<>(freqMap.size(), Comparator.comparingInt(node -> node.frequency)); // 将所有字符加入最小堆 for (var entry : freqMap.entrySet()) { pq.add(new HuffmanNode(entry.getKey(), entry.getValue())); } while (pq.size() != 1) { HuffmanNode left = pq.poll(); HuffmanNode right = pq.poll(); HuffmanNode parent = new HuffmanNode('\0', left.frequency + right.frequency); parent.left = left; parent.right = right; pq.add(parent); } return pq.peek(); // 返回根节点 } private static void generateCodes(HuffmanNode root, String code, StringBuilder sb, Map<String, Character> codes) { if (root == null) return; if (!isLeaf(root)) { sb.append('0'); generateCodes(root.left, code + '0', sb, codes); sb.setLength(sb.length()-1); // 回溯 sb.append('1'); generateCodes(root.right, code + '1', sb, codes); sb.setLength(sb.length()-1); // 回溯 } else { codes.put(code.toString(), root.character); } } private static boolean isLeaf(HuffmanNode node){ return node.left==null && node.right==null; } } ``` #### 3. 解码函数 有了前面准备好的编码表后,在实际执行解码时只需要逐位读取待解析的数据流并与当前已知最长前缀逐一比较直至找到完全一致项即可替换回原始字符[^2]。 ```java private static String decodeText(HuffmanNode root, String encodedString) { StringBuilder decodedOutput = new StringBuilder(); HuffmanNode currentNode = root; for (int i=0;i<encodedString.length();i++) { if(encodedString.charAt(i)=='0') { currentNode=currentNode.left; }else{ currentNode=currentNode.right; } if(isLeaf(currentNode)){ decodedOutput.append(currentNode.character); currentNode=root; //重置指针回到树顶继续下一个字符的寻找 } } return decodedOutput.toString(); } // 测试方法调用 public static void main(String[] args) throws Exception { String inputStr="i like like like java do you like a java"; System.out.println("Original Input:"+inputStr+"\n"); // Step1: Build Frequency Table & Tree Construction Map<Character,Integer> freqTable=buildFrequencyMap(inputStr.replaceAll("\\s+","")); HuffmanNode rootNode=buildTree(freqTable); //Step2: Generate Codes Mapping from the constructed tree. Map<String,Character> huffManCode=new LinkedHashMap<>();//LinkedHashmap maintains insertion order which helps during decoding process later on. generateCodes(rootNode,"",new StringBuilder(),huffManCode); // Print Generated Code mapping table just to verify correctness of our algorithm implementation so far. System.out.print("\tGenerated Huffamn Encoding:\n"); for(var e:huffManCode.entrySet()){ System.out.printf("%c:%s\n",e.getValue(),e.getKey()); } // Encode Original Message into Binary Form using above generated mappings. StringBuilder binaryEncodedMsg=new StringBuilder(); for(Character ch:inputStr.toCharArray()) if(huffManCode.containsKey(ch+""))binaryEncodedMsg.append(huffManCode.get((ch+""))); else throw new RuntimeException("Invalid Symbol Found!"); System.out.println("\n\tBinary Encoded Output:"); System.out.println(binaryEncodedMsg.toString()); // Decode Back Again To Verify Everything Works Fine Until Now ! String finalResult=decodeText(rootNode,binaryEncodedMsg.toString().replaceAll("[\\r\\n]+","")); System.out.println("\nFinal Decoded Result After Applying Reverse Process On Above Ciphertext Is As Follows:"); System.out.println(finalResult.equals(inputStr)?finalResult:"ERROR OCCURRED WHILE DECODING PROCESS PLEASE CHECK YOUR IMPLEMENTATION AGAIN."); } ``` 以上即为整个基于Java语言环境下关于如何具体实施哈夫曼编译器当中涉及到了几个核心环节的具体阐述与示范程序片段展示[^1][^2].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值