贪心算法之用优先队列(priority_queue)实现哈夫曼编码问题

1、问题

参考我的博客:贪心算法之哈夫曼编码问题

2、优先队列知识复习

参考我的博客:
C++之STL之priority_queue


3、代码实现

#include <iostream>
#include <queue>

using namespace std;

//最大字符编码数组长度
#define MAXCODELEN 100
//最大哈夫曼节点结构体数组个数
#define MAXHAFF 100
//最大哈夫曼编码结构体数组的个数
#define MAXCODE 100
#define MAXWEIGHT  10000;


typedef struct Haffman
{
    //权重
    int weight;
    //字符
    char ch;
    //父节点
    int parent;
    //左儿子节点
    int leftChild;
    //右儿子节点
    int rightChild;
	//下标
	int index;
}HaffmaNode;

struct cmp 
{
	bool operator() (HaffmaNode haffman1, HaffmaNode haffman2)
	{
		return haffman1.weight > haffman2.weight;
	}	
};

typedef struct Code
{
    //字符的哈夫曼编码的存储
    int code[MAXCODELEN];
    //从哪个位置开始
    int start;
}HaffmaCode;

HaffmaNode haffman[MAXHAFF];
HaffmaCode code[MAXCODE];
priority_queue<HaffmaNode, vector<HaffmaNode>, cmp> que;


void buildHaffman(int all)
{
    //哈夫曼节点的初始化之前的工作, weight为0,parent,leftChile,rightChile都为-1
    for (int i = 0; i < all * 2 - 1; ++i)
    {
        haffman[i].weight = 0;
        haffman[i].parent = -1;
        haffman[i].leftChild = -1;
        haffman[i].rightChild = -1;
		haffman[i].index = -1;
    }
    std::cout << "请输入需要哈夫曼编码的字符和权重大小" << std::endl;
    for (int i = 0; i < all; i++)
    {
        std::cout << "请分别输入第个" << i << "哈夫曼字符和权重" << std::endl;
        std::cin >> haffman[i].ch;
        std::cin >> haffman[i].weight;
		haffman[i].index = i;
		que.push(haffman[i]);
    }

	/**	
	while (!que.empty())
	{
		HaffmaNode node = que.top();
		std::cout << node.weight << std::endl;
		que.pop();
	}
	**/
	for (int i = 0; i < all - 1; ++i) 
	{
		HaffmaNode node1, node2;
		node1 = que.top();
		std::cout << node1.weight << std::endl;
		que.pop();
		node2 = que.top();
		std::cout << node2.weight << std::endl;
		que.pop();
		haffman[all + i].weight = node1.weight + node2.weight;		
		haffman[all + i].leftChild = node1.index;
		haffman[all + i].rightChild = node2.index;
		haffman[all + i].index = all + i;
		//这里不是node1.parent = all + i和node2.parent = all + i;
		//不然临时变量销毁了
		//node1.parent = all + i;
		//node2.parent = all + i;
		haffman[node1.index].parent = all + i;
		haffman[node2.index].parent = all + i;
	    std::cout << "haffman["<<all + i << "]:" << haffman[all + i].weight << "left is:" << haffman[all + i].leftChild << "right is:" << haffman[all + i].rightChild << std::endl;
		que.push(haffman[all + i]);
	}
	
}

//打印每个字符的哈夫曼编码
void printCode(int all)
{
    //保存当前叶子节点的字符编码
    HaffmaCode hCode;
    //当前父节点
    int curParent;
    //下标和叶子节点的编号
    int c;
    //遍历的总次数
    for (int i = 0; i < all; ++i)
    {
        hCode.start = all - 1;
        c = i;
        curParent = haffman[i].parent;
        //遍历的条件是父节点不等于-1
        while (curParent != -1)
        {
            //我们先拿到父节点,然后判断左节点是否为当前值,如果是取节点0
            //否则取节点1,这里的c会变动,所以不要用i表示,我们用c保存当前变量i
            if (haffman[curParent].leftChild == c)
            {
                hCode.code[hCode.start] = 0;
                std::cout << "hCode.code[" << hCode.start << "] = 0" << std::endl;
            }
            else
            {
                hCode.code[hCode.start] = 1;
                std::cout << "hCode.code[" << hCode.start << "] = 1" << std::endl;
            }
            hCode.start--;
            c = curParent;
            curParent = haffman[c].parent;
        }
        //把当前的叶子节点信息保存到编码结构体里面
        for (int j = hCode.start + 1; j < all; ++j)
        {
            code[i].code[j] = hCode.code[j];
        }
        code[i].start = hCode.start;
    }

}

int main()
{
    std::cout << "请输入有多少个哈夫曼字符" << std::endl;
    int all = 0;
    std::cin >> all;
    if (all <= 0)
    {
        std::cout << "您输入的个数有误" << std::endl;
        return -1;
    }
    buildHaffman(all);
    printCode(all);

	for (int i = 0; i < all * 2 - 1; ++i)
	{
		std::cout << haffman[i].parent << std::endl;	
	}
	for (int i = 0; i < all; ++i)
    {
        std::cout << haffman[i].ch << ": Haffman Code is:";
        for (int j = code[i].start + 1; j < all; ++j)
        {
            std::cout << code[i].code[j];
        }
        std::cout << std::endl;
    }
    return 0;
}

4、运行结果

请输入有多少个哈夫曼字符
6
请输入需要哈夫曼编码的字符和权重大小
请分别输入第个0哈夫曼字符和权重
a 5
请分别输入第个1哈夫曼字符和权重
b 32
请分别输入第个2哈夫曼字符和权重
c 18
请分别输入第个3哈夫曼字符和权重
d 7
请分别输入第个4哈夫曼字符和权重
e 25
请分别输入第个5哈夫曼字符和权重
f 13
5
7
haffman[6]:12left is:0right is:3
12
13
haffman[7]:25left is:6right is:5
18
25
haffman[8]:43left is:2right is:4
25
32
haffman[9]:57left is:7right is:1
43
57
haffman[10]:100left is:8right is:9
hCode.code[5] = 0
hCode.code[4] = 0
hCode.code[3] = 0
hCode.code[2] = 1
hCode.code[5] = 1
hCode.code[4] = 1
hCode.code[5] = 0
hCode.code[4] = 0
hCode.code[5] = 1
hCode.code[4] = 0
hCode.code[3] = 0
hCode.code[2] = 1
hCode.code[5] = 1
hCode.code[4] = 0
hCode.code[5] = 1
hCode.code[4] = 0
hCode.code[3] = 1
6
9
8
6
8
7
7
9
10
10
-1
a: Haffman Code is:1000
b: Haffman Code is:11
c: Haffman Code is:00
d: Haffman Code is:1001
e: Haffman Code is:01
f: Haffman Code is:101

5、总结

我们知道有限队列找出最小元素时间复杂度是log(n),所以时间复杂度降低了,变成了n * log(n).

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/u011068702/article/details/79451943
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