数据结构(十二)——赫夫曼树

给定 n 个权值作为 n 个叶子结点, 构造一棵二叉树, 若该树的带权路径长度(wpl)达到最小, 称这样的二叉树为最优二叉树, 也称为霍夫曼树(Huffman Tree)。

在正式介绍霍夫曼树之前,先介绍一下带权路径长度WPL(weighted path
length):树的带权路径长度规定为所有叶子结点的带权路径长度之和, 记为 WPL ,权值越大的结点离根结点越近的二叉树才是最优二叉树。

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

结点的权及带权路径长度: 若将树中结点赋给一个有着某种含义的数值, 则这个数值称为该结点的权。 结点的带权路径长度为: 从根结点到该结点之间的路径长度与该结点的权的乘积

比如下图所示三棵树的WPL分别是
在这里插入图片描述
规定的4个叶子节点,其权值分别是13,7,8,3,其wpl最小是59,WPL最小的就是赫夫曼树,其特点是权值较大的节点离根节点较近

实现赫夫曼树的步骤

  1. 从小到大进行排序, 将每一个数据, 每个数据都是一个节点 , 每个节点可以看成是一颗最简单的二叉树
  2. 取出根节点权值最小的两颗二叉树
  3. 组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和
  4. 再将这颗新的二叉树, 以根节点的权值大小 再次排序, 不断重复1-4的步骤, 直到数列中, 所有的数据都被处理, 就得到一颗赫夫曼树

赫夫曼树代码实现:

public class HuffmanTreeDemo {

	public static void main(String[] args) {
		int[] arr = {13, 7, 8, 3};
		Node root = creatHuffmanTree(arr);

		//
		preOrder(root);
	}
	
	public static void preOrder(Node root){
		if(root != null) {
			root.preOrder();
		}else {
			System.out.println("null");
		}
	}
	
	//创建赫夫曼树的方法
	public static Node creatHuffmanTree(int[] arr) {
		ArrayList<Node> nodes = new ArrayList<Node>();
		for(int value : arr){
			nodes.add(new Node(value));
		}
		
		while(nodes.size() > 1) {
			//排序,从小到大
			Collections.sort(nodes);
			System.out.println(nodes);
			
			//取出最小的节点
			Node leftNode = nodes.get(0);
			//取出第二小的节点
			Node rightNode = nodes.get(1);
			//构建新的
			Node parent = new Node(leftNode.value + rightNode.value);
			parent.left = leftNode;
			parent.right = rightNode;
			
			//从ArrayList中删除旧的加入新的
			nodes.remove(leftNode);
			nodes.remove(rightNode);
			nodes.add(parent);
		}
		
		//返回赫夫曼树的根节点
		return nodes.get(0);
	}

}

//创建节点类
//为了让Node对象支持排序 Collection集合排序
//让Node实现Comparable接口
class Node implements Comparable<Node>{
	int value;//权重
	Node left;//指向左子节点
	Node right;//指向右子节点
	
	//前序遍历	测试用
	public void preOrder() {
		System.out.println(this);
		if(this.left != null) {
			this.left.preOrder();
		}
		if(this.right != null) {
			this.right.preOrder(); 
		}
	}
	
	public Node(int value) {
		this.value = value;
	}

	@Override
	public String toString() {
		return "Node [value=" + value + "]";
	}

	@Override
	public int compareTo(Node o) {
		// TODO Auto-generated method stub
		
		//表示从小到大进行排序	 
		return this.value - o.value;
	}
	
	
	
}

实现结果检验,使用前序遍历,可以验证结果正确
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于数据结构赫夫曼树的C语言实现,可以分为以下几个步骤: 1. 定义赫夫曼树的结构体 ``` typedef struct HuffmanTreeNode { int weight; // 权值 int parent; // 父节点下标 int leftChild; // 左孩子下标 int rightChild; // 右孩子下标 } HuffmanTreeNode; ``` 2. 构建赫夫曼树 ``` void createHuffmanTree(HuffmanTreeNode *huffmanTree, int n) { int i, j, min1, min2; for (i = 0; i < 2 * n - 1; i++) { huffmanTree[i].parent = -1; huffmanTree[i].leftChild = -1; huffmanTree[i].rightChild = -1; } for (i = 0; i < n; i++) { scanf("%d", &huffmanTree[i].weight); } for (i = 0; i < n - 1; i++) { min1 = min2 = INT_MAX; int node1, node2; for (j = 0; j < n + i; j++) { if (huffmanTree[j].parent == -1 && huffmanTree[j].weight < min1) { min2 = min1; node2 = node1; min1 = huffmanTree[j].weight; node1 = j; } else if (huffmanTree[j].parent == -1 && huffmanTree[j].weight < min2) { min2 = huffmanTree[j].weight; node2 = j; } } huffmanTree[node1].parent = n + i; huffmanTree[node2].parent = n + i; huffmanTree[n + i].weight = min1 + min2; huffmanTree[n + i].leftChild = node1; huffmanTree[n + i].rightChild = node2; } } ``` 3. 编码 ``` void huffmanEncoding(HuffmanTreeNode *huffmanTree, int n) { char **huffmanCode = (char **) malloc(n * sizeof(char *)); char *code = (char *) malloc(n * sizeof(char)); code[n - 1] = '\0'; int i, j, c, p; for (i = 0; i < n; i++) { huffmanCode[i] = (char *) malloc(n * sizeof(char)); for (j = 0; j < n; j++) { huffmanCode[i][j] = '\0'; } c = i; p = huffmanTree[c].parent; while (p != -1) { if (huffmanTree[p].leftChild == c) { code[--n] = '0'; } else { code[--n] = '1'; } c = p; p = huffmanTree[c].parent; } strcpy(huffmanCode[i], &code[n]); } for (i = 0; i < n; i++) { printf("%d的哈夫曼编码为:%s\n", huffmanTree[i].weight, huffmanCode[i]); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值