1. <?php
  2. namespace Test;
  3.  
  4. use Iterator;
  5. use ArrayAccess;
  6. use Exception;
  7.  
  8. // 叶子结点或者连接结点的基类
  9. class HuffmanBase
  10. {
  11. protected $weight; // 权重
  12. protected $parent;
  13.  
  14. public function setParent($parent)
  15. {
  16. $this->parent = $parent;
  17. }
  18.  
  19. public function getWeight()
  20. {
  21. return $this->weight;
  22. }
  23.  
  24. public function getParent()
  25. {
  26. return $this->parent;
  27. }
  28. }
  29.  
  30. // 叶子结点
  31. class HuffmanLeafNode extends HuffmanBase
  32. {
  33. protected $code; // 需要编码的字母
  34.  
  35. public function __construct($weight,$code,$parent = null)
  36. {
  37. if(!is_int($weight) || $weight <= 0 || is_null($code))
  38. {
  39. throw new Exception('Param is error!' .__FILE__.__LINE__);
  40. }
  41. $this->weight = abs($weight);
  42. $this->code = $code;
  43. $this->parent = $parent;
  44. }
  45.  
  46. public function getCode()
  47. {
  48. return $this->code;
  49. }
  50. }
  51.  
  52. // 连接结点
  53. class HuffmanJoinNode extends HuffmanBase
  54. {
  55. protected $lChild;
  56. protected $rChild;
  57.  
  58. public function __construct($weight = 0,$lChild = null,$rChild = null)
  59. {
  60. $this->weight = $weight;
  61. $this->rChild = $rChild;
  62. $this->lChild = $lChild;
  63. }
  64.  
  65. public function setWeight($leftWeight,$rightWeight)
  66. {
  67. if(!is_int($this->rChild) || !is_int($this->lChild))
  68. {
  69. throw new \Exception("Please initialize the left child or the right child!\n");
  70. }
  71. $this->weight = $leftWeight + $rightWeight;
  72. }
  73.  
  74. public function setChild($child,$leftOrRight)
  75. {
  76. if('left' == $leftOrRight)
  77. {
  78. $this->lChild = $child;
  79. }
  80. elseif('right' == $leftOrRight)
  81. {
  82. $this->rChild = $child;
  83. }
  84. else
  85. {
  86. throw new \Exception("Please input 'left' or 'right' to leftOrRight!\n");
  87. }
  88. }
  89.  
  90. public function getChild($leftOrRight)
  91. {
  92. if('left' == $leftOrRight)
  93. {
  94. return $this->lChild;
  95. }
  96. elseif('right' == $leftOrRight)
  97. {
  98. return $this->rChild;
  99. }
  100. else
  101. {
  102. throw new \Exception("Please input 'left' or 'right' to leftOrRight!\n");
  103. }
  104. }
  105. }
  106.  
  107. // 哈夫曼树
  108. class HuffmanTree implements \ArrayAccess,\Iterator
  109. {
  110. protected $nodes = array();
  111.  
  112. public function &getAllNodes()
  113. {
  114. return $this->nodes;
  115. }
  116.  
  117. public function offsetExists($offset)
  118. {
  119. // TODO: Implement offsetExists() method.
  120. return isset($this->nodes[$offset]);
  121. }
  122.  
  123. public function offsetGet($offset)
  124. {
  125. // TODO: Implement offsetGet() method.
  126. if(isset($this->nodes[$offset]))
  127. {
  128. return $this->nodes[$offset];
  129. }
  130. else
  131. {
  132. return null;
  133. }
  134. }
  135.  
  136. public function offsetSet($offset,$value)
  137. {
  138. // TODO: Implement offsetSet() method.
  139. if(!($value instanceof HuffmanBase))
  140. {
  141. throw new Exception('Param is error!' .__FILE__.__LINE__);
  142. }
  143.  
  144. if(is_null($offset))
  145. {
  146. $this->nodes[] = $value;
  147. }
  148. else
  149. {
  150. $this->nodes[$offset] = $value;
  151. }
  152. }
  153.  
  154. public function offsetUnset($offset)
  155. {
  156. // TODO: Implement offsetUnset() method.
  157. unset($this->nodes[$offset]);
  158. }
  159.  
  160. public function current()
  161. {
  162. // TODO: Implement current() method.
  163. return current($this->nodes);
  164. }
  165.  
  166. public function key()
  167. {
  168. // TODO: Implement key() method.
  169. return key($this->nodes);
  170. }
  171.  
  172. public function next()
  173. {
  174. // TODO: Implement next() method.
  175. next($this->nodes);
  176. }
  177.  
  178. public function rewind()
  179. {
  180. // TODO: Implement rewind() method.
  181. reset($this->nodes);
  182. }
  183.  
  184. public function valid()
  185. {
  186. // TODO: Implement valid() method.
  187. return $this->offsetExists(key($this->nodes));
  188. }
  189.  
  190. public function length()
  191. {
  192. return count($this->nodes);
  193. }
  194. }
  195.  
  196. // 从[$left,$right]区间选择parent=0并且weight最小的两个结点,其序号分别为$minNode1,$minNode2;
  197. function selectTwoMinWeightNode(HuffmanTree &$huffmanTree,$left,$right,&$minNode1,&$minNode2)
  198. {
  199. $left = abs($left);
  200. $right = abs($right);
  201.  
  202. if(!is_int($left) || !is_int($right) || $left == $right)
  203. {
  204. throw new Exception('Param is error!' .__FILE__.__LINE__);
  205. }
  206.  
  207. if($left > $right)
  208. {
  209. $tmp = $left;
  210. $left = $right;
  211. $right = $tmp;
  212. }
  213.  
  214. $nodes = $huffmanTree->getAllNodes();
  215. if(!isset($nodes[$right]))
  216. {
  217. throw new Exception('Over the array index!'.__FILE__.__LINE__);
  218. }
  219.  
  220. $tmp = array();
  221. for($i = $left;$i <= $right; ++$i)
  222. {
  223. $huffmanNode = $huffmanTree[$i];
  224. if(!is_null($huffmanNode->getParent()))
  225. {
  226. continue;
  227. }
  228. $tmp[$i] = $huffmanNode->getWeight();
  229. }
  230.  
  231. if(count($tmp) <= 1)
  232. {
  233. throw new Exception('Not enough number!'.__FILE__.__LINE__);
  234. }
  235. asort($tmp,SORT_NUMERIC);
  236. $t = array_keys($tmp);
  237. $minNode1 = $t[0];
  238. $minNode2 = $t[1];
  239. }
  240.  
  241. // (编码 => 权重)
  242. $nodes = array('A' => 3, 'B' => 4, 'C' => 7, 'D' => 10);
  243.  
  244. $huffmanTree = new HuffmanTree();
  245.  
  246. // 初始化哈夫曼树的叶子结点
  247. foreach($nodes as $code => $weight)
  248. {
  249. $huffmanNode = new HuffmanLeafNode($weight,$code);
  250. $huffmanTree[] = $huffmanNode;
  251. }
  252.  
  253. $leafCount = $huffmanTree->length(); // 叶子结点的数量(大于1的值)
  254. $nodeCount = 2 * $leafCount -1 ; // 哈夫曼树结点的数量
  255.  
  256. // 初始化哈夫曼树的非叶子结点(如果编译器未优化,--$i应该是比$i++效率高点的)
  257. for($i = $nodeCount - $leafCount;$i >= 1; --$i)
  258. {
  259. $huffmanNode = new HuffmanJoinNode();
  260. $huffmanTree[] = $huffmanNode;
  261. }
  262.  
  263. // 建立哈夫曼树
  264. for($i = $leafCount;$i < $nodeCount; ++$i)
  265. {
  266. selectTwoMinWeightNode($huffmanTree,0,$i-1,$minNode1,$minNode2);
  267. $huffmanNode1 = $huffmanTree[$minNode1];
  268. $huffmanNode2 = $huffmanTree[$minNode2];
  269. $huffmanNode1->setParent($i);
  270. $huffmanNode2->setParent($i);
  271. $huffmanTree[$i]->setChild($minNode1,'left');
  272. $huffmanTree[$i]->setChild($minNode2,'right');
  273. $huffmanTree[$i]->setWeight($huffmanNode1->getWeight(),$huffmanNode2->getWeight());
  274. }
  275.  
  276. // 从叶子到根的遍历,得到字母的编码
  277. $huffmanCode = array();
  278. for($i = 0;$i < $leafCount; ++$i)
  279. {
  280. $leafNode = $huffmanTree[$i];
  281. $code = $leafNode->getCode();
  282. $reverseCode = array();
  283. for($c = $i,$pi = $leafNode->getParent();!is_null($pi);$pi = $huffmanTree[$pi]->getParent())
  284. {
  285. $huffmanNode = $huffmanTree[$pi];
  286. if($huffmanNode->getChild('left') === $c)
  287. {
  288. $reverseCode[] = 0;
  289. }
  290. elseif($huffmanNode->getChild('right') === $c)
  291. {
  292. $reverseCode[] = 1;
  293. }
  294. else
  295. {
  296. throw new Exception('Something error happened!' .__FILE__.__LINE__);
  297. }
  298. $c = $pi;
  299. }
  300. $huffmanCode[$code] = array_reverse($reverseCode);
  301. }
  302.  
  303. foreach($huffmanCode as $key => $value)
  304. {
  305. $s = implode(',',$value);
  306. echo $key. " : " .$s ."\n";
  307. }

