最小优先队列实现赫夫曼树 贪心策略

使用 最小优先队列存放要编码的key,和合并之后内部节点,注意最小优先队列,获得最小值时会把最小是删掉,下面是java实现。

package Algorithms;
class MinQueue<T extends Comparable<? super T>>{
	int heapSize;
	T[] heap;
	int capacity;
	public MinQueue(int capaticty)
	{
		this.capacity=capaticty;
		heapSize=0;
		//因为泛型擦除,泛型不能实例化,只能创建Object,然后再强制类型转换为数组
		//这里不能使用new Object 因为没有comparable,要使用直接父类comparable
		heap=(T[])new Comparable[capaticty];
	}
	/**
	 * 最小优先队列的维护
	 */
	public  void heapfy(int i)
	{
		if(i>=heapSize&&i<0)
		{
			System.out.println("要维护的节点错误");
			return ;
		}
		int left=2*i+1;
		int right=2*i+2;
		int min=i;
		//寻找i与其两个孩子的最小值
		if(left<heapSize&&heap[left].compareTo(heap[min])==-1)
			min=left;
		if(right<heapSize&&heap[right].compareTo(heap[min])==-1)
			min=right;
		if(min!=i)
		{
		    T temp=heap[min];
		    heap[min]=heap[i];
		    heap[i]=temp;
		    heapfy(min);
		}
	}
	/**
	 * 建立最小优先队列
	 */
	public void insert(T ele)
	{
		if(heapSize>=capacity)
		{
			System.out.println("最小优先队列已满!");
			return ;
		}
		heap[heapSize]=ele;
		heapSize++;
		int child=heapSize-1;
		int parent=(heapSize/2)-1;
		while(parent>=0&&heap[parent].compareTo(heap[child])>1)
		{
			T temp=heap[parent];
			heap[parent]=heap[child];
			heap[child]=temp;
			child=parent;
			parent=(child+1)/2-1;
		}
	}
	public T extractMin()
	{
		if(heapSize<=0)
		{
			System.out.println("没有元素");
			return null;
		}
		T min=heap[0];
		heapSize--;
		heap[0]=heap[heapSize];
		heap[heapSize]=min;
		heapfy(0);
		return min;
	}
}
public class HumanCode {
	public static class Node implements Comparable<Node>{
		public int freq;//字符出现的频率
		public char key;
		public Node left;
		public Node right;
		public Node (int freq,char key,Node left,Node right)
		{
			this.freq=freq;
			this.key=key;
			this.left=left;
			this.right=right;
		}
		@Override
		public int compareTo(Node o) {
			if(this.freq>o.freq)
				return 1;
			else if(this.freq==o.freq)
			    return 0;
			else
				return -1;
		}
	}
	/**
	 * @param q
	 * 构建哈夫曼树  具有n个关键字要进行n-1次合并
	 */
	public Node huffman(MinQueue<Node> q)
	{
		int n=q.heapSize;
		for(int i=1;i<n;i++)
		{
    		Node min1=q.extractMin();
	    	Node min2=q.extractMin();
		    int freq1=min1.freq;
    		int freq2=min2.freq;
	    	int freq=freq1+freq2;
    		Node node=new HumanCode.Node(freq, ' ', min1, min2);
    		q.insert(node);
    	}
		return q.extractMin();
	}
	public void huffmanAccess(Node node,String a)
	{
		if(node!=null)
		{
			if(node.key!=' ')
			System.out.print(a+" ");
			huffmanAccess(node.left,a+"0");
			huffmanAccess(node.right,a+"1");
		}
	}
	public static void main(String []args)
	{
		HumanCode hu=new HumanCode();
		MinQueue<Node>q=new MinQueue<Node>(6);

	     Node node1=new HumanCode.Node(5, 'f', null, null);
	     Node node2=new HumanCode.Node(9, 'e', null, null);
	     Node node3=new HumanCode.Node(12, 'c', null, null);
	     Node node4=new HumanCode.Node(13, 'b', null, null);
	     Node node5=new HumanCode.Node(16, 'd', null, null);
	     Node node6=new HumanCode.Node(45, 'a', null, null);
	     q.insert(node1);
	     q.insert(node2);
	     q.insert(node3);
	     q.insert(node4);
	     q.insert(node5);
	     q.insert(node6);
	     Node node=hu.huffman(q);
	     hu.huffmanAccess(node,"");
	}
}
时间: 2024-10-05 16:23:14

最小优先队列实现赫夫曼树 贪心策略的相关文章

使用优先队列构建赫夫曼树

关于赫夫曼编码和赫夫曼树的相关知识可参考之前两篇文章(由二叉树构造赫夫曼树.赫夫曼编码).本文介绍另一种构建赫夫曼树的方式,采用优先队列. 步骤: 1.首先我们需要统计不同字符出现的次数.一个字符出现的次数越多,说明其优先级越高,其赫夫曼编码应该越短: 2.将待编码的字符(即带权节点)存入优先级队列,优先级即字符出现的次数: 3.不断迭代队列,直到队列中剩下一个元素(即根节点).每次从队列中取出两个优先级最小的元素(优先级队列中的元素是按照节点优先级顺序排列的),然后生成一个新的赫夫曼树节点,节

