Huffuman编码的实现

Huffuman编码思想:根据字符出现的概率大小进行编码,出现概率高的字符使用较短的编码,出现概率低的字符使用较长的编码。

附上一个图个一个微博链接,可以自己感受一下。哈夫曼树以及哈夫曼编码的构造步骤_LDF-Dicky的博客-CSDN博客_哈夫曼树的构造

 代码实现:这部分代码粗看不难,但是细细分析之中的实现还是挺费脑的,尤其是中间在做递归之前传入的参数的结构,可以调试自己分析一下。

 

 

// Huffuman.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <queue>
#include <vector>
#include <string>

using namespace std;

//每一个符号定义为一个结构体,包括字符和出现频次
typedef struct
{
	unsigned char	character;  //定义字符是谁
	unsigned int	frequency;  //定义字符出现的频率
} CharNode;

static bool open_input_file(ifstream &input, const char *inputFileName)
{
	input.open(inputFileName);
	if (!input.is_open())
	{
		return false;
	}
	return true;
}
//定义一个二叉树结点
struct MinHeapNode
{
	char data; //值
	unsigned int freq; //频次
	MinHeapNode *left, *right; //定义两个子节点
	MinHeapNode(char data, unsigned freq) //定义结构体的构造函数,结构体和类的区别(可自行百度)
	{
		left = right = NULL;
		this->data = data;
		this->freq = freq;
	}
};
typedef struct MinHeapNode MinHeapNode;
//重写仿函数,实现降序,运算符重载也可以实现,具体见:https://blog.csdn.net/weixin_36888577/article/details/79937886
struct compare
{
	bool operator()(MinHeapNode* l, MinHeapNode *r)
	{
		return (l->freq > r->freq);
	}
};

static void get_huffman_code(MinHeapNode *root, string code)
{	//第一个参数表示根节点,第二次参数用于输出一个字符
	if (!root) //如果根节点为空
	{
		return;
	}

	if (root->data != -1) //下面合并生成的新字符都赋值成了-1,如果不是-1,到了最下面的子节点
	{
		cout << root->data << " : " << code << endl;;
	}

	get_huffman_code(root->left, code + "0"); //如果到了根节点,在左子树节点上加0,在右子树节点加1
	get_huffman_code(root->right, code + "1");
}

int _tmain(int argc, _TCHAR* argv[])
{
	ifstream inputFile; //构建文件输入流对象
	if (!open_input_file(inputFile, "input.txt")) //打开input.txt文件
	{
		cout << "Error: opening input file failed!" << endl;
		return -1;
	}

	char buf = inputFile.get(); //从文件流中读取一个字符放到buf中
	CharNode nodeArr[256] = { { 0, 0 } }; //一个字符,占据一个字节,有256中可能2^8 = 256,将里面元素全部初始化为0
	while (inputFile.good()) // 表示文件正常,没有读写错误,也不是坏的,也没有结束
	{
		cout << buf;
		nodeArr[buf].character = buf; //同样的结果会重复赋值,不造成影响
		nodeArr[buf].frequency++; //频率++,在全部遍历完之后就可以知道全部字符出现多少此
		buf = inputFile.get();
	}
	cout << endl;

	priority_queue<MinHeapNode*, vector<MinHeapNode*>, compare>  minHeap;
	for (int idx = 0; idx < 256; idx++)
	{
		if (nodeArr[idx].frequency > 0)
		{	//输出字符和次数
			cout << "Node " << idx << ": [" << nodeArr[idx].character << ", " << nodeArr[idx].frequency << "]" << endl;
			minHeap.push(new MinHeapNode(nodeArr[idx].character, nodeArr[idx].frequency));//使用优先级队列实现排序功能
		}
	}

	MinHeapNode *leftNode = NULL, *rightNode = NULL, *topNode = NULL;
	while (minHeap.size() != 1) //只剩下根节点的时候停止运行
	{
		leftNode = minHeap.top(); //得到优先级最小的那个元素
		minHeap.pop(); //弹出最小元素

		rightNode = minHeap.top(); //再拿到一个最小元素
		minHeap.pop();

		topNode = new MinHeapNode(-1, leftNode->freq + rightNode->freq); //两个最小的节点合并成一个节点,-1可以理解成一个虚值,不在文章里面的一个字符
		topNode->left = leftNode;
		topNode->right = rightNode;
		minHeap.push(topNode); //将刚刚构造好的新节点放进minHeap里面重新进行排序
	}

	get_huffman_code(topNode, "");  //出循环之后,topNode表示的就是根节点

	inputFile.close();
	return 0;

}

 

队列优先级实现:

#include<iostream>
#include <queue>
using namespace std;
//定义:priority_queue<Type, Container, Functional>
/*
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,
比如vector,deque等等,但不能用 list。STL里面默认用的是vector),
Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,
使用基本数据类型时,只需要传入数据类型,默认是大顶堆
*/
int main()
{
    //对于基础类型 默认是大顶堆,降序
    priority_queue<int> a;
    //等同于 priority_queue<int, vector<int>, less<int> > a;


    priority_queue<int, vector<int>, greater<int> > c;  //这样就是小顶堆,升序
    priority_queue<string> b;

    for (int i = 0; i < 5; i++)
    {
        a.push(i);
        c.push(i);
    }
    while (!a.empty())
    {
        cout << a.top() << ' ';
        a.pop();
    }
    cout << endl;

    while (!c.empty())
    {
        cout << c.top() << ' ';
        c.pop();
    }
    cout << endl;
    //字符,按照字母的先后顺序
    b.push("abc");
    b.push("abcd");
    b.push("cbd");
    while (!b.empty())
    {
        cout << b.top() << ' ';
        b.pop();
    }
    cout << endl;
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值