<?php
namespace Test; use Iterator;
use ArrayAccess;
use Exception; // 叶子结点或者连接结点的基类
class HuffmanBase
{
protected $weight; // 权重
protected $parent; public function setParent($parent)
{
$this->parent = $parent;
} public function getWeight()
{
return $this->weight;
} public function getParent()
{
return $this->parent;
}
} // 叶子结点
class HuffmanLeafNode extends HuffmanBase
{
protected $code; // 需要编码的字母 public function __construct($weight,$code,$parent = null)
{
if(!is_int($weight) || $weight <= 0 || is_null($code))
{
throw new Exception('Param is error!' .__FILE__.__LINE__);
}
$this->weight = abs($weight);
$this->code = $code;
$this->parent = $parent;
} public function getCode()
{
return $this->code;
}
} // 连接结点
class HuffmanJoinNode extends HuffmanBase
{
protected $lChild;
protected $rChild; public function __construct($weight = 0,$lChild = null,$rChild = null)
{
$this->weight = $weight;
$this->rChild = $rChild;
$this->lChild = $lChild;
} public function setWeight($leftWeight,$rightWeight)
{
if(!is_int($this->rChild) || !is_int($this->lChild))
{
throw new \Exception("Please initialize the left child or the right child!\n");
}
$this->weight = $leftWeight + $rightWeight;
} public function setChild($child,$leftOrRight)
{
if('left' == $leftOrRight)
{
$this->lChild = $child;
}
elseif('right' == $leftOrRight)
{
$this->rChild = $child;
}
else
{
throw new \Exception("Please input 'left' or 'right' to leftOrRight!\n");
}
} public function getChild($leftOrRight)
{
if('left' == $leftOrRight)
{
return $this->lChild;
}
elseif('right' == $leftOrRight)
{
return $this->rChild;
}
else
{
throw new \Exception("Please input 'left' or 'right' to leftOrRight!\n");
}
}
} // 哈夫曼树
class HuffmanTree implements \ArrayAccess,\Iterator
{
protected $nodes = array(); public function &getAllNodes()
{
return $this->nodes;
} public function offsetExists($offset)
{
// TODO: Implement offsetExists() method.
return isset($this->nodes[$offset]);
} public function offsetGet($offset)
{
// TODO: Implement offsetGet() method.
if(isset($this->nodes[$offset]))
{
return $this->nodes[$offset];
}
else
{
return null;
}
} public function offsetSet($offset,$value)
{
// TODO: Implement offsetSet() method.
if(!($value instanceof HuffmanBase))
{
throw new Exception('Param is error!' .__FILE__.__LINE__);
} if(is_null($offset))
{
$this->nodes[] = $value;
}
else
{
$this->nodes[$offset] = $value;
}
} public function offsetUnset($offset)
{
// TODO: Implement offsetUnset() method.
unset($this->nodes[$offset]);
} public function current()
{
// TODO: Implement current() method.
return current($this->nodes);
} public function key()
{
// TODO: Implement key() method.
return key($this->nodes);
} public function next()
{
// TODO: Implement next() method.
next($this->nodes);
} public function rewind()
{
// TODO: Implement rewind() method.
reset($this->nodes);
} public function valid()
{
// TODO: Implement valid() method.
return $this->offsetExists(key($this->nodes));
} public function length()
{
return count($this->nodes);
}
} // 从[$left,$right]区间选择parent=0并且weight最小的两个结点,其序号分别为$minNode1,$minNode2;
function selectTwoMinWeightNode(HuffmanTree &$huffmanTree,$left,$right,&$minNode1,&$minNode2)
{
$left = abs($left);
$right = abs($right); if(!is_int($left) || !is_int($right) || $left == $right)
{
throw new Exception('Param is error!' .__FILE__.__LINE__);
} if($left > $right)
{
$tmp = $left;
$left = $right;
$right = $tmp;
} $nodes = $huffmanTree->getAllNodes();
if(!isset($nodes[$right]))
{
throw new Exception('Over the array index!'.__FILE__.__LINE__);
} $tmp = array();
for($i = $left;$i <= $right; ++$i)
{
$huffmanNode = $huffmanTree[$i];
if(!is_null($huffmanNode->getParent()))
{
continue;
}
$tmp[$i] = $huffmanNode->getWeight();
} if(count($tmp) <= 1)
{
throw new Exception('Not enough number!'.__FILE__.__LINE__);
}
asort($tmp,SORT_NUMERIC);
$t = array_keys($tmp);
$minNode1 = $t[0];
$minNode2 = $t[1];
} // (编码 => 权重)
$nodes = array('A' => 3, 'B' => 4, 'C' => 7, 'D' => 10); $huffmanTree = new HuffmanTree(); // 初始化哈夫曼树的叶子结点
foreach($nodes as $code => $weight)
{
$huffmanNode = new HuffmanLeafNode($weight,$code);
$huffmanTree[] = $huffmanNode;
} $leafCount = $huffmanTree->length(); // 叶子结点的数量(大于1的值)
$nodeCount = 2 * $leafCount -1 ; // 哈夫曼树结点的数量 // 初始化哈夫曼树的非叶子结点(如果编译器未优化,--$i应该是比$i++效率高点的)
for($i = $nodeCount - $leafCount;$i >= 1; --$i)
{
$huffmanNode = new HuffmanJoinNode();
$huffmanTree[] = $huffmanNode;
} // 建立哈夫曼树
for($i = $leafCount;$i < $nodeCount; ++$i)
{
selectTwoMinWeightNode($huffmanTree,0,$i-1,$minNode1,$minNode2);
$huffmanNode1 = $huffmanTree[$minNode1];
$huffmanNode2 = $huffmanTree[$minNode2];
$huffmanNode1->setParent($i);
$huffmanNode2->setParent($i);
$huffmanTree[$i]->setChild($minNode1,'left');
$huffmanTree[$i]->setChild($minNode2,'right');
$huffmanTree[$i]->setWeight($huffmanNode1->getWeight(),$huffmanNode2->getWeight());
} // 从叶子到根的遍历,得到字母的编码
$huffmanCode = array();
for($i = 0;$i < $leafCount; ++$i)
{
$leafNode = $huffmanTree[$i];
$code = $leafNode->getCode();
$reverseCode = array();
for($c = $i,$pi = $leafNode->getParent();!is_null($pi);$pi = $huffmanTree[$pi]->getParent())
{
$huffmanNode = $huffmanTree[$pi];
if($huffmanNode->getChild('left') === $c)
{
$reverseCode[] = 0;
}
elseif($huffmanNode->getChild('right') === $c)
{
$reverseCode[] = 1;
}
else
{
throw new Exception('Something error happened!' .__FILE__.__LINE__);
}
$c = $pi;
}
$huffmanCode[$code] = array_reverse($reverseCode);
} foreach($huffmanCode as $key => $value)
{
$s = implode(',',$value);
echo $key. " : " .$s ."\n";
}

