Huffman 编码

数据结构作业
算法思路:每次找到两个最小的,然后合并,直到只剩下一个。
实现过程:
1. 实现MinHeap(或者可以直接用priority_queue)
2. 编码: 用队列层次遍历整棵树,同时记录每个节点的位置。
非叶子结点的code记作‘0’,叶子结点的code为本身。
把位置+1,这样树根就是1,每一行的bits就是该行数,
并且该点的编码就是这个位置去掉2进制下的首位。

MIN_HEAP.h

#pragma once
#ifndef MIN_HEAP
#define MIN_HEAP
#include <iostream> 
using namespace std;

static int counter = 0;     //前两组打印时按5层打印,看起来紧凑一些......
const int layer = 6;        //如果是5,第3组测试会溢出
const int MAXN = 1 << layer;
class Node;
class MyStack {
private:
    Node* stk[MAXN];
    int size;
public:
    MyStack() :size(0) {}
    void push(Node* v) { stk[size++] = v; }
    Node* pop() { return stk[--size]; }
    bool empty() { return size > 0; }
};
class MyQueue {
private:
    pair<Node*, int> q[MAXN];
    //first point to the first pos, while last point to the next pos of the last elemet.
    //that is to say, it only allows the size ranging from 0~(n-1)
    int first, last;
public:
    MyQueue() : first(0), last(0) {}
    int length()const { return (last - first + MAXN) % MAXN; }
    void push(pair<Node*, int> v) { q[last++] = v; last %= MAXN; }
    pair<Node*, int> front() { return q[first]; }
    void pop() { first++; first %= MAXN; }
    bool empty() { return length() == 0; }
};

class Node {
    friend class MinHeap;
    friend ostream& operator<<(ostream& out, const Node& node);
private:
    double frequence;
    char code;
    Node* left;
    Node* right;
public:
    Node(double _frequence, char _code, Node* _left = nullptr, Node* _right = nullptr) :
        frequence(_frequence), code(_code), left(_left), right(_right) {}
    bool operator<(const Node& a) { return frequence < a.frequence; }
    bool operator>(const Node& a) { return frequence > a.frequence; }
    Node* operator+(Node& a) {//let left be smaller
        if (frequence < a.frequence)
            return new Node(frequence + a.frequence, 0, this, &a);
        else return new Node(frequence + a.frequence, 0, &a, this);
    }
    void getCode(char** hcode, char codes[], double weights[], int size);
};

ostream& operator<<(ostream& out, const Node& node) {
    out << node.code << ":" << node.frequence << "  ";
    return out;
}

void Node::getCode(char** hcode, char codes[], double weights[], int size) {
    //utilize queue to
    char cd[MAXN];
    for (int i = 0; i < MAXN; ++i)cd[i] = 1;
    MyQueue q;
    q.push(make_pair(this, 0));
    cout << "Huffman code:" << endl;
    while (!q.empty()) {
        pair<Node*, int> node = q.front();
        q.pop();
        //if it's a leaf, store code and num
        //Then create Huffman code
        if (node.first->code != 0) {
            char c = node.first->code;
            int pos = node.second;
            cd[node.second] = c;
            //find the num of hcodes in codes
            int num = 0;
            for (; num < size; ++num)
                if (codes[num] == c)
                    break;
            //find the bits of corresponding character
            int _pos = pos + 1;//find the number of bits, cuz same level has same bits
            int bit = -1;
            while (_pos) {
                ++bit;
                _pos >>= 1;
            }
            hcode[num] = new char[bit];
            ++pos;
            //create Huffman code
            for (int i = bit - 1; i >= 0; --i) {
                hcode[num][i] = (pos & 1) ? '1' : '0';
                pos >>= 1;
            }
            //print Huffman code
            cout << codes[num] << ": ";
            for (int i = 0; i < bit; ++i)
                cout << hcode[num][i];
            cout << endl;
        }
        else cd[node.second] = '0';//output 0 if it's not a leaf
        if (node.first->left != nullptr)
            q.push(make_pair(node.first->left, 2 * node.second + 1));
        if (node.first->right != nullptr)
            q.push(make_pair(node.first->right, 2 * node.second + 2));
    }
    //print Huffman Tree
    cout << endl;
    int cur = 0;
    ////////////////////////////////////前两次测试按layer=5
    int _layer = layer;
    if (counter < 3)_layer = 5;
    ////////////////////////////////////前两次测试按layer=5
    for (int i = 0; i < _layer; ++i) {
        for (int j = 0; j < (1 << (_layer - i - 1)); ++j)
            cout << " ";
        for (int j = 1; j <= 1 << i; ++j) {
            char val = cd[cur++];
            if (val == 1)
                cout << " ";
            else cout << val;
            for (int k = 0; k < (1 << (_layer - i)) - 1; ++k)
                cout << " ";
        }
        cout << endl;
    }
    //delete Huffman Tree
    MyStack stk;
    stk.push(this);
    while (!stk.empty()) {
        Node* node = stk.pop();
        if (node->right != nullptr)
            stk.push(node->right);
        if (node->left != nullptr)
            stk.push(node->left);
        delete node;
    }
}

