IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 2021-10-06 -> 正文阅读

[数据结构与算法]2021-10-06

计算Huffman树的带权路径长度WPL(C++优先队列实现)

1 构建一棵Huffman树

typedef struct HTreeNode
{
    DataType data;  //结点的关键字
    HTreeNode *lchild,*rchild;  //左右孩子
    int level;  //结点在树中的层次
    
}HTreeNode,*HTree;

/***
 * 构造Huffman树:
 * 对于优先队列中的结点,每次取下两个合成一个新的结点重新加入优先队列,直至优先队列中仅剩一个结点
 * 由于优先队列,所以我们每次取下的,必然是两个最小的关键字结点,契合Huffman算法
 **/ 
HTree HuffmanTree(priority_queue<HTree,vector<HTree>,cmp> &q){
    
    while (q.size()>1)//仅剩一个结点(即Huffman树的根节点时跳出循环)
    {
        HTree h1=q.top();
        q.pop();
        HTree h2=q.top();
        q.pop();
        HTree h=(HTreeNode*)malloc(sizeof(HTreeNode));  //将取出的两个节点合成新的结点
        h->lchild=h1;
        h->rchild=h2;
        h->data=h1->data+h2->data;
        q.push(h);
    }

    return q.top();
    
}

2 计算Huffman树中指定结点所在的层次

//计算在Huffman树中指定p结点的层次
int getLevel(HTree tree,HTreeNode* p){
    if(!tree)
        return 0;
    if(tree==p){//发现了p结点,则当前层为第一层,向上累加可得p结点的层次
        return 1;
    }
    int lLevel=getLevel(tree->lchild,p);
    int rLevel=getLevel(tree->rchild,p);
    
    if (lLevel || rLevel) //左右孩子不全为NULL时,则当前结点可能是根结点到P结点路径上的点,需要继续递归探查
    {
         return lLevel>rLevel? lLevel+1:rLevel+1;
    }
    //当tree结点不为NULL,不是p结点,又是叶子结点(即p不会是根节点到P结点路径上的点)
    return 0;
    
}

3 设置Huffman树中所有结点的层次

/***
 *设置HuffmanTree每个结点的层次值,这里采用遍历每个结点进行设置。 
 **/
void setTNodeDepth(HTree &tree){
    HTree t=tree;
   
    queue<HTree> q;
    q.push(tree);
    while(!q.empty()){
        HTree h=q.front();
        q.pop();
        h->level=getLevel(tree,h);
       	if(h->lchild)
            q.push(h->lchild);
        if(h->rchild)
            q.push(h->rchild);
    }
    
}

4 计算Huffman树的带权路径长度WPL

/***
 * 计算Huffman的WPL值:所有叶子的层次和权值的乘积之和
 **/
int getHuffmanTreeWPL(HTree tree){
    HTree t=tree;
    int HuffmanTreeWPL=0;
    queue<HTree> q;
    q.push(tree);
    while(!q.empty()){
        HTree h=q.front();
        q.pop();
        h->level=getLevel(tree,h);
        if(!h->lchild && !h->rchild){//只计算叶子节点的权值
            HuffmanTreeWPL+=(h->level*h->data);
        }
        if(h->lchild)
            q.push(h->lchild);
        if(h->rchild)
            q.push(h->rchild);
    }

    return HuffmanTreeWPL;
}

完整代码如下所示:

/*
 * @Descripttion: 利用C++ STL的优先队列解决Huffman问题
 * @version: 1.0
 * @Author: Sakura
 * @Date: 2021-10-06 12:34:18
 * @LastEditTime: 2021-10-06 22:45:15
 */
#include <iostream>
#include<queue>
#include<stack>
#define N 100
#define DataType int
using namespace std;

typedef struct HTreeNode
{
    DataType data;
    HTreeNode *lchild,*rchild;
    int level;
    
}HTreeNode,*HTree;

/**
 * 设置优先队列的排序规则,关键字小的放在队头
 **/ 
struct cmp
{
	bool operator () (const HTree &a, const HTree &b)		  
	{
		return a->data>b->data;			
	}
};

/**
 * 将数组中的关键字,逐个存入到优先队列中
 **/ 
void init(priority_queue<HTree,vector<HTree>,cmp> &q,int arr[],int len){

    
    for(int i=0;i<len;i++){
        HTree h=(HTreeNode*)malloc(sizeof(HTreeNode));
        h->lchild=NULL;
        h->rchild=NULL;
        h->data=arr[i];
        q.push(h);
    }

}

