algorithm.php 6.9 KB

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