哈夫曼树以及哈夫曼编码|数据结构

发布于 2021-07-10  24 次阅读


/*
       哈夫曼树

 结果带权路径长度(WPL)最小

(1) 以权值分别为W1,W2...Wn的n各结点,构成n棵二叉树T1,T2,...Tn并组成森林F={T1,T2,...Tn},其中每棵二叉树 Ti仅有一个权值为 Wi的根结点;

(2) 在F中选取两棵根结点权值最小的树作为左右子树构造一棵新二叉树,并且置新二叉树根结点权值为左右子树上根结点的权值之和(根结点的权值=左右孩子权值之和,叶结点的权值= Wi)

(3) 从F中删除这两棵二叉树,同时将新二叉树加入到F中;

(4) 重复(2)、(3)直到F中只含一棵二叉树为止,这棵二叉树就是Huffman树。



*/

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

#define NODE_NUM 16                  //叶子结点个数
#define MAXVAL 32767

//哈夫曼树的存储表示
typedef struct
{
    int weight;                     // 权值
    int parent, lchild,rchild;      // 双亲及左右孩子的下标 
}HuffmanTree;


typedef struct {                    //哈夫曼编码结构体
    int bit[8];                        //存放当前结点的哈夫曼编码
    int start;                        //bit[start]-bit[8]存放哈夫曼编码
}HCodeType;

HuffmanTree HuffNode[NODE_NUM];    //定义全局变量数组HuffNode存放哈夫曼树
HCodeType HuffCode[8];               //定义全局变量数组HuffCode存放哈夫曼编码
int n;//叶子个数

//构建哈弗曼树
void CreateHuffmanTree()
{
    int min1, min2;//两个最小权值
    int p1, p2;//两个最小权值结点的数组下标
    cout << "输入叶子结点个数" << endl;
    cin >> n;

    if (2*n>NODE_NUM)
    {
        cout << "原本预设的叶子结点个数宏不够大";
    }

    for (int i = 0; i < 2 * n-1; i++)     //HuffNode 初始化 
    {
        HuffNode[i].weight = 0;
        HuffNode[i].parent = 0;
        HuffNode[i].lchild = 0;
        HuffNode[i].rchild = 0;
    }

    cout << "输入带权结点" << endl;
    for (int i=0;i<n;i++)
    {
        cin >> HuffNode[i].weight;
    }

    for (int i=n;i<2*n-1;i++)
    {
        min1 = min2 = MAXVAL;
        p1 = p2 = 0;
        for (int j=0;j<i;j++)
        {
            if (HuffNode[j].parent==0)
            {
                if (HuffNode[j].weight<min1)
                {
                    min2 = min1;
                    min1 = HuffNode[j].weight;
                    p2 = p1;
                    p1 = j;
                }
                else if (HuffNode[j].weight<min2)
                {
                    min2 = HuffNode[j].weight;
                    p2 = j;
                }
            }
        }
        HuffNode[p1].parent = HuffNode[p2].parent = i+1;
        HuffNode[i].lchild = p1+1;
        HuffNode[i].rchild = p2+1;
        HuffNode[i].weight = HuffNode[p1].weight + HuffNode[p2].weight;
    }
}

//输出哈夫曼树
void PrintHuffTree() 
{            
    int i;
    cout << endl;
    cout << "哈夫曼树各项数据如下表所示:" << endl;
    cout << "结点i weight parent    lchid    rchild" << endl;
    for (i = 0; i < 2 * n - 1; i++)
        cout << i + 1 << setw(8) << HuffNode[i].weight << setw(8) << HuffNode[i].parent << setw(8) << HuffNode[i].lchild << setw(8) << HuffNode[i].rchild <<endl;
        /*printf("%d\t%d\t%d\t%d\t%d\n", i+1, HuffNode[i].weight, HuffNode[i].parent,
            HuffNode[i].lchild, HuffNode[i].rchild);*/
    cout << endl;
}

//构造哈夫曼编码
void CreateHuffCode()
{        
    HCodeType cd;
    int c, p;

    for (int i = 0; i <n; i++) 
    {
        cd.start = n;
        c = i+1;
        p = HuffNode[i].parent;
        while (p)
        {   
            cd.start--;
            if (HuffNode[p-1].lchild == c)
                cd.bit[cd.start] = 0;
            else
                cd.bit[cd.start] = 1;

            c = p;
            p = HuffNode[p-1].parent;
        }
        for (int j = cd.start; j < n; j++)
            HuffCode[i].bit[j] = cd.bit[j];
        HuffCode[i].start = cd.start;
    }
}

//输出每个叶子结点的哈夫曼编码
void PrintHuffcode(void) {        
    int i, j;
    cout << "每个叶子结点的哈夫曼编码为:" << endl;
    for (i = 0; i <n; i++)
    {
        for (j = HuffCode[i].start; j < n; j++)
            cout << HuffCode[i].bit[j];
        cout << endl;
    }
}

int main()
{
    CreateHuffmanTree();
    PrintHuffTree();
    CreateHuffCode();
    PrintHuffcode();
    return 0;
}