这篇文章你可以了解到如下知识:
- 了解一些基本概念,什么是权值,什么是带权路径等
- 了解赫夫曼树的基本概念
- 主页有更多的数据结构和算法的笔记,供需要之人参考
- 下一篇文章赫夫曼编码地址为:https://blog.csdn.net/weixin_46635575/article/details/121295353
二叉树的系列文章:
- 什么是二叉树(增删改查):https://blog.csdn.net/weixin_46635575/article/details/121121492
- 二叉树的顺序存储:https://blog.csdn.net/weixin_46635575/article/details/121188680
- 线索化二叉树:https://blog.csdn.net/weixin_46635575/article/details/121189266
- 树之赫夫曼树:https://blog.csdn.net/weixin_46635575/article/details/121269506
- 赫夫曼编码:https://blog.csdn.net/weixin_46635575/article/details/121295353
一、基本介绍
(一)概念
1、给定n个权值作为n个叶子节点,构造一颗二叉树,若该树的带权路劲长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称为赫夫曼数(Huffman Tree),还有的书翻译为赫夫曼书。
2、赫夫曼数是带权路径长度最短的树,权值较大的节点离根较近。
(二)解释
二、题目理解
给你一个数组:{13,7,8,3,29,6,1},要求转化为一颗赫夫曼树。
实现思路:
图解:
- 步骤一,先排序
{1,3,6,7,8,13,29} - 步骤二,取数
取出1和3,他们的父节点是1+3 = 4;
- 步骤三
用上面形成的一个树和6进行组合
然后再跳7和8组合成为一棵树,为什么不进行三目的步骤三呢,因为7和8比10小啊
步骤四
最终排序(重复排序得到)
图不能理解就代码来。
三、代码实现
首先代码阅读建议
- 首先看我们的节点Node类
- 然后再来看我们的创建赫夫曼树的方法(首先看第一层的推导版,然后看第二层的建议,然后看三层的循环版)
- 最后看遍历的方法
package cn.mldn;
import java.util.*;
public class HuffmanTree {
public static void main(String[] args) {
int[] arr = {13, 7, 8, 3, 29,6,1};
Node node = creatHuffmanTree(arr);
//测试一把,
preOrder(node);
}
//创建赫夫曼树
public static Node creatHuffmanTree(int[] arr) {
/*
//--------------------------第一层----------------------------------
//第一步为了方便操作
//1、遍历arr数组
//2、将arr的每一个元素构成一个Node
List<Node> nodes = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
Node node = new Node(arr[i]);
nodes.add(node);
}
//第二步排序
Collections.sort(nodes);//必须实现Comparable接口
System.out.println("nodes = " + nodes);
//第三步,开始制造数
//(1)取出权值最小的二叉树
Node leftNode = nodes.get(0);//一个元素也可以看成一个二叉树
//(2)取出权为第二的二叉树
Node rightNode = nodes.get(1);
//(3)将一二步制造为一课新的二叉树
Node parent = new Node(leftNode.value + rightNode.value);
//将一二三的挂起来
parent.left = leftNode;
parent.right = rightNode;
//(4)删除ArraysList里面处理过的数据
nodes.remove(leftNode);
nodes.remove(rightNode);
//(5)新构建的要加入里面
nodes.add(parent);
System.out.println("nodes = " + nodes);
//第二步排序
Collections.sort(nodes);//必须实现Comparable接口
//第三步,开始制造数
//(1)取出权值最小的二叉树
leftNode = nodes.get(0);//一个元素也可以看成一个二叉树
//(2)取出权为第二的二叉树
rightNode = nodes.get(1);
//(3)将一二步制造为一课新的二叉树
parent = new Node(leftNode.value + rightNode.value);
//将一二三的挂起来
parent.left = leftNode;
parent.right = rightNode;
//(4)删除ArraysList里面处理过的数据
nodes.remove(leftNode);
nodes.remove(rightNode);
//(5)新构建的要加入里面
nodes.add(parent);
System.out.println("nodes = " + nodes);
//第二步排序
Collections.sort(nodes);//必须实现Comparable接口
//第三步,开始制造数
//(1)取出权值最小的二叉树
leftNode = nodes.get(0);//一个元素也可以看成一个二叉树
//(2)取出权为第二的二叉树
rightNode = nodes.get(1);
//(3)将一二步制造为一课新的二叉树
parent = new Node(leftNode.value + rightNode.value);
//将一二三的挂起来
parent.left = leftNode;
parent.right = rightNode;
//(4)删除ArraysList里面处理过的数据
nodes.remove(leftNode);
nodes.remove(rightNode);
//(5)新构建的要加入里面
nodes.add(parent);
System.out.println("nodes = " + nodes);
//-------------------------第二层是重复第一层的过程,然后到最后我们的nodes里面最后剩下一下,------------------------------
//nodes = [Node{value=1}, Node{value=3}, Node{value=6}, Node{value=7}, Node{value=8}, Node{value=13}, Node{value=29}]
//nodes = [Node{value=3}, Node{value=7}, Node{value=8}, Node{value=13}, Node{value=29}, Node{value=7}]
//nodes = [Node{value=7}, Node{value=8}, Node{value=13}, Node{value=29}, Node{value=10}]
//nodes = [Node{value=8}, Node{value=13}, Node{value=29}, Node{value=17}]
//最后要到剩下一个就可以了,接下来看循环版
*/
//-------------------------第三层,我们经过第一步后,然后再来循环处理-------------------------------------------------
List<Node> nodes = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
Node node = new Node(arr[i]);
nodes.add(node);
}
//最终剩下一个元素,所以大于1
while (nodes.size() > 1) {
//第二步排序
Collections.sort(nodes);//必须实现Comparable接口
System.out.println("nodes = " + nodes);
//第三步,开始制造数
//(1)取出权值最小的二叉树
Node leftNode = nodes.get(0);//一个元素也可以看成一个二叉树
//(2)取出权为第二的二叉树
Node rightNode = nodes.get(1);
//(3)将一二步制造为一课新的二叉树
Node parent = new Node(leftNode.value + rightNode.value);
//将一二三的挂起来
parent.left = leftNode;
parent.right = rightNode;
//(4)删除ArraysList里面处理过的数据
nodes.remove(leftNode);
nodes.remove(rightNode);
//(5)新构建的要加入里面
nodes.add(parent);
System.out.println("nodes = " + nodes);
}
return nodes.get(0);
}
//为了后续测试,写一个前序遍历的方法
public static void preOrder(Node node) {
if (node != null) {
node.preOrder();
}else {
System.out.println("树为空");
}
}
}
/**
* 首先创建节点类
* 1、因为我们第一步就是要排序,所以我们实现Comparable接口
*/
class Node implements Comparable<Node>{
int value;//节点的权值
Node left;//指向左子节点
Node right;//指向右子节点
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
@Override
public int compareTo(Node o) {
//表示从小到达排序
return this.value - o.value;
}
//为了方便进行后续测试,写一个前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
}
四、下一篇文章:赫夫曼压缩
文章地址:https://blog.csdn.net/weixin_46635575/article/details/121295353