zoukankan      html  css  js  c++  java
  • 优先队列解哈夫曼编码问题之带权路径长度

    1.什么是优先队列?


    先说个生活中的例子
    想想医院,重症急诊患者肯定不能像普通患者那样依次排队就诊,他们就可以插队了
    他比较迟进队列,但他优先级高,所以就相对较早出队列去就诊了

    优先队列一般用堆来实现,堆有两种(具体看这:http://blog.csdn.net/u012763794/article/details/51002372
    对于大根堆实现的优先队列,总是优先级高的元素先被删除;相对的,对于小根堆实现的优先队列,总是优先级低的元素先被删除。

    那么对于大根堆:你权值高,优先级也高
    但对于小根堆,权值低,优先级才高,刚好相反
    下面用小根堆来解决解哈夫曼编码,其实就改几个符号(大于改小于号,大家可以对比一下)

    2.先说什么是哈夫曼编码?


    比如说AABCDCA这个字符串,我怎么编码呢
    先统计个字符的出现次数(下面我把次数说成权值吧
    A C D
    3 1 2 1
    然后构成一颗哈夫曼树:就权值最小的两个加起来,将加起来的权值作为他们两的父亲结点,把那两个剔除,将父亲结点加进来然后再把最小的加起来,作为父亲结点,直到最后只剩一个父亲结点(哎这里不怎么会说,直接看我制作的图吧)

    那么4个字母就可以编码成
    A:0
    B:110
    C:10
    D:111
    这样就将数据压缩了,本来我们每个用8个bit的二进制表示。

    不过下面我们解决的是带权路径长度,就是取每个结点的权值乘以到根结点的长度(就是到根结点有多少条线),再将每个结点的计算记过加起来
    以上面的例子为例:WPL = 1*3 +1 *3 + 2*2 + 3*1 = 13 ,
    还有一种计算方法,就是把哈夫曼树除了根结点以外的索引权值加起来
    我们从最低加起
    WPL =  1 + 1  + 2 + 2 + 4 + 3 = 13
    下面就是用第二中方法,看看编程实现,看看结果对不

    3.解决哈夫曼编码问题之带权路径长度

    #include<iostream>
    using namespace std;
    class Heap {
    private:
        int *data, size;
    public:
        Heap(int length_input) {
            data = new int[length_input];
            size = 0;
        }
        ~Heap() {
            delete[] data;
        }
        void push(int value) {
            data[size] = value;
            int current = size;
            int father = (current - 1) / 2;
            while (data[current] < data[father]) {
                swap(data[current], data[father]);
                current = father;
                father = (current - 1) / 2;
            }
            size++;
        }
        int top() {
             return data[0];
        }
        void update(int pos, int n) {
            int lchild = 2 * pos + 1, rchild = 2 * pos + 2;
            int min_value = pos;
            if (lchild < n && data[lchild] < data[min_value]) {
                min_value = lchild;
            }
            if (rchild < n && data[rchild] < data[min_value]) {
                min_value = rchild;
            }
            if (min_value != pos) {
                swap(data[pos], data[min_value]);
                update(min_value, n);
            }
        }
        void pop() {
            swap(data[0], data[size - 1]);
            size--;
            update(0, size);
        }
        int heap_size() {
            return size;
        }
    };
    int main() {
    	//n:一共有n个数,value代表权值(在哈弗曼编码里代表每个字符出啊先的次数)
    	//ans:用于保存带权路径长度
    	int n, value, ans = 0;
    	cin>>n;
    	Heap heap(n);
    	for (int i = 1; i <= n; i++) {
    		cin>>value;
    		heap.push(value);
    	}
    	//因为我们的带权路径长度是不用算根结点的,所以下面的循环就是剩最后一个点时结束
    	//只有一个结点就直接它的权值就是带权路径长度
    	if (n == 1) {
    		ans = ans + heap.top();
    	}
    	while (heap.heap_size() > 1) {
    		//因为上面的数据结构是小根堆(即对于每个结点,它的权值小于以它为根构成的子树的所以的结点,注意这里不是之和)
    		//a,b都是从堆顶获取的权值,获取完就删除该结点,所以a,b就是堆里面权值最小的两个结点
    		int a = heap.top();
    		heap.pop();
    		int b = heap.top();
    		heap.pop();
    		//将a,b的和累加带权路径长度中
    		ans = ans + a + b;
    		//最后将a,b的和插入到堆中
    		heap.push(a+b);
    	}
    	cout<<ans<<endl;
        return 0;
    }
    

    4.运行结果



    可以看到跟我们上面的手算的结果是一样的

  • 相关阅读:
    shell流程控制
    shell编程变量介绍与表达式详解
    shell编程简介
    反向代理与负载均衡
    存储库之mongodb,redis,mysql
    请求库之requests,selenium
    解析库之re、beautifulsoup、pyquery
    爬虫基本原理
    Django 函数和方法的区别
    Django 知识补漏单例模式
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286551.html
Copyright © 2011-2022 走看看