haffman树

#include<iostream>
#include<string>
using namespace std;

int ABC[104] = { 0 };  //每个字符    权重初始为0   前大后小
int n = 0;                
bool  flag[104] = { false };  //已经处理过  初始false为未处理
char text[10000];     //用text数组将a.txt里面的内容存储 
char txt[10000];      //尽可能的大   否则二进制编码越界
int haffman[52][50] = {-1};
FILE *p;
int h = 0;   //作为全局变量  作用于反编码过程 记录数组下标

struct node
{
    int data;    //仍然以数组的下标表示 字符abc
    int  rchild = -1;  //右子树
    int  lchild = -1;  //左子树
}nodetree[103];

//寻找数组中最小的值  返回下标
int findmin()
{
    int i = 0;
    int j = 0;
    int weight = 0;
    while (!flag[i]) i++;
    j = i;
    weight = ABC[i];
    for (; i < 104; i++)
    {
        if (flag[i] == true && weight > ABC[i])  //找出字幕出现次数大于0   且最小的
        {
            weight = ABC[i];
            j = i;
        }
    }
    flag[j] = false;     //找出的最小值下次不再参与
    return j;
}

void creat()
{
    for (int i = 0; i < 52+n-1; i++)
    {
        nodetree[i].data = i;
    }
    //cout << "最小值排序 :" << endl;
    for (int i = 52; i <52+n-1; i++)
    {
        int a = findmin();
        int  b = findmin();
        //cout << a <<" "<< ABC[a] << endl << b <<" "<<ABC[b] << endl;
        //cout << char(a + 97-26) << endl;
        //cout << char(b + 97-26) << endl;
        nodetree[i].lchild = a;
        nodetree[i].rchild = b;
        ABC[i] = ABC[a] + ABC[b];
        flag[i] = true;
    }
    cout << endl;
    //for (int i = 52; i < 52 + n - 1; i++)
    //{
    //    cout << nodetree[i].data << " " << nodetree[i].lchild << "," << nodetree[i].rchild << endl;
    //}
}


int asc[50];     //用以暂时存放haffman编码
int j = -1;    //j不会变化
void visittree(node  tree)
{
    if (tree.lchild == -1 && tree.rchild == -1)    //叶子节点储存字母
    {
        int i = 0; 
        
        if (tree.data < 26)
            cout << char(65 + tree.data) << "编码:";
        else
            cout << char(tree.data + 97 - 26) << "编码:";

        while (asc[i] != -1)
        {
            haffman[tree.data][i] = asc[i];
            cout << asc[i++];
        }
        cout << endl  ;
        return;
    }
    
    j++;
    asc[j] = 0;
    visittree(nodetree[tree.lchild]);
    asc[j] = 1;
    visittree(nodetree[tree.rchild]);
    asc[j] = -1;
    j--;
    
}

//输入根节点与数组下标  返回数组下标   haffman反编码
int decode(node tree,int i)
{
    if (tree.lchild == -1 && tree.rchild == -1)
    {    
        if(tree.data<26) 
            fprintf(p, "%c", tree.data +65);
        else 
            fprintf(p, "%c", tree.data + 97 - 26);
        return h;
    }
    h++;
    if (text[i] == '0')
        decode(nodetree[tree.lchild],i+1);
    else
        decode(nodetree[tree.rchild],i+1);
}

int main()
{
    //进行初始化  
    memset(flag, false, sizeof(flag));   
    memset(asc, -1, sizeof(asc));
    memset(haffman, -1, sizeof(haffman));
    

    //读取已存在的文件a.txt  并把文件内容放到text数组与txt数组中  方便操作
    
    char ch;
    int i = 0;
    p = fopen("E:\\a.txt", "r");
    if (p == NULL)
    {
        printf("failed to open file. ");
        exit(1);
    }
    cout << "原文中含有的英文字母是:" << endl;
    while ((ch = getc(p)) != EOF)
    {
        if (ch >= 65 && ch <= 90||ch>=97&&ch<=122)
        {
            txt[i] = ch;
            text[i++] = ch;
            cout << ch;
        }
    }
    //text[i] = '\0';
    //txt[i] = '\0';
    fclose(p);


    //输出文件中a-z,A—Z的出现的次数  以及总共出现的字母数
    cout << endl;
    i = 0;
    while (text[i] != '\0')//将字mu出现的次数记录作为权值写到数组ABC
    {
        if (text[i] <= 90)
            ABC[text[i++] - 65]++;
        else
            ABC[text[i++] - 97 + 26]++;
    }
    for (i = 0; i < 26; i++)
    {
        cout << "字母:" << char(i + 65) << "次数:" << ABC[i] << endl;
    }
    for (; i < 52; i++)
    {
        cout << "字母:" << char(i + 97-26) << "次数:" << ABC[i] << endl;
    }
    for (i = 0; i < 52; i++)
    {
        if (ABC[i]!=0)
        {
            n++;
            flag[i] = true;
        }
    }
    cout <<endl<< "总共的字母数量是n:" << n << endl;

    //创建haffman树  nodetree[n-2+52]作为根节点   
    //visittree函数将遍历所有叶子节点 并把得到的haffman编码写入二维数组haffman中
    creat();
    visittree(nodetree[n - 2+52]);
    //输出字母的haffman编码
    cout << endl << endl << endl;
    for (i = 0,j=0; i < 52; i++)
    {
        if (ABC[i] != 0)
            if (i < 26)
            {
                cout << char(65 + i) << "编码:";
                while (haffman[i][j] != -1)
                    cout << haffman[i][j++];
                cout << endl;
            }
            else
            {
                cout << char(i + 97-26) << "编码:";
                while (haffman[i][j] != -1)
                    cout << haffman[i][j++];
                cout << endl;
            }
        j = 0;
    }

    //创建b.txt  将text数组中的字母编码后写入
    i = 0;
    p = fopen("E:\\b.txt", "w");
    while ((ch = text[i++])!='\0')
    {
        if (ch < 91)
        {
            j = 0;
            while (haffman[ch - 65][j] != -1)
                fprintf(p, "%d", haffman[ch - 65][j++]);
        }
        else
        {
            j = 0;
            while (haffman[ch - 97+26][j] != -1)
                fprintf(p, "%d", haffman[ch - 97+26][j++]);
        }
    }
    fclose(p);
    
    //输出b.txt中的内容 并存到text数组中
    p = fopen("E:\\b.txt", "r");
    fscanf(p, "%s", text);
    printf("b.txt: %s\n", text);
    fclose(p);

    //创建c.txt 对text进行反编码写c.txt   
    p = fopen("E:\\c.txt", "w");
    while (text[h] != '\0')
    {
        decode(nodetree[52 + n - 2], h);    
    }
    fclose(p);
    cout << endl;

    //输出c.txt文件里面的内容 对比a.txt
    p = fopen("E:\\c.txt", "r");
    fscanf(p, "%s", text);
    printf("c.txt: %s\n", text);
    fclose(p);


    cout << endl;
    printf("a.txt: %s\n", txt);
    cout << endl;

    //比较a.txt与c.txt的内容
    if (strcmp(text, txt) == 0)
        cout << "a.txt与c.txt相等,编码成功" << endl;
    else
        cout << "编码失败" << endl;

    getchar();
    return 0;
}

 

posted @ 2018-06-12 21:09  征包  阅读(239)  评论(0编辑  收藏  举报