本章介绍哈夫曼树。和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现。后续再分别给出C++和Java版本的实现;实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可。若文章有错误或不足的地方,请帮忙指出!

目录

1. 哈夫曼树的介绍
2. 哈夫曼树的图文解析
3. 哈夫曼树的基本操作
4. 哈夫曼树的完整源码


转载请注明出处:http://www.cnblogs.com/skywang12345/

更多内容:数据结构与算法系列 目录

哈夫曼树的介绍

Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树。

定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。
这个定义里面涉及到了几个陌生的概念,下面就是一颗哈夫曼树,我们来看图解答。

(01) 路径和路径长度

定义:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
例子:100和80的路径长度是1,50和30的路径长度是2,20和10的路径长度是3。

(02) 结点的权及带权路径长度

定义:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
例子:节点20的路径长度是3,它的带权路径长度= 路径长度 * 权 = 3 * 20 = 60。

(03) 树的带权路径长度

定义:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
例子:示例中,树的WPL= 1*100 + 2*80 + 3*20 + 3*10 = 100 + 160 + 60 + 30 = 350。

比较下面两棵树

上面的两棵树都是以{10, 20, 50, 100}为叶子节点的树。

左边的树WPL=2*10 + 2*20 + 2*50 + 2*100 = 360
右边的树WPL=350

左边的树WPL > 右边的树的WPL。你也可以计算除上面两种示例之外的情况,但实际上右边的树就是{10,20,50,100}对应的哈夫曼树。至此,应该堆哈夫曼树的概念有了一定的了解了,下面看看如何去构造一棵哈夫曼树。

哈夫曼树的图文解析

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,哈夫曼树的构造规则为:

1. 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
2. 在森林中选出根结点的权值最小的两棵树进行合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
3. 从森林中删除选取的两棵树,并将新树加入森林;
4. 重复(02)、(03)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

以{5,6,7,8,15}为例,来构造一棵哈夫曼树。

第1步:创建森林,森林包括5棵树,这5棵树的权值分别是5,6,7,8,15。
第2步:在森林中,选择根节点权值最小的两棵树(5和6)来进行合并,将它们作为一颗新树的左右孩子(谁左谁右无关紧要,这里,我们选择较小的作为左孩子),并且新树的权值是左右孩子的权值之和。即,新树的权值是11。 然后,将"树5"和"树6"从森林中删除,并将新的树(树11)添加到森林中。
第3步:在森林中,选择根节点权值最小的两棵树(7和8)来进行合并。得到的新树的权值是15。 然后,将"树7"和"树8"从森林中删除,并将新的树(树15)添加到森林中。
第4步:在森林中,选择根节点权值最小的两棵树(11和15)来进行合并。得到的新树的权值是26。 然后,将"树11"和"树15"从森林中删除,并将新的树(树26)添加到森林中。
第5步:在森林中,选择根节点权值最小的两棵树(15和26)来进行合并。得到的新树的权值是41。 然后,将"树15"和"树26"从森林中删除,并将新的树(树41)添加到森林中。
此时,森林中只有一棵树(树41)。这棵树就是我们需要的哈夫曼树!

哈夫曼树的基本操作

哈夫曼树的重点是如何构造哈夫曼树。本文构造哈夫曼时,用到了以前介绍过的"(二叉堆)最小堆"。下面对哈夫曼树进行讲解。

1. 基本定义

typedef int Type;

typedef struct _HuffmanNode {
Type key; // 权值
struct _HuffmanNode *left; // 左孩子
struct _HuffmanNode *right; // 右孩子
struct _HuffmanNode *parent; // 父节点
} HuffmanNode, *HuffmanTree;

HuffmanNode是哈夫曼树的节点类。

2. 构造哈夫曼树

/*
* 创建Huffman树
*
* 参数说明:
* a 权值数组
* size 数组大小
*
* 返回值:
* Huffman树的根
*/
HuffmanNode* create_huffman(Type a[], int size)
{
int i;
HuffmanNode *left, *right, *parent; // 建立数组a对应的最小堆
create_minheap(a, size); for(i=0; i<size-1; i++)
{
left = dump_from_minheap(); // 最小节点是左孩子
right = dump_from_minheap(); // 其次才是右孩子 // 新建parent节点,左右孩子分别是left/right;
// parent的大小是左右孩子之和
parent = huffman_create_node(left->key+right->key, left, right, NULL);
left->parent = parent;
right->parent = parent; // 将parent节点数据拷贝到"最小堆"中
if (dump_to_minheap(parent)!=0)
{
printf("插入失败!\n结束程序\n");
destroy_huffman(parent);
parent = NULL;
break;
}
} // 销毁最小堆
destroy_minheap(); return parent;
}

首先通过create_huffman(a, size)来一个最小堆。最小堆构造完成之后,进入for循环。

每次循环时:

(01) 首先,将最小堆中的最小节点拷贝一份并赋值给left,然后重塑最小堆(将最小节点和后面的节点交换位置,接着将"交换位置后的最小节点"之前的全部元素重新构造成最小堆);
(02) 接着,再将最小堆中的最小节点拷贝一份并将其赋值right,然后再次重塑最小堆;
(03) 然后,新建节点parent,并将它作为left和right的父节点;
(04) 接着,将parent的数据复制给最小堆中的指定节点。