赫夫曼树JAVA实现及分析

一,介绍 1)构造赫夫曼树的算法是一个贪心算法,贪心的地方在于:总是选取当前频率(权值)最低的两个结点来进行合并,构造新结点. 2)使用最小堆来选取频率最小的节点,有助于提高算法效率,因为要选频率最低的,要么用排序,要么用堆.用堆的话,出堆的复杂度为O(logN),而向堆中插入一个元素的平均时间复杂度为O(1),在构建赫夫曼树的过程中,新生成的结点需要插入到原来的队列中,故用堆来维持这种顺序比排序算法要高效地多. 二,赫夫曼算法分析 ①用到的数据结构分析 首先需要构造一棵赫夫曼树,因此需要二叉链

经典算法题每日演练——第十三题 赫夫曼树

原文:经典算法题每日演练--第十三题 赫夫曼树 赫夫曼树又称最优二叉树,也就是带权路径最短的树,对于赫夫曼树,我想大家对它是非常的熟悉,也知道它的应用场景, 但是有没有自己亲手写过,这个我就不清楚了,不管以前写没写,这一篇我们来玩一把. 一:概念 赫夫曼树里面有几个概念,也是非常简单的,先来看下面的图: 1. 基础概念 <1>  节点的权: 节点中红色部分就是权,在实际应用中,我们用“字符”出现的次数作为权. <2>  路径长度:可以理解成该节点到根节点的层数,比如:“A”到根节点

哈夫曼树——贪心

哈夫曼树——贪心 哈夫曼树:给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree).哈夫曼树是带权路径长度                 最短的树,权值较大的结点离根较近. 此类题目一般求算哈夫曼树路径总值,利用贪心选择性质每次从队头取出两个边权和最小的树合并成新树入队(优先队列,保证队首元素最小),每次记录新树权值,当队内只剩一棵树时结束算法: priority_queue<long long,vector

由二叉树构造赫夫曼树

赫夫曼树: 假设有n个权值{w1,w2,w3....},试构造一棵具有n个叶子节点的二叉树,每个叶子节点带权为wi,则其中带权路径长度最小的二叉树称为最优二叉树或者叫赫夫曼树. 构造赫夫曼树: 假设有n个权值,则构造出的赫夫曼树有n个叶子节点,n个权值分别设置为w1,w2,....wn,则赫夫曼树的构造规则为: 1.将w1,w2...看成是有n棵树的森林: 2.在森林中选择两个根节点的权值最小的树合并,作为一棵新树的左右子树,且新树的根节点权值为其左右子树根节点权值之和: 3.从森林中删除选取的

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

flyfish 2015-8-1 Huffman tree因为翻译不同所以有其他的名字 赫夫曼树.霍夫曼树.哈夫曼树 定义引用自严蔚敏<数据结构> 路径 从树中一个结点到另一个结点之间的分支构成两个结点之间的路径. 路径长度 路径上的分支数目称作路径长度. 树的路径长度 树的路径长度就是从根节点到每一结点的路径长度之和. 结点的带权路径长度 结点的带权路径长度就是从该结点到根节点之间的路径长度与结点上权的乘积. 树的带权路径长度 树的带权路径长度就是树中所有叶子结点的带权路径长度之和,通常记做

13.赫夫曼树及其应用

一.赫夫曼树定义与原理 1.路径长度:从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径的长度; 2.树的路径长度:即从树根到每一结点的路径长度之和; 3.结点的带权的路径长度:即从该结点从到树根之间的路径长度与结点上权的乘积; 4.树的带权路径长度:为树中所有叶子结点的带权路径长度之和; 5.赫夫曼树定义:假设有n个权值{w1,w2,....,wn},构造一颗有n个叶子结点的二叉树,每个叶子结点带权wk,每个叶子的路径长度为lk,则其中带权路径长度WPL最小的

赫夫曼树(最优二叉树)

.在选择最小s1s2的时候少了一个空语句分号..调试了好久..坑爹. 这个是最优的编码策略能达到最少的编码 1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<math.h> 5 #include<queue> 6 #include<algorithm> 7 using namespace std; 8 typedef struct 9 {

【数据结构】赫夫曼树的实现和模拟压缩(C++)

赫夫曼(Huffman)树,由发明它的人物命名,又称最优树,是一类带权路径最短的二叉树,主要用于数据压缩传输. 赫夫曼树的构造过程相对比较简单,要理解赫夫曼数,要先了解赫夫曼编码. 对一组出现频率不同的字符进行01编码,如果设计等长的编码方法,不会出现混淆的方法,根据规定长度的编码进行翻译,有且只有一个字符与之对应.比如设计两位编码的方法,A,B,C,D字符可以用00-11来表示,接收方只要依次取两位编码进行翻译就可以得出原数据,但如果原数据只由n个A组成的,那发出的编码就是2n个0组成,这样的