运行结果:

运行环境:

ArrayAccess  :(PHP 5 >= 5.0.0, PHP 7)

PHP 哈夫曼的实现的更多相关文章

  1. 哈夫曼(huffman)树和哈夫曼编码

    哈夫曼树 哈夫曼树也叫最优二叉树(哈夫曼树) 问题:什么是哈夫曼树? 例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80-89分: B,70-79分: C,60-69分: D,<60 ...

  2. (哈夫曼树)HuffmanTree的java实现

    参考自:http://blog.csdn.net/jdhanhua/article/details/6621026 哈夫曼树 哈夫曼树(霍夫曼树)又称为最优树. 1.路径和路径长度在一棵树中,从一个结 ...

  3. 数据结构之C语言实现哈夫曼树

    1.基本概念 a.路径和路径长度 若在一棵树中存在着一个结点序列 k1,k2,……,kj, 使得 ki是ki+1 的双亲(1<=i<j),则称此结点序列是从 k1 到 kj 的路径. 从 ...

  4. (转载)哈夫曼编码(Huffman)

    转载自:click here 1.哈夫曼编码的起源: 哈夫曼编码是 1952 年由 David A. Huffman 提出的一种无损数据压缩的编码算法.哈夫曼编码先统计出每种字母在字符串里出现的频率, ...

  5. C++哈夫曼树编码和译码的实现

    一.背景介绍: 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的 ...

  6. 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  7. HDU2527 哈夫曼编码

    Safe Or Unsafe Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  8. *HDU1053 哈夫曼编码

    Entropy Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  9. YTU 3027: 哈夫曼编码

    原文链接:https://www.dreamwings.cn/ytu3027/2899.html 3027: 哈夫曼编码 时间限制: 1 Sec  内存限制: 128 MB 提交: 2  解决: 2 ...

  10. 哈夫曼树---POJ3253

    http://poj.org/problem?id=3253 这就是 最典型的哈夫曼树的题型,我们就根据这道题学习一下哈夫曼树 这是最开始我们把21据下来之后我们据下8,然后再据下5得到34,可以看出 ...