二叉堆中已经介绍过堆,这里就不再对堆的代码进行说明了。若有疑问,直接参考后文的源码。其它的相关代码,也Please RTFSC(Read The Fucking Source Code)!

哈夫曼树的完整源码

哈夫曼树的源码共包括4个文件。

1. 哈夫曼树的头文件(huffman.h)

2. 哈夫曼树的实现文件(huffman.c)

3. 哈夫曼树对应的最小堆(minheap.c)

4. 哈夫曼树的测试程序(huffman_test.c)

哈夫曼树(一)之 C语言详解的更多相关文章

  1. 哈夫曼树的构建(C语言)

    哈夫曼树的构建(C语言) 算法思路: 主要包括两部分算法,一个是在数组中找到权值最小.且无父结点两个结点位置,因为只有无父结点才能继续组成树: ​ 另一个就是根据这两个结点来修改相关结点值. 结构定义 ...

  2. 数据结构之C语言实现哈夫曼树

    1.基本概念 a.路径和路径长度 若在一棵树中存在着一个结点序列 k1,k2,……,kj, 使得 ki是ki+1 的双亲(1<=i<j),则称此结点序列是从 k1 到 kj 的路径. 从 ...

  3. C语言数据结构之哈夫曼树及哈夫曼编码的实现

    代码清单如下: #pragma once #include<stdio.h> #include"stdlib.h" #include <string.h> ...

  4. 哈夫曼树(二)之 C++详解

    上一章介绍了哈夫曼树的基本概念,并通过C语言实现了哈夫曼树.本章是哈夫曼树的C++实现. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载 ...

  5. Android版数据结构与算法(七):赫夫曼树

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 近期忙着新版本的开发,此外正在回顾C语言,大部分时间没放在数据结构与算法的整理上,所以更新有点慢了,不过既然写了就肯定尽力将这部分完全整理好分享出 ...

  6. 6-9-哈夫曼树(HuffmanTree)-树和二叉树-第6章-《数据结构》课本源码-严蔚敏吴伟民版

    课本源码部分 第6章  树和二叉树 - 哈夫曼树(HuffmanTree) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接☛☛☛ <数据结构-C语言版> ...

  7. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

  8. java实现哈弗曼树和哈夫曼树压缩

    本篇博文将介绍什么是哈夫曼树,并且如何在java语言中构建一棵哈夫曼树,怎么利用哈夫曼树实现对文件的压缩和解压.首先,先来了解下什么哈夫曼树. 一.哈夫曼树 哈夫曼树属于二叉树,即树的结点最多拥有2个 ...

  9. 【贪心 哈夫曼树】bzoj2923: [Poi1998]The lightest language

    失去了以前用STL乱搞的能力…… 题目描述 语言也是数学上经常研究的一种数据. 给出数学上关于语言的如下定义: 字母表:大小为 K 的字母表是一个由 K 不同的字符组成的集合. 单词:长度为 m 的单 ...

随机推荐

  1. [转] How to import a large data set using XPO efficiently within a transaction

    https://www.devexpress.com/Support/Center/Example/Details/T333879

  2. ECMall——安装时的小bug解决办法

    第一次安装ECmall,安装了好多遍,总是出现Strict Standards: Non-static method这样的错误,折腾了五六遍,还是安装不上,仍然是类似的错误.气愤!于是上百度查:Ecm ...

  3. Ubuntu 12.04 改造指南

    文章转自:http://www.lupaworld.com/article-217719-1.html 升级12.04已经有一段时间了.作为一个从08年就开始用Ubuntu的老用户,我觉得作为一个LT ...

  4. 初学python里的yield send next

    今天看书的时候突然看到这个想起来一直没有怎么使用过send和next试了一下 发现了一个诡异的问题 import math def get_primes(start): while 1 : if is ...

  5. Angular 2 + Electron 开发web和桌面应用

    https://github.com/zhongzf/angular2-electron-quickstart Web用法: # Clone this repository git clone htt ...

  6. 微软Connect教程系列—VS2015集成新潮工具(四)

    本课程来源与微软connect视频教程,Modern Web Tooling in Visual Studio 2015 本课程主要讲下当下流行的前端工具 bower和grunt 首先简单介绍下这俩货 ...

  7. Grpc微服务从零入门

    快速入门 安装 JDK 毫无疑问,要想玩Java,就必须得先装Java JDK,目前公司主要使用的是Oracle JDK 8,安装完成后要配置环境才能正常使用,真蠢,不过也就那么一下下,认了吧.配置方 ...

  8. 精神哥讲Crash(一):UnsatisfiedLinkError

    版权声明:本文为腾讯Bugly原创文章,如需转载,请标明出处.   大家好,我是腾讯Bugly的精神哥(英文名:spirit),是Bugly资深码奴的同时,又是Bugly神秘的Crash实验室研究员哦 ...

  9. PostgreSQL基础整理(一)

    1. 创建数据库: 1)登录bin目录,createdb.exe -U postgres -e mydb; -U 表示本次操作的登录用户名,如果不写会取windows登录的账户,如Administra ...

  10. java 多线程(threadlocal)

    package com.example; import java.util.Random; public class App { public static class MyRunnable1 imp ...