运行结果:

运行环境:

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. SpringCloud学习笔记(5):Hystrix Dashboard可视化监控数据

    简介 上篇文章中讲了使用Hystrix实现容错,除此之外,Hystrix还提供了近乎实时的监控.本文将介绍如何进行服务监控以及使用Hystrix Dashboard来让监控数据图形化. 项目介绍 sc ...

  2. Winform中对ZedGraph的RadioGroup进行数据源绑定,即通过代码添加选项

    场景 在寻找设置RadioGroup的选项时没有找到相关博客,在DevExpress的官网找到 怎样给其添加选项. DevExpress官网教程: https://documentation.deve ...

  3. rabbitmq+haproxy+keepalived高可用集群环境搭建

    1.先安装centos扩展源: # yum -y install epel-release 2.安装erlang运行环境以及rabbitmq # yum install erlang ... # yu ...

  4. 第二场周赛(递归递推个人Rank赛)——题解

    很高兴给大家出题,本次难度低于上一场,新生的六个题都可以直接裸递归式或者裸递推式解决,对于老生的汉诺塔3,需要找出一般式,后两题分别为裸ST算法(或线段树)/线性DP. 正确的难度顺序为 种花 角谷定 ...

  5. Java多线程(十四):Timer

    Timer schedule(TimerTask task, Date time) 该方法在指定日期执行任务,如果是过去的时间,这个任务会立即被执行. 执行时间早于当前时间 示例代码,当前时间是201 ...

  6. Tomcat类加载器体系结构

    <深入理解java虚拟机>——Tomcat类加载器体系结构 标签: java / 虚拟机 / tomcat Tomcat 等主流Web服务器为了实现下面的基本功能,都实现了不止一个自定义的 ...

  7. 安全性测试:OWASP ZAP 2.8 使用指南(三):ZAP代理设置

    ZAP本地代理设置 如前文所言,ZAP的工作机制,是通过“中间代理”的形式实现. ZAP的代理设置可以从菜单中的:工具 - 选项 - Local Proxies加载. 在这里可以设置ZAP用来接受接入 ...

  8. [C++] 头文件中不要用using namespace std

    先总结下: 1. using namespce std:尽量不要(或者强硬一点,不许)在头文件中使用. 解析: 不让这么用,主要原因就是防止名字重复(即自定义变量名和std中名字重复),因为头文件会被 ...

  9. Containers vs Serverless:你选择谁,何时选择?

    两者都是当今技术时代的热门话题,也都被视为是开发技术的竞争对手. 首先,还有相当多的好奇和担心.此外,两者都是可供工程师使用的.高效的.机器无关的抽象. 但是,在冠军之间,有一个不可逾越的鸿沟.你要么 ...

  10. pycharm使用sublime/boxy配色方案

    # 展示效果图 1. github官网连接:https://github.com/simoncos/pycharm-monokai 2.克隆代码并解压文件 3.PyCharm -> File - ...