huffman(哈夫曼)树的实现

哈夫曼树的实现

概念:

哈夫曼(Huffman)树又称最优二叉树或最优搜索树,是一种带权路径长度最短的二叉树。在许多应用中,常常赋给树中结点一个有某种意义的实数,称此实数为该结点的权。从树根结点到该结点之间的路径长度与该结点上权的乘积称为结点的带权路径长度(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 
#include 

using namespace std;

int n, m;
typedef struct
{
    int weight;                               //节点权重
    int parent, lchild, rchild;               //节点的双亲下标,左右孩子的下标
    int code;                                 //节点的编号
}htnode, *huffmantree;

//      选择两个权值最小的节点
void Selectmin(huffmantree ht, int n, int &s1, int &s2)
{
    s1 = s2 = 0;                              // 初始化两最小个节点的位置
    int i;

    for(i=1; i ht[s2].weight)             // 判断两节点的大小,永远保持s1的权值比s2小
    {
        int t = s1;
        s1 = s2;
        s2 = t;
    }
    for(i+=1; i> n;                                 // 输入要输入的节点数
    m = 2*n - 1;                              // n个叶子的huffman树有2n-1个节点

    ht = new htnode[m + 1];                   // htnode[0] 不存节点
    for( int i=1; i<=m; i++)                  // 初始化每个节点的值
    {
        ht[i].parent = ht[i].lchild = ht[i].rchild = 0;
        ht[i].code = -1;                      // 初始化编码都为-1
    }
    for( int i=1; i<=n; i++)                  // 输入每个节点的权值
    {
        cin >> ht[i].weight;
    }

    ht[0].weight = m;                         // ht[0]的权值设为节点个数

    for( int i=n+1; i<=m; i++)                // 有n个节点,从n+1的位置开始添加节点
    {
        int s1,s2;
        Selectmin(ht, i, s1, s2);             // 传入要添加节点的huffman树和要添加的位置
                                              // 返回两个权值最小的位置,并且s1<=s2
        ht[s1].parent = i;                    // 将两节点的双亲设为新节点的位置
        ht[s2].parent = i;
        ht[s1].code = 0;                      // 较小的节点编码为0
        ht[s2].code = 1;                      // 较大的节点编码为1
        ht[i].lchild = s1;                    // 添加新节点,左右孩子为两节点的位置
        ht[i].rchild = s2;
        ht[i].weight = ht[s1].weight + ht[s2].weight;   // 新节点的权值为左右孩子权值的和


    }
}

// 计算huffman树的总路径长度
int huffmantreeWPL(huffmantree ht, int i, int d)    // 传入huffman树,节点位置,节点深度
{
    if(ht[i].lchild == 0 && ht[i].rchild == 0 )     // 若该节点为叶子节点,算出该节点的路径
        return ht[i].weight * d;
    else                                            // 若该节点不是叶子节点,则该节点的路径等于左右孩子的路径和
        return huffmantreeWPL(ht, ht[i].lchild, d+1) + huffmantreeWPL(ht, ht[i].rchild, d+1);
}


// 输出huffman树各节点的信息
void printf(huffmantree ht)
{
    cout << "index weight parent lchild rchild" << endl;
    for(int i=1; i<=m; i++)
    {
        cout << "  " << i << "  " << " ";
        cout << "  " << ht[i].weight << "   ";
        cout << "  " << ht[i].parent << "   ";
        cout << "  " << ht[i].lchild << "   ";
        cout << "  " << ht[i].rchild << "   " << endl;
    }
}

// 输出各叶子节点的编码
void Encoding(huffmantree ht, int i)
{
    if(ht[i].parent==0)              // 若该节点为根节点返回上一层
        return;
    else
    {
        Encoding(ht, ht[i].parent);         // 用递归找到该叶子的根节点,输入从根节点到叶子的编码
    }
    cout << ht[i].code;
}

// 输出叶子节点的编码
void huffmantreeEncoding(huffmantree ht)
{
    for(int i=1; i<=n; i++)                 // 只输出前n个节点的编码
    {
        if(ht[i].lchild==0 && ht[i].rchild==0)     // 如果该节点为叶子节点
        {
            printf("%d:",ht[i].weight);
            Encoding(ht,i);                        // 用递归输出该节点的编码
            printf("\n");
        }
    }
}



int main()
{
    huffmantree ht;
    creathuffmantree(ht);                              // 先创建一个huffman树
    printf(ht);                                        // 输出huffman树各节点的信息
    cout << "WPL = " << huffmantreeWPL(ht,m,0) << endl;  // 算出huffman树的总路径长度
    huffmantreeEncoding(ht);                            // 输出各叶子节点的编码
    return 0;
}



你可能感兴趣的:(算法模版)