//输出整个优先队列
void print(priority_queue<HTree,vector<HTree>,cmp> &q){
    while (!q.empty())
    {
        HTree h=q.top();
        q.pop();
        cout<<h->data<<endl;
    }

    cout<<"--------------------------"<<endl;
}

/***
 * 构造Huffman树:
 * 对于优先队列中的结点,每次取下两个合成一个新的结点重新加入优先队列,直至优先队列中仅剩一个结点
 * 由于优先队列,所以我们每次取下的,必然是两个最小的关键字结点,契合Huffman算法
 **/ 
HTree HuffmanTree(priority_queue<HTree,vector<HTree>,cmp> &q){
    
    while (q.size()>1)//仅剩一个结点(即Huffman树的根节点时跳出循环)
    {
        HTree h1=q.top();
        q.pop();
        HTree h2=q.top();
        q.pop();
        HTree h=(HTreeNode*)malloc(sizeof(HTreeNode));  //将取出的两个节点合成新的结点
        h->lchild=h1;
        h->rchild=h2;
        h->data=h1->data+h2->data;
        q.push(h);
    }

    return q.top();
    
}
//递归计算指定节点的高度(与本题无关)
int getDepth(HTree tree){
    if (tree==NULL)
    {
        return 0;
    }else{
        
        int lDepth=getDepth(tree->lchild);
        int rDepth=getDepth(tree->rchild);
        return lDepth>rDepth? lDepth+1:rDepth+1;
    }
    
}

//计算在Huffman树中指定p结点的层次
int getLevel(HTree tree,HTreeNode* p){
    if(!tree)
        return 0;
    if(tree==p){//发现了p结点,则当前层为第一层,向上累加可得p结点的层次
        return 1;
    }
    int lLevel=getLevel(tree->lchild,p);
    int rLevel=getLevel(tree->rchild,p);
    
    if (lLevel || rLevel) //左右孩子不全为NULL时,则当前结点可能是根结点到P结点路径上的点,需要继续递归探查
    {
         return lLevel>rLevel? lLevel+1:rLevel+1;
    }
    //当tree结点不为NULL,不是p结点,又是叶子结点(即p不会是根节点到P结点路径上的点)
    return 0;
    
}

/***
 *设置HuffmanTree每个结点的层次值,这里采用遍历每个结点进行设置。 
 **/
void setTNodeDepth(HTree &tree){
    HTree t=tree;
    // int treeHeight=getDepth(tree);  //HuffmanTree的树高度
    queue<HTree> q;
    q.push(tree);
    while(!q.empty()){
        HTree h=q.front();
        q.pop();
        h->level=getLevel(tree,h);
        // cout<<tree->data<<"  "<<h->data<<"  "<<h->level<<endl;
        if(h->lchild)
            q.push(h->lchild);
        if(h->rchild)
            q.push(h->rchild);
    }
    
}

/***
 * 计算Huffman的WPL值:所有叶子的层次和权值的乘积之和
 **/
int getHuffmanTreeWPL(HTree tree){
    HTree t=tree;
    int HuffmanTreeWPL=0;
    queue<HTree> q;
    q.push(tree);
    while(!q.empty()){
        HTree h=q.front();
        q.pop();
        h->level=getLevel(tree,h);
        if(!h->lchild && !h->rchild){//只计算叶子节点的权值
            // cout<<h->level<<"*"<<h->data<<"="<<h->level*h->data<<endl;
            HuffmanTreeWPL+=(h->level*h->data);
        }
        if(h->lchild)
            q.push(h->lchild);
        if(h->rchild)
            q.push(h->rchild);
    }

    return HuffmanTreeWPL;
}

int main(){
    
    DataType arr[N] = {1, 8, 15, 19, 32, 17, 65, 3, 9};
    int len = 9;
    priority_queue<HTree,vector<HTree>,cmp> q;
    init(q,arr,len);
    HTree tree=HuffmanTree(q);

    setTNodeDepth(tree);
    cout<<getHuffmanTreeWPL(tree)<<endl;
    return 0;
}

小白也是在学习数据结构,哪里学的不通透欢迎各位指正!
觉得写得不错的话,点个赞吧!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-07 14:04:31  更:2021-10-07 14:05:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 11:49:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码