class MinHeap {
private:
    Node *heap[MAXN];
    int size;
public:
    MinHeap() :size(0) {}
    int getSize() { return size; }
    void construct(char codes[], double weights[], int _size);
    void insert(Node& node);
    Node* remove_top();
};

void MinHeap::construct(char codes[], double weights[], int _size) {
    size = _size;
    for (int i = 1; i <= _size; ++i)
        heap[i] = new Node{ weights[i - 1],codes[i - 1] };
    //handle from the last father
    for (int _cur = _size / 2; _cur > 0; --_cur) {
        int cur = _cur;
        int son = 2 * cur;
        while (son <= _size) {
            //able to step down
            if (*heap[cur] > *heap[son] ||
                (son + 1 <= _size && *heap[cur] > *heap[son + 1])) {
                //no right
                if (son + 1 > _size) {
                    swap(heap[cur], heap[son]);
                    cur = son;
                    son *= 2;
                    continue;
                }
                //compare the two child
                if (*heap[son] < *heap[son + 1]) {
                    swap(heap[cur], heap[son]);
                    cur = son;
                    son *= 2;
                    continue;
                }
                else {
                    swap(heap[cur], heap[son + 1]);
                    cur = son + 1;
                    son = 2 * cur;
                }
            }
            else break;
        }
    }
}

void MinHeap::insert(Node& node) {
    ++size;
    heap[size] = &node;
    int cur = size;
    while (cur > 1 && *heap[cur] < *heap[cur / 2]) {
        swap(heap[cur], heap[cur / 2]);
        cur /= 2;
    }
}

Node* MinHeap::remove_top() {
    swap(heap[1], heap[size]);
    //pretend to delete
    --size;
    int cur = 1;
    int son = 2 * cur;
    while (son <= size) {
        //able to step down
        if (*heap[cur] > *heap[son] ||
            (son + 1 <= size && *heap[cur] > *heap[son + 1])) {
            //no right
            if (son + 1 > size) {
                swap(heap[cur], heap[son]);
                cur = son;
                son *= 2;
                continue;
            }
            //compare the two child
            if (*heap[son] < *heap[son + 1]) {
                swap(heap[cur], heap[son]);
                cur = son;
                son *= 2;
                continue;
            }
            else {
                swap(heap[cur], heap[son + 1]);
                cur = son + 1;
                son = 2 * cur;
            }
        }
        else break;
    }
    return heap[size + 1];
}
#endif // !1

Huffman.cpp

#include "MIN_HEAP.h"

void HuffmanCode(char codes[], double weights[], int size);
int main()
{
    cout << "Test1:" << endl; counter++;
    char codes1[5] = { 'a', 'b', 'c', 'd', 'e' };
    double weights1[5] = { 0.42, 0.19, 0.07, 0.15, 0.17 };
    HuffmanCode(codes1, weights1, 5);
    cout << "\n\n" << endl;
    cout << "Test2:" << endl; counter++;
    char codes2[6] = { 'a', 'b', 'c', 'd', 'e', 'f' };
    double weights2[6] = { 0.07, 0.24, 0.16, 0.30, 0.14, 0.09 };
    HuffmanCode(codes2, weights2, 6);
    cout << "\n\n" << endl;
    cout << "Test3:" << endl; counter++;
    char codes3[10] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
    double weights3[10] = { 0.07, 0.24, 0.06, 0.12, 0.02, 0.09, 0.10, 0.11, 0.14, 0.05 };
    HuffmanCode(codes3, weights3, 10);

    cout << endl;
    system("pause");
    return 0;
}

void HuffmanCode(char codes[], double weights[], int size) {
    cout << "codes and weights:" << endl;
    for (int i = 0; i < size; ++i)
        cout << codes[i] << ": " << weights[i] << endl;
    cout << endl;
    MinHeap hp;
    hp.construct(codes, weights, size);
    while (hp.getSize() != 1) {
        Node *min1 = hp.remove_top();
        Node *min2 = hp.remove_top();
        Node* add_result = (*min1) + (*min2);
        hp.insert(*add_result);
    }
    Node *root = hp.remove_top();
    char** hcodes = new char*[size];
    root->getCode(hcodes, codes, weights, size);//Huffman Tree has been released
    for (int i = 0; i < size; ++i)
        delete[] hcodes[i];
    delete[] hcodes;
}

三组测试数据如下:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值