哈夫曼树的创建(代码实现)
先给出我们的哈夫曼树结点类:
- 注意: 我们的结点类一定要实现Comparable接口, 以便于我们可以通过Collections工具类来调用sort()方法给我们的集合排序
- 因为我们想要构建哈夫曼树的源数据是一个Node对象构成的数组, 然后我们为了操作方便, 我们将这个Node对象构成的数组先转化为集合,方便我们操作
/**
* 首先我们先创建一个哈夫曼树节点类
*/
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 +"]";
}
//这里为了能让我们的结点类进行排序, 我们要实现Comparable接口并实现compareTo()方法
@Override
public int compareTo(Node node){
return this.value - node.value; //this-形参是升序排序
}
//为了方便测试我们编写一个对二叉树进行前序遍历的方法
//我们会通过哈夫曼树类中的前序遍历的方法调用此方法, 并且会传入我们要开始遍历的头结点
public void preOrder(){
//先打印我们的当前节点
System.out.println(this);
if(this.left != null){ //如果左边子树上有节点就向左边子树上遍历
this.left.preOrder();
}
if(this.right != null){ //如果右边子树上有节点就向右边子树上遍历
this.right.preOrder();
}
}
}
然后给出我们的构建哈夫曼树的类:
- 我们只需要向这个类中的构建哈夫曼树的方法中传入一个int型的数组,传入的int[]中存储的就是每个结点的权值, 那么我们传入这个数组之后我们就要通过操作这个数组最终构建一个哈夫曼树, 然后将这个哈夫曼树的头结点返回
public class HuffmanTree {
//编写一个生成哈夫曼树的方法
//开始的时候传入一个数组
public static Node createHuffmanTree(int [] arr){
//首先我们先创建一个ArrayList集合, 用于遍历将我们的数组中的元素封装为一个一个的Node结点之后加入到我们的ArrayList集合对象中来
ArrayList<Node> nodes = new ArrayList<>();
//使用foreach(增强for循环进行遍历)
for (int a:
arr) {
nodes.add(new Node(a));
}
//然后我们就要编写一个while循环,在while循环中来生成我们的哈夫曼树
while(nodes.size() > 1){ //只要集合中还有超过一个元素, 那么我们就继续执行while循环
//由于我们每次的时候都是要找到权值最小的结点, 所以我们先要对我们的集合进行一个排序
Collections.sort(nodes); //使用Collections工具类中的sort()方法对nodes进行一个排序, 默认是通过自然排序的方式
//排序之后取出最小的两个值
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//创建一个新的结点, 这个节点的value就是这两个结点之和
Node node = new Node(leftNode.value+rightNode.value);
//将新结点拼接上去
node.right = rightNode;
node.left = leftNode;
/*
此时要注意: 我们删除这两个结点的时候一定要是先删除索引为1的结点, 然后删除索引为2的结点, 因为如果我们先删除索引为0的结点之后那么原来索引为1的结点就会变成索引为0
的结点, 所以这个时候我们再去删除索引为1的结点, 如果我们删除结点之前集合中只有两个结点, 这个时候就会出现索引越界异常
*/
//删除两个旧结点
nodes.remove(rightNode);
nodes.remove(leftNode);
//将我们的新结点添加到集合中
nodes.add(node);
}
//最终退出循环的时候集合中就只剩下了一个元素, 剩下的一个元素就是创建好的哈夫曼树的头结点, 我们直接将这个头结点返回即可
return nodes.get(0);
}
//编写一个前序遍历的方法
public static void preOrder(Node root){// 传入头结点从头结点开始遍历
root.preOrder();
}
//测试我们的生成哈夫曼树的方法
public static void main(String[] args) {
//创建一个数组,数组中保存我们想要转换为哈夫曼树的权值, 然后将这个数组传入到我们的生成哈夫曼树的方法中
int[] arr = {12,234,34,2,1};
Node huffmanTree = createHuffmanTree(arr);
preOrder(huffmanTree);
}
}
补充:
注意: 我们如果ArrayList集合中只有两个数据了,这个时候如果我们要通过索引删除ArrayList集合中的剩余的两个数据, 这个时候如果我们通过索引删除, 这个时候我们一定要注意: 我们先要删除集合中的索引为1的结点, 然后删除集合中索引为0的结点 ----> 如果我们先删除索引为0的结点然后删除集合中索引为1的结点这个时候就会出现索引越界异常, 那么为什么会出现索引越界异常?
- 因为这个时候我们删除元素之前集合中就只剩下了两个元素, 这个时候我们通过索引删除元素, 这个时候如果我们先删除索引为0的结点, 那么删除了这个索引为1的结点之后集合中就只剩下了索引为0的一个结点, 这个时候我们如果还是删除索引为1的结点, 这个时候就会出现一个索引越界异常
- 对于这种细节问题我们一定要去深入的研究和学习, 往往遇到一个检查不出来的问题的时候就说明是遇到了短板,就更要去检查出来, 做到查缺补漏