哈夫曼树的建立和哈夫曼编码的构造

给定n个权值作为n的叶子结点,构造一颗二叉树,若带权路径长度达到最小,成这样的二叉树为最有二叉树,也称为哈夫曼树 。哈夫曼树是带全路径长度最短的树,权值较大的结点离根较近。

哈夫曼树的构造:

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。n个权值分别设为w1、w2、…、wn,则哈夫曼树的构造规则:

(1)将w1、w2、…、wn看成是有n棵树的森林(每棵树仅有一个结点);

(2)在森林中选出两个根结点的权值最小的树合并,作为一颗新树的左右子树,且新树的根结点权值为其左右子树根结点权值之和;

(3)从森林中删除选取的两棵树,并将新树加入森林;

(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_SIZE = 10;
const int MAX_ = 2 * MAX_SIZE -1;
typedef struct htnode
{
    int weight;
    int parent, lchild, rchild;
}htnode;
typedef struct htcode
{
    char data;
    int weight;
    char code[MAX_SIZE];
}htcode;
void init(htcode hc[], int n)
{
    cout << "char" << endl;
    for(int i=1;i<=n;i++)
        cin >> hc[i].data;
    cout << "weight" << endl;
    for(int i=1;i<=n;i++)
        cin >> hc[i].weight;
}
void select(htnode ht[], int j, int &a, int &b)  //寻找最小的两个
{
    int i;
    for(i=1;i<=j&&ht[i].parent != 0;i++)
        ;
    a = i;
    for(i=1;i<=j;i++)
        if(ht[i].parent == 0 && ht[i].weight < ht[a].weight)
            a = i;
    for(i = 1;i<=j;i++)
        if(ht[i].parent == 0 && i!=a)
            break;
    b = i;
    for(int i=1;i<=j;i++)
        if(ht[i].parent == 0 && i!=a && ht[i].weight < ht[b].weight)
            b = i;

}
void huffman(htnode ht[], htcode hc[], int n)
{
    char cd[MAX_SIZE];
    int m = 2*n-1, s1, s2;
    for(int i=1; i<=m;i++)
    {
        if(i <= n)
            ht[i].weight = hc[i].weight;
        ht[i].parent = ht[i].lchild = ht[i].rchild = 0;
    }
    for(int i=n+1;i<=m;i++)
    {
        select(ht, i-1, s1, s2);
        cout << s1 << "  " << s2 << endl;
//        cout << ht[s1].weight << "  " << ht[s2].weight << endl;
        ht[s1].parent = i;
        ht[s2].parent = i;
        ht[i].lchild = s1;
        ht[i].rchild = s2;
        ht[i].weight = ht[s1].weight + ht[s2].weight;
        cout << ht[i].weight << endl;
    }


//哈夫曼树编码方法1
    cd[n - 1] = '\0';
    for(int i=1;i<=n;i++)
    {
        int start = n-1;
        for(int j=i, f = ht[i].parent; f ; j = f, f = ht[f].parent )
        {
            if(ht[f].lchild == j)
                cd[--start] = '0';
            else
                cd[--start] = '1';
        }
        strcpy(hc[i].code, &cd[start]);
    }

//哈夫曼树编码方法2
    // 该方法从根出发,递归遍历哈夫曼树,求得编码。标记0,1,2含义如下:
    //0:搜到一个满足条件的新结点
    //1:当前正在搜其儿子结点的结点,还没有回溯回来
    //2:不满足条件或者儿子结点已全部搜完,已经回溯回来,则回溯到其父结点
    //注意:当流程走到一个结点后,其标记立即变为下一状态,
//    int p, len = 0;
//    for(int i=1;i<=m;i++)
//        if(ht[i].parent == 0)
//        {
//            p = i;
//            break;
//        }
//    for(int i=1;i<=m;i++)
//        ht[i].weight = 0;
//    while(p)
//    {
//        if(ht[p].weight == 0)
//        {
//            ht[p].weight = 1;
//            if(ht[p].lchild != 0)
//            {
//                p = ht[p].lchild;
//                cd[len++] = '0';
//            }
//        }
//        else if(ht[p].weight == 1)
//        {
//            ht[p].weight = 2;
//            if(ht[p].rchild !=0)
//            {
//                p = ht[p].rchild;
//                cd[len++] = '1';
//            }
//            else if(ht[p].rchild == 0)
//            {
//                cd[len] = '\0';
//                strcpy(hc[p].code, cd);
//            }
//        }
//        else
//        {
//            ht[p].weight = 0;
//            p = ht[p].parent;
//            --len;
//        }
//    }
}
void huffmandecode(htnode ht[], htcode hc[], char code[], int n)
{
    char *ch = code;
    int m = 0;
    for(int i=1;i<=2*n-1;i++)
        if(ht[i].parent == 0)
        {
            m = i;
            break;
        }
   // cout << hc[m].weight << endl;
    int i;
    while(*ch != '\0')
    {
        for(i=m; ht[i].lchild !=0 && ht[i].rchild!=0;)
        {
            if(*ch == '0')
                i = ht[i].lchild;
            else if(*ch == '1')
                i = ht[i].rchild;
            ch++;
        }
        cout << hc[i].data << " ";
    }
    cout << endl;
}
int main()
{
    //freopen("1.txt", "r", stdin);
    htnode ht[MAX_ + 1];
    htcode hc[MAX_SIZE + 1];
    int n;
    cin >> n;
    init(hc, n);
    huffman(ht, hc, n);
    for(int i =1;i<=n;i++)
        cout << hc[i].data << " " << hc[i].code << endl;
    char code[43] = "011001110101101110010100011111001001100111";
//    for(int i=0;i<=42;i++)
//        cout << code[i] << " ";
    //getchar();
    //scanf("%s", &code);
    huffmandecode(ht, hc, code, n);


    return 0;
}



你可能感兴趣的:(编码,哈夫曼树,哈夫曼编码,typedef)