algorithm.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: stanley-king
  5. * Date: 16/6/24
  6. * Time: 上午1:18
  7. */
  8. function less($x,$y)
  9. {
  10. return $x < $y;
  11. }
  12. class full_set
  13. {
  14. private static $stInstance = null;
  15. public static function instance()
  16. {
  17. if(static::$stInstance == null) {
  18. static::$stInstance = new full_set();
  19. }
  20. }
  21. }
  22. class algorithm
  23. {
  24. static function bsearch($x, $list)
  25. {
  26. $left = 0;
  27. $right = count($list)-1;
  28. while ($left <= $right) {
  29. $mid = ($left + $right) >> 1;
  30. if ($list[$mid] == $x) {
  31. return $mid;
  32. } elseif ($list[$mid] > $x) {
  33. $right = $mid - 1;
  34. } elseif ($list[$mid] < $x) {
  35. $left = $mid + 1;
  36. }
  37. }
  38. return -1;
  39. }
  40. static function binary_search($sortarr, $val, $compare = "less")
  41. {
  42. $last = count($sortarr);
  43. $first = self::lower_bonud($sortarr,$val,$compare);
  44. return $first != $last && !$compare($val, $sortarr[$first]);
  45. }
  46. //返回位置标记了一个 >= value 的值。
  47. static function lower_bonud($container, $val,$compare = "less")
  48. {
  49. if(!is_array($container)) {
  50. return -1;
  51. }
  52. $len = count($container);
  53. $first = 0;
  54. while ($len != 0)
  55. {
  56. $l2 = intval($len / 2);
  57. $m = $first + $l2;
  58. if ($compare($container[$m],$val))
  59. {
  60. $first = ++$m;
  61. $len -= $l2 + 1;
  62. }
  63. else {
  64. $len = $l2;
  65. }
  66. }
  67. return $first;
  68. }
  69. //返回位置标记了一个 > value 的值。
  70. static function upper_bound($container, $val,$compare = "less")
  71. {
  72. if (!is_array($container)) {
  73. return -1;
  74. }
  75. $len = count($container);
  76. $first = 0;
  77. while ($len != 0)
  78. {
  79. $l2 = intval($len / 2);
  80. $m = $first + $l2;
  81. if ($compare($val,$container[$m])) {
  82. $len = $l2;
  83. } else {
  84. $first = ++$m;
  85. $len -= $l2 + 1;
  86. }
  87. }
  88. return $first;
  89. }
  90. static function array_insert(&$arr,$pos,$val)
  91. {
  92. if(is_array($val)) {
  93. $left = array_slice($arr, 0, $pos);
  94. $left[] = $val;
  95. $right = array_slice($arr, $pos);
  96. $arr = array_merge($left, $right);
  97. }
  98. else {
  99. array_splice($arr,$pos,0,$val);
  100. }
  101. }
  102. static function array_erase(&$arr,$pos)
  103. {
  104. return array_splice($arr,$pos,1);
  105. }
  106. static function set_intersection($ar1, $ar2)
  107. {
  108. if($ar1 === full_set::instance()) {
  109. return $ar2;
  110. }
  111. if($ar2 === full_set::instance()) {
  112. return $ar1;
  113. }
  114. $count1 = count($ar1);
  115. $count2 = count($ar2);
  116. $pos1 = 0;
  117. $pos2 = 0;
  118. $result = [];
  119. while ($pos1 != $count1 && $pos2 != $count2)
  120. {
  121. $val1 = $ar1[$pos1];
  122. $val2 = $ar2[$pos2];
  123. if ($val1 < $val2) {
  124. ++$pos1;
  125. }
  126. elseif($val1 == $val2) {
  127. $result[] = $val1;
  128. ++$pos1;
  129. ++$pos2;
  130. }
  131. else {
  132. ++$pos2;
  133. }
  134. }
  135. return $result;
  136. }
  137. private static function copy($src,$pos,&$result)
  138. {
  139. $count = count($src);
  140. for (;$pos < $count;++$pos) {
  141. $result[] = $src[$pos];
  142. }
  143. return $result;
  144. }
  145. static function set_union($ar1,$ar2)
  146. {
  147. $count1 = count($ar1);
  148. $count2 = count($ar2);
  149. $pos1 = 0;
  150. $pos2 = 0;
  151. $result = [];
  152. for (; $pos1 != $count1; )
  153. {
  154. if ($pos2 == $count2) {
  155. return self::copy($ar1, $pos1, $result);
  156. }
  157. if ($ar1[$pos1] > $ar2[$pos2])
  158. {
  159. $result[] = $ar2[$pos2];
  160. ++$pos2;
  161. }
  162. elseif($ar1[$pos1] == $ar2[$pos2]) {
  163. $result[] = $ar1[$pos1];
  164. ++$pos1;
  165. ++$pos2;
  166. }
  167. else
  168. {
  169. $result[] = $ar1[$pos1];
  170. ++$pos1;
  171. }
  172. }
  173. return self::copy($ar2,$pos2,$result);
  174. }
  175. public static function not_in($src,$avables)
  176. {
  177. if(empty($src)) return array();
  178. if(empty($avables)) return $src;
  179. $src = array_unique($src);
  180. $avables = array_unique($avables);
  181. sort($src);
  182. sort($avables);
  183. $result = [];
  184. foreach ($src as $val)
  185. {
  186. if(algorithm::binary_search($avables,$val) == false) {
  187. $result[] = $val;
  188. }
  189. }
  190. return $result;
  191. }
  192. }
  193. class uniquer
  194. {
  195. private $mContainer;
  196. private $mCompare;
  197. public function __construct($compare = 'less')
  198. {
  199. $this->mContainer = [];
  200. $this->mCompare = $compare;
  201. }
  202. public function add_value($val)
  203. {
  204. if(algorithm::binary_search($this->mContainer,$val,$this->mCompare) == false) {
  205. $pos = algorithm::lower_bonud($this->mContainer,$val,$this->mCompare);
  206. algorithm::array_insert($this->mContainer,$pos,$val);
  207. return true;
  208. } else {
  209. return false;
  210. }
  211. }
  212. public function add_values(array $datas)
  213. {
  214. if(!is_array($datas)) return false;
  215. foreach ($datas as $val) {
  216. $this->add_value($val);
  217. }
  218. return true;
  219. }
  220. public function remove_value($val)
  221. {
  222. if(algorithm::binary_search($this->mContainer,$val,$this->mCompare) != false) {
  223. $pos = algorithm::lower_bonud($this->mContainer,$val);
  224. algorithm::array_erase($this->mContainer,$pos);
  225. return true;
  226. } else {
  227. return false;
  228. }
  229. }
  230. public function values() {
  231. return $this->mContainer;
  232. }
  233. public function find($val)
  234. {
  235. return algorithm::binary_search($this->mContainer,$val,$this->mCompare);
  236. }
  237. public function range($lower,$high)
  238. {
  239. if(empty($lower)) {
  240. $pos_low = 0;
  241. }
  242. else {
  243. $pos_low = algorithm::lower_bonud($this->mContainer,$lower,$this->mCompare);
  244. }
  245. if(empty($high)) {
  246. $pos_high = count($this->mContainer);
  247. }
  248. else {
  249. $pos_high = algorithm::lower_bonud($this->mContainer,$high,$this->mCompare);
  250. }
  251. if($pos_low < 0) return [];
  252. return array_slice($this->mContainer, $pos_low, $pos_high - $pos_low);
  253. }
  254. }
  255. class array_helper
  256. {
  257. public static function mapper($items,callable $func)
  258. {
  259. $result = [];
  260. foreach ($items as $item)
  261. {
  262. $key = $func($item);
  263. if($key === false) continue;
  264. $result[$key] = $item;
  265. }
  266. return $result;
  267. }
  268. }