哈夫曼树之C++实现

关于哈夫曼树的讲解请参考上篇《三步学通哈夫曼树》(https://blog.csdn.net/helloworldchina/article/details/105210054),这里笔者仅补充一下C++代码的实现。见下:

1 c++代码

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

bool pr=false;//true  打印测试日志
//哈夫曼树的结构
typedef struct
{
    int weight;    // 权值
    int parent, lChild, rChild;    // 双亲及左右孩子的下标
}HTNode, *HuffmanTree;

//输出哈夫曼树各结点信息
void Print(HuffmanTree hT)
{
    std::cout << "index weight parent lChild rChild" << std::endl;
    std::cout << left;    // 左对齐输出
    for(int i = 1, m = hT[0].weight; i <= m; i++)
    {
        std::cout << setw(5) << i << " ";
        std::cout << setw(6) << hT[i].weight << " ";
        std::cout << setw(6) << hT[i].parent << " ";
        std::cout << setw(6) << hT[i].lChild << " ";
        std::cout << setw(6) << hT[i].rChild << std::endl;

    }
}

// 选择权值最小的两颗树
void SelectMin(HuffmanTree hT, int k, int &index1, int &index2)
{
    index1 = index2 = 0;
    int i,j;
    for(j = 1; j <= k;j++)
    {//使index1,index2分别指向hT中最前面的两个无双亲的结点
        if(0 == hT[j].parent)
        {
            if( 0== index1)
            {
                index1 = j;
            }
            else
            {
                index2 = j;
                break;
            }
        }
    }

    if(hT[index1].weight > hT[index2].weight)
    {//使结点index1的权小于index2的权
        int t = index1;
        index1 = index2;
        index2 = t;
    }

    for(i =j+1; i<k;  i++){//继续查找没有双亲且权值最小的两个结点,将其地址记在index1和index2中
        if(0 == hT[i].parent)
        {
            if(hT[i].weight < hT[index1].weight)
            {
                index2 = index1;
                index1 = i;
            }else if(hT[i].weight < hT[index2].weight)
            {
                index2 = i;
            }
        }
    }
}


// 构造有n个权值(叶子结点)的哈夫曼树
int CreateHufmanTree(HuffmanTree &hT)
{
    std::cout << "请输入权值的数量n=? " << std::endl;
    int n, k;//n 权值数(叶子结点数)  k结点的个数
    cin >> n;
    if (n<=1) return 0;
    k = 2*n - 1;
    //创建存储哈夫曼树的数组
    hT = new HTNode[k + 1];    // 0号结点不使用
    //给数组赋初值0
    for(int i = 1; i <= k; i++){
        hT[i].parent = hT[i].lChild = hT[i].rChild = 0;
    }
    std::cout << "请依次输入权值,并回车确认" << std::endl;
    for(int i = 1; i <= n; i++){
        cin >> hT[i].weight;    // 输入权值
    }
    hT[0].weight = k;    // 用0号结点保存结点数量


    if (pr)
    {
        std::cout << "打印初始的数组:" << std::endl;
        Print(hT);
    }

    /****** 初始化完毕, 创建哈夫曼树 ******/
    for(int i = n + 1; i <=k; i++)
    {
        int index1, index2;
        SelectMin(hT, i, index1, index2);

        hT[index1].parent = hT[index2].parent = i;
        hT[i].lChild = index1; hT[i].rChild = index2;    // 作为新结点的孩子
        hT[i].weight = hT[index1].weight + hT[index2].weight;    // 新结点为左右孩子结点权值之和

        if (pr)
        {
            std::cout << "打印构建哈夫曼树过程中的数组:" << std::endl;
            std::cout << "i=" <<i<<std::endl;
            std::cout << "index1=" <<index1<<";index2="<<index2<<std::endl;
            Print(hT);
        }
    }
    return 1;
}

int HuffmanTreeWPL_(HuffmanTree hT, int i, int deepth)
{
    if(hT[i].lChild == 0 && hT[i].rChild == 0)
    {
        return hT[i].weight * deepth;
    }
    else
    {
        return HuffmanTreeWPL_(hT, hT[i].lChild, deepth + 1) + HuffmanTreeWPL_(hT, hT[i].rChild, deepth + 1);
    }
}

// 计算WPL(带权路径长度)
int HuffmanTreeWPL(HuffmanTree hT)
{
    return HuffmanTreeWPL_(hT, hT[0].weight, 0);
}



// 销毁哈夫曼树
void DestoryHuffmanTree(HuffmanTree &hT)
{
    delete[] hT;
    hT = NULL;
}

int main()
{

    HuffmanTree hT;
    if (CreateHufmanTree(hT))
    {
        std::cout << "打印哈夫曼树数组:" << std::endl;
        Print(hT);
        std::cout << "WPL = " << HuffmanTreeWPL(hT) << std::endl;
        DestoryHuffmanTree(hT);
    } else std::cout << "输入有误,不能创建哈夫曼树!" << std::endl;

    return 0;
}

2 运行结果

在这里插入图片描述

发布了17 篇原创文章 · 获赞 9 · 访问量 5850

猜你喜欢

转载自blog.csdn.net/helloworldchina/article/details/105210853