数据结构课程设计——Huffman Coding(简单压缩)

版权声明:没人会转的( ̄▽ ̄) https://blog.csdn.net/j2_o2/article/details/86256311

须知 课程设计作业,bug较多,懒得擦屁股

课程设计主要熟悉Huffman编码之类,瞎搞的 简单压缩 增大程序。

首先不能压缩文件夹,懒得搞了。。

运行程序输入1或2之后以 一个 换行或者空格 当作分隔符。

测试了几个视频,图片虽然无损但是效果不咋滴,还是某些字符占比高的文本文件效果比较好。

代码:


主函数

#include "huffmantree.h"
#include "File_operate.h"
#include <bits/stdc++.h>
using namespace std;

int main()
{
    string filename, op;
    while(1)
    {
        system("cls");
        puts("输入1压缩\n输入2解压\n输入其他结束");
        cin >> op;
        getchar();
        if(op == "1")
        {
            puts("拖入文件或者输入目标路径");
            getline(cin, filename);
            if(filename[0] == '"') filename = filename.substr(1, filename.size()-2);
            File_operate *it;
            it = new File_operate(filename);
            if(it -> compression()) puts("压缩成功");
            else puts("压缩失败");
            delete(it);
            system("pause");
        }
        else if(op == "2")
        {
            puts("拖入文件或者输入目标路径");
            getline(cin, filename);
            if(filename[0] == '"') filename = filename.substr(1, filename.size()-2);
            File_operate *it;
            it = new File_operate(filename);
            if(it -> decompression()) puts("解压成功");
            else puts("解压失败");
            delete(it);
            system("pause");
        }
        else break;
    }
    return 0;
}

huffmantree.h

#define ONCE
#ifndef HUFFMANTREE_H_INCLUDED
#define HUFFMANTREE_H_INCLUDED

#include <unordered_map>
#include <algorithm>
#include <queue>
#include <string>
using std::unordered_map;
using std::priority_queue;
using std::string;

struct Node
{
    int weight, pos;
    int fa, lson, rson;
    Node() = default;
    Node(int a, int b, int c, int d, int e):weight(a),pos(b),fa(c),lson(d),rson(e){}
    bool operator < (const Node &_) const
    {
        return weight == _.weight ? pos > _.pos : weight > _.weight;
    }
};

struct Denode
{
    int id;
    int lson, rson;
    Denode()
    {
        id = -1;
        lson = rson = 0;
    }
};

class HuffmanTree
{
public:
    void Creat(unordered_map<int, int> &);
    string Translate(const int &);
// map[]运算会在索引项不存在的时候自动创建一个对象,所以函数不能加const,傻逼BUG
protected:
    int n;
    unordered_map<int, string> Hash;
    priority_queue<Node> Queue;
    Node *HT;
};

#endif // HUFFMANTREE_H_INCLUDED

huffmantree.cpp

#include "huffmantree.h"

string HuffmanTree::Translate(const int &wtf)
{
    return Hash[wtf];
}

void HuffmanTree::Creat(unordered_map<int, int> &cnt)
{
    n = cnt.size();
    if(n <= 1) return;
    int m = (n<<1)-1, index = 0;
    HT = new Node[m];
    for(int i = 0; i < m; ++i) HT[i] = Node(0,i,0,0,0);
    for(auto tmp:cnt)
    {
        HT[index].weight = tmp.second;
        Queue.push(HT[index++]);
    }
    Node x, y;
    for(int i = n; i < m; ++i)
    {
        x = Queue.top(); Queue.pop();
        y = Queue.top(); Queue.pop();
        HT[x.pos].fa = i;
        HT[y.pos].fa = i;
        HT[i].lson = x.pos;
        HT[i].rson = y.pos;
        HT[i].weight = x.weight+y.weight;
        Queue.push(HT[i]);
    }
    Hash.clear();
    auto iter = cnt.begin();
    for(int i = 0; i < n; ++i, ++iter)
    {
        string tmp = "";
        for(int la = i, f = HT[i].fa; f; la = f, f = HT[f].fa)
        {
            if(HT[f].lson == la) tmp += '0';
            else tmp += '1';
        }
        reverse(tmp.begin(),tmp.end());
        Hash[iter->first] = tmp;
    }
    delete []HT;
}

File_operate.h

#define ONCE
#ifndef FILE_OPERATE_H_INCLUDED
#define FILE_OPERATE_H_INCLUDED

#include "huffmantree.h"
#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <ostream>
#include <fstream>
#include <string>
#include <string>
using std::iostream;
using std::unordered_map;
using std::ofstream;
using std::ifstream;
using std::string;
using std::ios;
using std::cout;
using std::endl;
using std::string;

class File_operate
{
public:
    File_operate(string s):path(s){}
    bool Readfile(string); // 压缩读取文件字符信息
    void dataout(string, ofstream &); // 压缩输出文件信息
    bool compression(); // 压缩
    bool decompression(); // 解压
protected:
    Denode *root;
    string path;
    unordered_map<int, int> cnt; // 字符出现次数
    HuffmanTree *tree;
};

