haffman哈夫曼树——贪心算法(java)

接下来学习了哈夫曼树,总结一下哈夫曼树:

了解Huffman算法之前,我们先介绍一下一颗树的构造价值:

构造价值指的是,在一个树当中,如果有n层,那么每层的系数为123……n,然后吧每个叶子节点的构造价值乘以系数,总和就是这棵树的构造总价值,这也就叫做哈夫曼树的构造价值,我们看一个例子:

对于这一棵树,我们计算一下他的哈夫曼构造价值:

《haffman哈夫曼树——贪心算法(java)》

这里叶子节点一共有3个:61317

所以价值等于6*2 + 13 *3 + 17 *3 = 102

同样是这3个叶子节点,我们换一种树的构造法:

 《haffman哈夫曼树——贪心算法(java)》

这种情况下,哈夫曼构造价值 = 17*2 + 6*3 + 13*3 = 91.构造价值比上一种要小。

        所以我们发现,只要把数值大的叶子节点,放在更低的层次,就可以使总构造价值更小。这就是哈夫曼树,那么如何构造这棵树呢?

        哈夫曼树、哈夫曼编码之类的都是一个思想,就是使用贪心法,每次都选取当前最小的两个树加起来,最后吧所有的东西构造成一课树。

我们用一组数据来举例子:

假如有这么6个节点,每个节点有一定的构造价值

 《haffman哈夫曼树——贪心算法(java)》

那么就有对应的两个数组:

int f[] =    { 45  ,   13   ,  12  ,  16  ,  9  ,  5  }

char d[] = {‘a’      ,‘b’,     ‘c’,     ‘d’,  ‘e’,   ‘f’  };

我们首先解决一下这个问题的先决条件,构造一颗树,但是二叉树(BinaryTree)在api中没有显式的定义,需要我们自己定义。下面写一下这里的需要用到的树的功能:这里的树重写了comparable接口的compareto方法,用来后续的键值比较

public class BinaryTree implements Comparable<BinaryTree>{
	int key;
	char data;
	BinaryTree left;
	BinaryTree right;
	public BinaryTree() {
		// TODO 自动生成的构造函数存根
	}
	public BinaryTree(int k, char d, BinaryTree l, BinaryTree r) {
		this.key = k;
		this.data = d;
		this.left = l;
		this.right = r;
	}
	public String toString() {
		return data+"," + key + ";";
	}
	@Override
	public int compareTo(BinaryTree x) {
		// TODO 自动生成的方法存根
		if (key < x.key) {
			return -1;
		}
		if (key > x.key) {
			return 1;
		}
		return 0;
	}
	
	//中序遍历
	public void inOrder() {
		if (left != null) {
			left.inOrder();
		}
		System.out.println(toString());
		if (right != null) {
			right.inOrder();
		}
	}

}

接下来我们实现哈夫曼树的构造:

思路是这样的,我们选最小的两片叶子,然后吧他合并起来的值当成一个新的叶子,加进里面,然后再选两个最小的值合并起来,然后重复知道最后只有两个值,然后合并,就构造成了一颗树,如图:

先选59,拼成一个14的树

 《haffman哈夫曼树——贪心算法(java)》

 

然后选1213,评成25的树

 《haffman哈夫曼树——贪心算法(java)》

然后选1416,评成30

 《haffman哈夫曼树——贪心算法(java)》

再选2530,评成一个65的树

 《haffman哈夫曼树——贪心算法(java)》

最后吧4555拼起来,就构成了哈夫曼树:

 《haffman哈夫曼树——贪心算法(java)》


代码解决方案:java里有一个东西叫做优先队列(PriorityQueue),优先队列可以理解为一个可以排序的队列,优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。详见api文档搜索PriorityQueue

通过优先队列,我们把数据都放进去,然后通过优先队列来取数,这样就可以保证每次取得最小的两个,然后我们在构造成一颗树,下面看代码:

public class BinaryTree implements Comparable<BinaryTree>{
	int key;
	char data;
	BinaryTree left;
	BinaryTree right;
	public BinaryTree() {
		// TODO 自动生成的构造函数存根
	}
	public BinaryTree(int k, char d, BinaryTree l, BinaryTree r) {
		this.key = k;
		this.data = d;
		this.left = l;
		this.right = r;
	}
	public String toString() {
		return data+"," + key + ";";
	}
	@Override
	public int compareTo(BinaryTree x) {
		// TODO 自动生成的方法存根
		if (key < x.key) {
			return -1;
		}
		if (key > x.key) {
			return 1;
		}
		return 0;
	}
	
	//中序遍历
	public void inOrder() {
		if (left != null) {
			left.inOrder();
		}
		System.out.println(toString());
		if (right != null) {
			right.inOrder();
		}
	}

}

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/likunkun__/article/details/80258515
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