哈夫曼编码及文件操作

#include<iostream>
#include<string>
#include<vector>
#include<fstream>
using namespace std;
//定义字符以及权值
struct binaChar{
    char value;
    int width;
};
//定义储存哈夫曼树节点
struct node {
    char value;
    int width;
    struct node* rchild;
    struct node* lchild;
};
//统计字符,赋予权值
void getCharArray(string str,vector<binaChar> & vec) {
    for (int i = 0; i <str.size(); i++) {
        bool isExist = false;
        for (int j = 0; j < vec.size(); j++) {
            if (str[i] == vec[j].value) {
                vec[j].width++;
                isExist = true;
            }
        }
        if (!isExist) {
            binaChar bc;
            bc.value = str[i];
            bc.width = 1;
            vec.push_back(bc);
        }
    }
}
//交换三个变量的值
void swap(binaChar& a, binaChar&b) {
    binaChar temp = a;
    a = b;
    b = temp;
}
//快速排序,方便查找较小的两个权值
int quick(int begin, int end, vector<binaChar>& array) {
    int i = begin, j = end;
    binaChar pivot = array[begin];
    while (i < j) {
        while (array[j].width >= pivot.width && j > i) j--;
        while (array[i].width <= pivot.width && j > i) i++;
        swap(array[j], array[i]);
    }
    array[begin]= array[i];
    array[i]=pivot;
    return i;
}
void quickSort(int begin, int end, vector<binaChar>& array) {
    if (begin < end) {
        int mid =quick(begin, end, array);
        quickSort(begin, mid - 1, array);
        quickSort(mid + 1, end, array);
    }
}

//生成哈夫曼树
void getHuffmanTree(vector<binaChar> bc, struct node*& head) {
    vector<node*> tree;
    for (int i = 0; i < bc.size(); i++) {
        node* n = new node();
        n->value = bc[i].value;
        n->width = bc[i].width;
        n->lchild = n->rchild = NULL;
        tree.push_back(n);
    }
    while (tree.size() > 1) {
        int min1 = 0, min2 = 1;//经过排序,已经确定0,1位置的字符权值最小。
        node* p = new node();
        p->value =NULL;
        p->width = tree[min1]->width+tree[min2]->width;
        p->lchild = tree[min1];
        p->rchild = tree[min2];
        tree.erase(tree.begin());//移除已经合并的节点:0,1
        tree.erase(tree.begin());
        //在指定位置插入新节点
        bool isInsert = false;
        for (int i = 0; i <tree.size(); i++) {
            if (p->width<tree[i]->width) {
                tree.insert(tree.begin()+i, p); 
                isInsert = true;
                break;
            }
        }
        //如果新节点权值最大,保证节点被插在最后
        if (!isInsert) tree.push_back(p);//
    }
    head=tree[0];//返回构造完成的树
}

void getString(string& text) {
    ifstream infile;
    infile.open("D:\\data\\infile\\text.txt", ios::out | ios::in);
    if (!infile) {
        cout << "待加密文件读取失败!" << endl;
        return;
    }
    getline(infile, text, '\n');
    cout<<"字符串写入成功!"<<endl;
    infile.close();
}
void Tran(node* root,string str, string& code,char ch) {
    if (root == NULL) return;
    Tran(root->lchild, str + '0',code,ch);
    Tran(root->rchild, str + '1',code,ch);
    if (root->value== ch) {
        code = str;
        return;
    }
}
//加密
void getCodeFile(struct node* root, vector<binaChar> bc) {
    ifstream infile;
    infile.open("D:\\data\\infile\\text.txt", ios::out | ios::in);
    if (!infile) {
        cout << "待加密文件读取失败!" << endl;
        return;
    }
    string text;
    getline(infile,text,'\n');
    infile.close();
    ofstream outfile;
    outfile.open("D:\\data\\infile\\coding.txt", ios::out | ios::in);
    if (!outfile) {
        cout << "加密文件读取失败!" << endl;
        return;
    }

    for (int i = 0; i < text.size(); i++) {
        node* p = root;
        string str,temp;
        Tran(p,temp, str, text[i]);
        outfile <<str;
    }
    cout << "加密文件写入成功!" << endl;
    outfile.close();
}
//解密
char reTran(node* root,string str,int &i) {
    while (true) {
        if (str[i] == '0') root=root->lchild;
        if (str[i] == '1') root=root->rchild;
        if (root->value != NULL) return root->value;
        i++;
    }
}
void decodingFile(struct node* root) {
    ifstream infile;
    infile.open("D:\\data\\infile\\coding.txt", ios::out | ios::in);
    if (!infile) {
        cout << "加密文件写入失败!" << endl;
        return;
    }
    string str;
    infile >> str;
    infile.close();
    ofstream outfile;
    outfile.open("D:\\data\\infile\\decoding.txt", ios::out | ios::in);
    if (!outfile) {
        cout<<"解密文件读取失败!"<<endl;
        return;
    }
    for (int i = 0; i < str.size(); i++) {
        node* p =root;
        char ch=reTran(root, str, i);
        outfile <<ch;
    }
    cout << "解密文件写入成功!" << endl;
    outfile.close();
}

int main()
{
    string str;
    getString(str);
    node* head=new node();
    vector<binaChar> vec;
    getCharArray(str, vec);
    quickSort(0, vec.size()-1, vec);
    getHuffmanTree(vec,head);
    getCodeFile(head,vec);
    decodingFile(head);
}

哈夫曼编码能实现文件的压缩,但是由于没有将01串转比特流写入,实际上得到的文件占据更大的空间。所以,涉及到的文件均是为了方便查看。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值