哈夫曼树

原创 2015年11月20日 16:00:34

哈夫曼树概念

哈夫曼(Huffman)树又称最优二叉树。它是n个带权叶子结点构成的二叉树中,带权路径长度WPL最小的二叉树。因为构造这种树的算法是最早由哈夫曼于1952年提出的,所以被称之为哈夫曼树。

二叉树的性质

二叉树中有五点性质非常重要,需要记住。
性质1:在二叉树的第 i 层上至多有2^(i-1)个结点
性质2:深度为k的二叉树至多有2^k-1个结点
性质3:对任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1
性质4:具有n个结点的完全二叉树的深度为[log(n)]+1([x]表示不大于x的最大整数)
性质5:如果对一棵有n个结点的完全二叉树(其深度为[log(n)]+1)的结点按层序编号(从第1层到第[log(n)]+1层,每层从左到右),对任一结点i(1<=i<=n)有:
(1).如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点[i/2]
(2).如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
(3).如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1

基本术语

结点的权
“权”就相当于“重要度”,我们形象的用一个具体的数字来表示,然后通过数字的大小来决定谁重要,谁不重要。
路径
树中从“一个结点”到“另一个结点”之间的分支。
路径长度
一个路径上的分支数量。
树的路径长度
从树的根节点到每个节点的路径长度之和。
节点的带权路径路径长度
其实也就是该节点到根结点的路径长度乘以该节点的权。
树的带权路径长度
树中各个叶节点的路径长度*该叶节点的权的和,常用WPL(Weight Path Length)表示。

其中二叉树性质3证明如下:
T = n0 + n1 +n2
(1) 按照边求和得: T = n1 + 2 * n2 + 1
(2) 所以 (2) - (1)可得 n2 + 1 - n0 = 0
所以n0 = n2 + 1

哈弗曼树有一个性质:
哈夫曼树的总结点数是2n-1(n是叶子节点数)
证明如下:

因为二叉树中n0=n2+1;
所以节点总数T=n0+n1+n2=n2+1+n1+n2;
又n1=0,
所以T=2n2+1=2(n0-1)+1=2n0-1,得证

哈夫曼数构建和编码

详见《入门经典》P235
1.首先将字符按权值大小排序成向量P;
2.每次合并后的点push_back到向量Q,因为后合并的点一定小于先合并的点,所以Q内也是有序的;
3.这样每次比较P,Q的首元素就可以提取出两个最小的点,进行合并

2、3步骤相当于时间复杂度为O(n),加上1排序O(nlgn),总时间复杂度为O(nlgn)

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

struct node{
    int w;
    node* lchild;
    node* rchild;
    node():w(0),lchild(NULL),rchild(NULL){}
};

node* huffman(int weights[],int len){
    sort(weights,weights+len);
    vector<node*> P;
    for (int m = 0; m < len;m++){
        node* n = new node();
        n->w = weights[m];
        P.push_back(n);
    }
    vector<node*> Q;

    int i = 0, j = 0;
    while (i<len || Q.size()<len-1){//因为度为2的节点数为len-1个
        if (i==0){
            node* p = new node();
            p->lchild = P[0];
            p->rchild = P[1];
            p->w = P[0]->w + P[1]->w;

            Q.push_back(p);
            i += 2;
        }
        else{
            node* p = new node();
            vector<node*> tmp(2);
            for (int cnt = 0; cnt < 2;cnt++){
                if (i < len){
                    if (j<Q.size() && P[i]->w > Q[j]->w){
                        tmp[cnt] = Q[j];
                        j++;
                    }
                    else{
                        tmp[cnt] = P[i];
                        i++;
                    }
                }
                else{//处理P向量用完的情况
                    tmp[cnt] = Q[j];
                    j++;
                }

            }
            p->lchild = tmp[0];
            p->rchild = tmp[1];
            p->w = tmp[0]->w + tmp[1]->w;

            Q.push_back(p);
        }
    }

    return Q[len - 2];
}

void print(node* root){
    if (root != NULL){
        cout << root->w<<" ";
    }
    if (root->lchild != NULL){
        print(root->lchild);
    }
    if (root->rchild!=NULL){
        print(root->rchild);
    }
}