随机推荐

  1. 大数据平台搭建 - cdh5.11.1 - spark源码编译及集群搭建

    一.spark简介 Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎,Spark 是一种与 hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些有用的不同 ...

  2. moment实现计算两个时间的差值

    var m1 = moment('2018-08-14 11:00:00'), m2 = moment('2018-08-14 12:10:00'); console.log(m1)console.l ...

  3. 括号匹配(c语言实现)

    ⭐ 我的网站: www.mengyingjie.com ⭐ 1要求 编写程序检查该字符串的括号是否成对出现,而且不能交叉出现. 输入: 一个字符串,里边可能包含"()"." ...

  4. FlagCounter被封杀?自己实现一个简单的多国访客计数器

    起因 前段时间发现博客右边的FlagCounter计数器突然没了,又看到了博客园封杀了FlagCounter的消息,有点摸不着头脑.于是上FlagCounter的网站上看了一眼,发现最近出现的来自新国 ...

  5. 【面试题】Java常见面试题

    集合与数组? 数组:(可以存储基本数据类型)是用来存储对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用 集合:(只能存储对象,对象类型可以不一样)集合的长度可变,可在多数情况下使用 ...

  6. 4款黑科技级别的宝藏APP,能够轻松满足你的多种需求,请低调收藏

    有没有这样几款软件,在你每次一换新手机的时候就会立刻重新安装下来,感觉自己已经完全离不开它们?今天就来给大家分享几个非常好用的APP. 一.小羊搜搜 在生活中人人都有自己的爱好,无论你是喜欢影视.小说 ...

  7. # C# 中的Task创建指南

    本文还处于草稿阶段,难免还有错误修改改正,逻辑还不是很清晰,笔者会努力完善,长期更新! [0000] 前言 标题起得有些"大",意在集大家的力量,总结出来一份关于Task相对&qu ...

  8. Android蓝牙低功耗(BLE)模块设计

    在阅读这篇文章之前你应该对GATT和Android蓝牙框架有一定的了解.这里不会向你解释Service.Characteristics等蓝牙知识.这里只是我写下我对Android Ble的再次封装来适 ...

  9. springboot启动后自动退出

    有时新建的springboot启动后自动退出运行,如图所示: 此种情况大都数是因为pom文件加入了tomcat的依赖,与springboot内嵌的tomcat冲突导致,所以只需将pom文件中的tomc ...

  10. 冒泡排序--JavaScript描述

    相信凡是编程入门的都接触过冒泡排序算法,排序算法在编程中经常用到. 1. code /** * 冒泡排序 * 1.比较的轮数等于总数 - 1 * 2.比较次数等于要比较的个数 - 1 * --比较从第 ...