#endif // FILE_OPERATE_H_INCLUDED

File_operate.cpp

#include "File_operate.h"

// 压缩读取文件字符信息
bool File_operate::Readfile(string filename)
{
    cnt.clear();
    ifstream in_file(filename, ios::in|ios::binary);
    if(!in_file.is_open()) return 0;
    for(unsigned char ch; ch = in_file.get(), in_file; ++cnt[int(ch)]);
    ++cnt[256];
    in_file.close();
    return 1;
}

// 压缩字符
void File_operate::dataout(string filename, ofstream & out_file)
{
    ifstream in_file(filename, ios::in|ios::binary);
    unsigned char ch, outch;
    string tmp;
    char code[305];
    int head = 0, tail = 0, mod = 300, len = 0, wtf;
    while(in_file)
    {
        ch = in_file.get();
        // 255 文本结束符,每次都进来了,导致每次解压都大了一点,找了半天bug
        if(!in_file && ch == 255) break;
        tmp = tree->Translate(int(ch));
        for(int i = 0; i < tmp.size(); ++i)
        {
            code[tail] = tmp[i];
            tail = (tail+1)%mod;
            ++len;
        }
        for(wtf = 0; wtf || len >= 8; --len)
        {
            if(!wtf) outch = 0;
            outch <<= 1;
            if(code[head] == '1') outch |= 1;
            wtf = (wtf+1)%8;
            head = (head+1)%mod;
            if(!wtf) out_file << outch;
        }
    }
    in_file.close();

    tmp = tree->Translate(256);
    for(int i = 0; i < tmp.size(); ++i)
    {
        code[tail] = tmp[i];
        tail = (tail+1)%mod;
        ++len;
    }
    for(wtf = 0; len > 0 || wtf; --len)
    {
        if(!wtf) outch = 0;
        outch <<= 1;
        if(len > 0 && code[head] == '1') outch |= 1;
        wtf = (wtf+1)%8;
        head = (head+1)%mod;
        if(!wtf) out_file << outch;
    }
}

// 压缩 将原文件名,字符和编码,以及压缩后的字符,打印到输出文件里
bool File_operate::compression()
{
    if(!Readfile(path)) return 0;
    string name, newpath, shortname;
    int flag = 0, check = 0, index = path.size()-1;
    for(int i = path.size()-1; ~i; --i)
    {
        if(path[i] == '\\') flag = 1;
        if(path[i] == '.' && !check) check = 1, index = i;
        if(flag) newpath += path[i];
    }
    for(int i = index-1; ~i && path[i] != '\\'; --i) shortname += path[i];
    for(int i = index; i < path.size(); ++i) name += path[i];

    reverse(newpath.begin(), newpath.end());
    reverse(shortname.begin(), shortname.end());
    if(name == ".wzy") return 0;
    tree = new HuffmanTree();
    tree -> Creat(cnt);

    ofstream out_file(newpath+shortname+".wzy",ios::out|ios::binary);
    if(!out_file.is_open()) return 0;
    out_file << name << "\\ ";
    out_file << cnt.size() << " ";
    for(auto tmp:cnt)
    {
        out_file << tmp.first << " " << (tree -> Translate(tmp.first)) << " ";
    }
    dataout(path, out_file);
    delete tree;
    out_file.close();
    return 1;
}

/***压缩***/
/***解压***/

bool File_operate::decompression()
{
    // 确保文件正确,找到输出格式
    if(path.size() < 4) return 0;

    string newpath, wzy;
    wzy = path.substr(path.size()-4,4);
    if(wzy != ".wzy") return 0;

    newpath = path.substr(0,path.size()-4);
    ifstream in_file(path, ios::in|ios::binary);
    in_file >> wzy;
    newpath += wzy.substr(0,wzy.size()-1);
    ofstream out_file(newpath,ios::out|ios::binary);

    // 建树
    string code;
    int n;
    in_file >> n;
    root = new Denode[n<<1];
    for(int i = 0, index = 1, id; i < n; ++i)
    {
        in_file >> id >> code;
        int now = 0;
        for(int i = 0; i < code.size(); ++i)
        {
            if(code[i] == '0')
            {
                if(root[now].lson == 0)
                    root[now].lson = index++;
                now = root[now].lson;
            }
            else
            {
                if(root[now].rson == 0)
                    root[now].rson = index++;
                now = root[now].rson;
            }
        }
        root[now].id = id;
    }
    int now = 0, flag = 0;
    int ch = in_file.get(); // 文件指针应该还指向空格
    // 输出原数据
    while(in_file)
    {
        ch = in_file.get();
        for(int i = 7; ~i; --i)
        {
            if((1<<i)&ch) now = root[now].rson;
            else now = root[now].lson;
            if(~root[now].id)
            {
                if(root[now].id == 256)
                {
                    flag = 1;
                    break;
                }
                out_file << (unsigned char)(root[now].id);
                now = 0;
            }
        }
        if(flag) break;
    }
    delete []root;
    in_file.close();
    out_file.close();
}

猜你喜欢

转载自blog.csdn.net/j2_o2/article/details/86256311
今日推荐