void huffman_code(node* root,int code[],int cur){
    if (root->lchild == NULL&&root->rchild == NULL){
        for (int i = 0; i < cur;i++){
            cout << code[i];
        }
        cout << endl;
    }

    if (root->lchild!=NULL){
        code[cur] = 1;
        huffman_code(root->lchild, code, cur + 1);
        code[cur] = 0;//修改了全局变量一定要改回来
    }
    if (root->rchild!=NULL){
        code[cur] = 0;
        huffman_code(root->rchild, code, cur + 1);
        code[cur] = 1;
    }
}

int main(){
    int weights[] = {2,5,7,13};
    int len = 4;
    node* root = huffman(weights, len);
    //print(root);
    int *code=new int[len];
    huffman_code(root, code, 0);

    return 0;
}

这里写图片描述
这里写图片描述

这里写图片描述
这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

哈夫曼树详解

二叉树中有一种特别的树——哈夫曼树(最优二叉树),其通过某种规则(权值)来构造出一哈夫曼二叉树,在这个二叉树中,只有叶子节点才是有效的数据节点(很重要),其他的非叶子节点是为了构造出哈夫曼而引入的! ...
  • best_fiends_zxh
  • best_fiends_zxh
  • 2016年12月05日 20:23
  • 1006

这个Matlab实现的程序,实现用于一维8位或16位整数数组的自适应Huffman哈夫曼编码。

  • 2010年01月15日 12:56
  • 38KB
  • 下载

关于哈夫曼树的一些总结--(总是要和完全二叉树和满二叉树搞混了 = =)

哈夫曼树: 给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。哈夫曼树是带权路径长度最短的树,权值较大的结...
  • HL_liang
  • HL_liang
  • 2014年12月30日 16:47
  • 2797

哈夫曼树学习小记

B组又现我不会的神奇东西了……定义:现在有n个元素,每个元素有一个值。 你需要把这n个元素放在一棵二叉树的叶子节点上,规定每个元素的代价为它所在叶子节点的深度乘上它的值,哈夫曼树就是使总代价最小的这...
  • Cold_Chair
  • Cold_Chair
  • 2017年08月24日 15:37
  • 244

C++ 哈夫曼树的实现

我的源码主要是实现了哈夫曼树的基本功能,代码并没有进行更加好的优化,望见谅,如果你有好的idea,可以的话,告诉我一下,学习学习~...
  • Notzuonotdied
  • Notzuonotdied
  • 2016年11月06日 15:10
  • 3403

哈夫曼树C++实现

哈夫曼树的介绍 Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树。 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。 这...
  • qq1263292336
  • qq1263292336
  • 2015年11月30日 17:08
  • 1651

Huffman tree(赫夫曼树、霍夫曼树、哈夫曼树、最优二叉树)

Huffman tree(赫夫曼树、霍夫曼树、哈夫曼树、最优二叉树)flyfish 2015-8-1Huffman tree因为翻译不同所以有其他的名字 赫夫曼树、霍夫曼树、哈夫曼树 定义引用自严蔚...
  • flyfish1986
  • flyfish1986
  • 2015年08月01日 22:37
  • 2631

哈夫曼树(最优二叉树)及其Java实现

一、定义 一些定义: 节点之间的路径长度:在树中从一个结点到另一个结点所经历的分支,构成了这两个结点间的路径上的经过的分支数称为它的路径长度 树的路径长度:从树的根节点到树中每一结点...
  • bruce_6
  • bruce_6
  • 2014年08月18日 10:50
  • 4759

JAVA实现哈夫曼树

** * 创建哈夫曼树,并打印。 * * @author timmy1 1.创建树的节点:包括节点的数据,他指向的左节点和右节点 2.使用list集合保存所有的节点元素 * 3.创建...
  • Timmy_zzh
  • Timmy_zzh
  • 2016年11月24日 09:26
  • 647

[c] HDOJ1053 哈夫曼树的应用

http://acm.hdu.edu.cn/showproblem.php?pid=1053 题目标题:entropy 题目大意:将一串字符串用哈夫曼树的方法压缩,求压缩前与压缩后所占空间与压缩比...
  • wychermit
  • wychermit
  • 2015年07月20日 20:58
  • 324
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:哈夫曼树
举报原因:
原因补充:

(最多只允许输入30个字)