mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-11 09:48:40 +00:00
fixes #76
Still many unimplemented elements but the basic functions are usable?!
This commit is contained in:
parent
5522cf06fc
commit
4dd9f34670
|
|
@ -45,73 +45,78 @@ class BinaryTree extends Tree
|
|||
return $list;
|
||||
}
|
||||
|
||||
public function getLeft() {
|
||||
return $this->nodes[0] ?? null;
|
||||
public function getLeft(Node $base)
|
||||
{
|
||||
$neighbors = $base->getNeighbors($base);
|
||||
|
||||
// todo: index can be wrong, see setLeft/setRight
|
||||
return $neighbors[0] ?? null;
|
||||
}
|
||||
|
||||
public function getRight() {
|
||||
return $this->nodes[1] ?? null;
|
||||
public function getRight(Node $base)
|
||||
{
|
||||
$neighbors = $base->getNeighbors($base);
|
||||
|
||||
// todo: index can be wrong, see setLeft/setRight
|
||||
return $neighbors[1] ?? null;
|
||||
}
|
||||
|
||||
public function setLeft(BinaryTree $left) {
|
||||
$this->nodes[0] = $left;
|
||||
public function setLeft(Node $base, Node $left)
|
||||
{
|
||||
if($this->getLeft($base) === null) {
|
||||
$this->addNode($base, $left);
|
||||
// todo: doesn't know that this is left
|
||||
// todo: maybe need to add numerics to edges?
|
||||
} else {
|
||||
// todo: replace node
|
||||
}
|
||||
}
|
||||
|
||||
public function setRight(BinaryTree $right) {
|
||||
$this->nodes[1] = $right;
|
||||
public function setRight(Node $base, Node $right)
|
||||
{
|
||||
if($this->getRight($base) === null) {
|
||||
$this->addNode($base, $right);
|
||||
// todo: doesn't know that this is right
|
||||
// todo: maybe need to add numerics to edges?
|
||||
} else {
|
||||
// todo: replace node
|
||||
}
|
||||
}
|
||||
|
||||
public function preOrder(\Closure $callback) {
|
||||
public function inOrder(Node $node, \Closure $callback)
|
||||
{
|
||||
if(count($this->nodes) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$callback($this);
|
||||
$this->nodes[0]->inOrder($callback);
|
||||
$this->nodes[1]->inOrder($callback);
|
||||
$this->inOrder($this->getLeft($node), $callback);
|
||||
$callback($node);
|
||||
$this->inOrder($this->getRight($node), $callback);
|
||||
}
|
||||
|
||||
public function inOrder(\Closure $callback) {
|
||||
if(count($this->nodes) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->nodes[0]->inOrder($callback);
|
||||
$callback($this);
|
||||
$this->nodes[1]->inOrder($callback);
|
||||
}
|
||||
|
||||
public function postOrder(\Closure $callback) {
|
||||
if(count($this->nodes) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->nodes[0]->inOrder($callback);
|
||||
$this->nodes[1]->inOrder($callback);
|
||||
$callback($this);
|
||||
}
|
||||
|
||||
private function getVerticalOrder(int $horizontalDistance = 0, array &$order)
|
||||
private function getVerticalOrder(Node $node, int $horizontalDistance = 0, array &$order)
|
||||
{
|
||||
if(!isset($order[$horizontalDistance])) {
|
||||
$order[$horizontalDistance] = [];
|
||||
}
|
||||
|
||||
$order[$horizontalDistance][] = $this;
|
||||
$order[$horizontalDistance][] = $node;
|
||||
$left = $this->getLeft($node);
|
||||
$right = $this->getRight($node);
|
||||
|
||||
if(isset($this->nodes[0])) {
|
||||
$this->nodes[0]->getVerticalOrder($horizontalDistance-1, $order);
|
||||
if(isset($left)) {
|
||||
$this->getVerticalOrder($left, $horizontalDistance-1, $order);
|
||||
}
|
||||
|
||||
if(isset($this->nodes[1])) {
|
||||
$this->nodes[1]->getVerticalOrder($horizontalDistance+1, $order);
|
||||
if(isset($right)) {
|
||||
$this->getVerticalOrder($right, $horizontalDistance+1, $order);
|
||||
}
|
||||
}
|
||||
|
||||
public function verticalOrder(\Closure $callback)
|
||||
public function verticalOrder(Node $node, \Closure $callback)
|
||||
{
|
||||
$order = [];
|
||||
$this->getVerticalOrder(0, $order);
|
||||
$this->getVerticalOrder($node, 0, $order);
|
||||
|
||||
foreach($order as $level) {
|
||||
foreach($level as $node) {
|
||||
|
|
@ -120,19 +125,21 @@ class BinaryTree extends Tree
|
|||
}
|
||||
}
|
||||
|
||||
public function isSymmetric() : bool {
|
||||
// todo: compare values? true symmetry requires the values to be the same
|
||||
if(isset($this->nodes[0]) && isset($this->nodes[1])) {
|
||||
return isSymmetric($this->nodes[0], $this->nodes[1]);
|
||||
public function isSymmetric(Node $node1 = null, Node $node2 = null) : bool
|
||||
{
|
||||
if(!isset($node1) && !isset($node2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
$left1 = $this->getLeft($node1);
|
||||
$right1 = $this->getRight($node1);
|
||||
|
||||
$left2 = isset($node2) ? $this->getLeft($node1) : $this->getLeft($node2);
|
||||
$right2 = isset($node2) ? $this->getRight($node1) : $this->getRight($node2);
|
||||
|
||||
public function symmetric(BinaryTree $tree1, BinaryTree $tree2) : bool {
|
||||
// todo: compare values? true symmetry requires the values to be the same
|
||||
if(($tree1 !== null && $tree2 !== null) || $tree1 === $tree2) {
|
||||
return isSymmetric($tree1->getLeft(), $tree1->getRight()) && isSymmetric($tree2->getRight(), $tree2->getLeft());
|
||||
if(isset($node1) && isset($node2)) {
|
||||
return $this->isSymmetric($left1, $right2) && $this->isSymmetric($right1, $left2);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
53
Stdlib/Graph/Edge.php
Normal file
53
Stdlib/Graph/Edge.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* Orange Management
|
||||
*
|
||||
* PHP Version 7.0
|
||||
*
|
||||
* @category TBD
|
||||
* @package TBD
|
||||
* @author OMS Development Team <dev@oms.com>
|
||||
* @author Dennis Eichhorn <d.eichhorn@oms.com>
|
||||
* @copyright 2013 Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link http://orange-management.com
|
||||
*/
|
||||
namespace phpOMS\Datatypes;
|
||||
|
||||
/**
|
||||
* Tree class.
|
||||
*
|
||||
* @category Framework
|
||||
* @package phpOMS\Datatypes
|
||||
* @author OMS Development Team <dev@oms.com>
|
||||
* @author Dennis Eichhorn <d.eichhorn@oms.com>
|
||||
* @license OMS License 1.0
|
||||
* @link http://orange-management.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Edge
|
||||
{
|
||||
private $node1 = null;
|
||||
|
||||
private $node2 = null;
|
||||
|
||||
private $directed = false;
|
||||
|
||||
public function __construct(Node $node1, Node $node2, bool $directed = false)
|
||||
{
|
||||
$this->node1 = $node1;
|
||||
$this->node2 = $node2;
|
||||
$this->directed = $directed;
|
||||
}
|
||||
|
||||
public function getNodes() : array
|
||||
{
|
||||
return [$this->node1, $this->node2];
|
||||
}
|
||||
|
||||
public function isDirected() : bool
|
||||
{
|
||||
return $this->directed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
<?php
|
||||
/**
|
||||
* Orange Management
|
||||
*
|
||||
* PHP Version 7.0
|
||||
*
|
||||
* @category TBD
|
||||
* @package TBD
|
||||
* @author OMS Development Team <dev@oms.com>
|
||||
* @author Dennis Eichhorn <d.eichhorn@oms.com>
|
||||
* @copyright 2013 Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link http://orange-management.com
|
||||
*/
|
||||
namespace phpOMS\Datatypes;
|
||||
|
||||
/**
|
||||
* Tree class.
|
||||
*
|
||||
* @category Framework
|
||||
* @package phpOMS\Datatypes
|
||||
* @author OMS Development Team <dev@oms.com>
|
||||
* @author Dennis Eichhorn <d.eichhorn@oms.com>
|
||||
* @license OMS License 1.0
|
||||
* @link http://orange-management.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Graph
|
||||
{
|
||||
protected $nodes = [];
|
||||
|
||||
protected $edges = [];
|
||||
|
||||
public function addNode(Node $node)
|
||||
{
|
||||
$this->nodes[] = $node;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setNode($key, Node $node)
|
||||
{
|
||||
$this->nodes[$key] = $node;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addEdge(Edge $edge)
|
||||
{
|
||||
$this->edges[] = $edge;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEdge($key, Edge $edge)
|
||||
{
|
||||
$this->edges[$key] = $edge;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNode($key) : Node
|
||||
{
|
||||
return $this->nodes[$key];
|
||||
}
|
||||
|
||||
public function getEdge($key) : Edge
|
||||
{
|
||||
return $this->edges[$key];
|
||||
}
|
||||
|
||||
public function getEdgesOfNode($node) : array
|
||||
{
|
||||
if(!($node instanceof Node)) {
|
||||
$node = $this->getNode($node);
|
||||
}
|
||||
|
||||
$edges = [];
|
||||
foreach($this->edges as $edge) {
|
||||
$nodes = $edge->getNodes();
|
||||
|
||||
if($nodes[0] === $node || $nodes[1] === $node) {
|
||||
$edges[] = $edge;
|
||||
}
|
||||
}
|
||||
|
||||
return $edges;
|
||||
}
|
||||
|
||||
public function getNeighbors($node) : array
|
||||
{
|
||||
if(!($node instanceof Node)) {
|
||||
$node = $this->getNode($node);
|
||||
}
|
||||
|
||||
$edges = $this->getEdgesOfNode($node);
|
||||
$neighbors = [];
|
||||
|
||||
foreach($edges as $edge) {
|
||||
$nodes = $edge->getNodes();
|
||||
|
||||
if($nodes[0] !== $node && $nodes[0] !== null) {
|
||||
$neighbors[] = $nodes[0];
|
||||
} elseif($nodes[1] !== $node && $nodes[0] !== null) {
|
||||
$neighbors[] = $nodes[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $neighbors;
|
||||
}
|
||||
|
||||
public function getDimension() : int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getBridges() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getKruskalMinimalSpanningTree() : Tree
|
||||
{
|
||||
return new Tree();
|
||||
}
|
||||
|
||||
public function getPrimMinimalSpanningTree() : Tree
|
||||
{
|
||||
return new Tree();
|
||||
}
|
||||
|
||||
public function getCircle() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getFloydWarshallShortestPath() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getDijkstraShortestPath() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function depthFirstTraversal() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function breadthFirstTraversal() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function longestPath() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function longestPathBetweenNodes() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getOrder() : int
|
||||
{
|
||||
return count($this->nodes);
|
||||
}
|
||||
|
||||
public function getSize() : int
|
||||
{
|
||||
return count($this->edges);
|
||||
}
|
||||
|
||||
public function getDiameter() : int
|
||||
{
|
||||
$diameter = 0;
|
||||
|
||||
foreach($this->nodes as $node1) {
|
||||
foreach($this->nodes as $node2) {
|
||||
if($node1 === $node2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$diameter = max($diameter, $this->getFloydWarshallShortestPath($node1, $node2));
|
||||
}
|
||||
}
|
||||
|
||||
return $diameter;
|
||||
}
|
||||
|
||||
public function getGirth() : int
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getCircuitRank() : int
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getNodeConnectivity() : int
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getEdgeConnectivity() : int
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function isConnected() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getUnconnected() : array
|
||||
{
|
||||
// get all unconnected sub graphs
|
||||
}
|
||||
|
||||
public function isBipartite() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isTriangleFree() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isCircleFree() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
33
Stdlib/Graph/Node.php
Normal file
33
Stdlib/Graph/Node.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* Orange Management
|
||||
*
|
||||
* PHP Version 7.0
|
||||
*
|
||||
* @category TBD
|
||||
* @package TBD
|
||||
* @author OMS Development Team <dev@oms.com>
|
||||
* @author Dennis Eichhorn <d.eichhorn@oms.com>
|
||||
* @copyright 2013 Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link http://orange-management.com
|
||||
*/
|
||||
namespace phpOMS\Datatypes;
|
||||
|
||||
/**
|
||||
* Tree class.
|
||||
*
|
||||
* @category Framework
|
||||
* @package phpOMS\Datatypes
|
||||
* @author OMS Development Team <dev@oms.com>
|
||||
* @author Dennis Eichhorn <d.eichhorn@oms.com>
|
||||
* @license OMS License 1.0
|
||||
* @link http://orange-management.com
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo : there is a bug with Hungary ibans since they have two k (checksums) in their definition
|
||||
*/
|
||||
class Node
|
||||
{
|
||||
}
|
||||
|
|
@ -25,44 +25,58 @@ namespace phpOMS\Datatypes;
|
|||
* @license OMS License 1.0
|
||||
* @link http://orange-management.com
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo : there is a bug with Hungary ibans since they have two k (checksums) in their definition
|
||||
*/
|
||||
class Tree extends Graph
|
||||
{
|
||||
protected $nodes = [];
|
||||
private $root = null;
|
||||
|
||||
public function add(Tree $node) {
|
||||
$this->nodes[] = $node;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function set($key, Tree $node) {
|
||||
$this->nodes[$key] = $node;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMaxDepth() : int
|
||||
public function __construct()
|
||||
{
|
||||
$depth = [0];
|
||||
$root = new Node();
|
||||
$this->addNode($root);
|
||||
}
|
||||
|
||||
foreach($this->nodes as $node) {
|
||||
$depth[] = $node->getMaxDepth();
|
||||
public function addNode(Node $base, Node $node)
|
||||
{
|
||||
parent::addNode($node);
|
||||
parent::addEdge(new Edge($base, $node));
|
||||
}
|
||||
|
||||
public function getMaxDepth(Node $node = null) : int
|
||||
{
|
||||
$currentNode = $node ?? $this->root;
|
||||
|
||||
if(!isset($currentNode)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return max($depth) + 1;
|
||||
$depth = 1;
|
||||
$neighbors = $this->getNeighbors($currentNode);
|
||||
|
||||
foreach($neighbors as $neighbor) {
|
||||
$depth = max($depth, $depth + $this->getMaxDepth($neighbor));
|
||||
}
|
||||
|
||||
return $depth;
|
||||
}
|
||||
|
||||
public function getMinDepth() : int
|
||||
public function getMinDepth(Node $node = null) : int
|
||||
{
|
||||
$depth = [0];
|
||||
$currentNode = $node ?? $this->root;
|
||||
|
||||
foreach($this->nodes as $node) {
|
||||
$depth[] = $node->getMinDepth();
|
||||
if(!isset($currentNode)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$depth = [];
|
||||
$neighbors = $this->getNeighbors($currentNode);
|
||||
|
||||
foreach($neighbors as $neighbor) {
|
||||
$depth[] = $this->getMaxDepth($neighbor);
|
||||
}
|
||||
|
||||
$depth = empty($depth) ? 0 : $depth;
|
||||
|
||||
return min($depth) + 1;
|
||||
}
|
||||
|
||||
|
|
@ -76,34 +90,70 @@ class Tree extends Graph
|
|||
}
|
||||
}
|
||||
|
||||
public function isLeaf() : bool
|
||||
public function isLeaf(Node $node) : bool
|
||||
{
|
||||
return count($this->nodes) === 0;
|
||||
return count($this->getEdgesOfNode($node)) === 1;
|
||||
}
|
||||
|
||||
public function getDimension() : int
|
||||
{
|
||||
$size = 1;
|
||||
|
||||
foreach($this->nodes as $node) {
|
||||
$size += $node->getDimension() + 1;
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
public function getLevelNodes(int $level, array &$nodes)
|
||||
public function getLevelNodes(int $level, Node $node) : array
|
||||
{
|
||||
--$level;
|
||||
$neighbors = $this->getNeighbors($node);
|
||||
$nodes = [];
|
||||
|
||||
if($level === 1) {
|
||||
return $neighbors;
|
||||
}
|
||||
|
||||
foreach($neighbors as $neighbor) {
|
||||
array_merge($nodes, $this->getLevelNodes($level, $neighbor));
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
public function isFull(int $type) : bool {
|
||||
if(count($this->edges) % $type !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($this->nodes as $node) {
|
||||
if($level === 0) {
|
||||
$nodes[] = $this;
|
||||
$neighbors = count($this->getNeighbors($node));
|
||||
|
||||
return $nodes;
|
||||
} else {
|
||||
$this->getLevelNodes($level, $nodes);
|
||||
if($neighbors !== $type && $neighbors !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function preOrder(Node $node, \Closure $callback) {
|
||||
if(count($this->nodes) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$callback($node);
|
||||
$neighbors = $this->getNeighbors();
|
||||
|
||||
foreach($neighbors as $neighbor) {
|
||||
// todo: get neighbors needs to return in ordered way
|
||||
$this->preOrder($neighbor, $callback);
|
||||
}
|
||||
}
|
||||
|
||||
public function postOrder(Node $node, \Closure $callback) {
|
||||
if(count($this->nodes) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$neighbors = $this->getNeighbors();
|
||||
|
||||
foreach($neighbors as $neighbor) {
|
||||
// todo: get neighbors needs to return in ordered way
|
||||
$this->postOrder($neighbor, $callback);
|
||||
}
|
||||
|
||||
$callback($node);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user