Heaviest path in special graph (PHP) - php

I have to search the heaviest path in graph what like:
1
2 1
4 5 8
2 2 3 4
(1,1,8,4 in this example)
The graph like this ever.
So it is an element who has two children except lowermosts. Who has children they has a common child e.g. (in above graph) 5 (in 3. row) is a common child to 2 and 1 (in 2. row.).
So these are nodes and not edges and them have a value.
I wrote an algorithm in php:
class node{
public $children = array();
public $value;
public $_heavier = null;
public $_value = null;
function __construct($value, $children) {
$this->value = $value;
$this->children = $children;
}
function heavier() {
if (null !== $this->_value) {
echo 'b' . $this->value . '<br>';
return $this->_value;
}
$val = $this->value;
if ($this->children[0]) {
$c1 = $this->children[0]->heavier();
$c2 = $this->children[1]->heavier();
if ($c1 > $c2) {
$this->_heavier = 0;
$val += $c1;
} else {
$this->_heavier = 1;
$val += $c2;
}
}
echo 'a' . $this->value . '<br>';
$this->_value = $val;
return $val;
}
function getPath() {
if (null !== $this->_heavier) {
echo $this->children[$this->_heavier]->getPath();
}
return $this->value;
}
}
$exists = array();
function a($row, $item) {
global $input, $exists;
$nextRow = $row + 1;
$child1No = $item;
$child2No = $item + 1;
$child1 = null;
if (isset($input[$nextRow][$child1No])) {
$child1 = a($nextRow, $child1No);
}
$child2 = null;
if (isset($input[$nextRow][$child2No])) {
$child2 = a($nextRow, $child2No);
}
if (!isset($exists[$row][$item])) {
$obj = new node($input[$row][$item], array($child1, $child2));
$exists[$row][$item] = &$obj;
} else {
$obj = &$exists[$row][$item];
}
return $obj;
}
$nodes = a(0, 0);
$nodes->heavier();
echo $nodes->getPath();
echo '<br>';
It is works, but too much time.
How to speed up?
Thx.

Your algorithm is the most optimal possible - you take O(n) time where n is the number of nodes. It can easily be proved that nothing faster can be done.
I think the slow part of your algorithm is the echo-ing - this is a very heavy operation and might slow your algorithm quite a bit as you echo too much.
PS: By the way on how many nodes you execute your algorithm? Is it really on only 10?

Related

How do you get the next key in an associative array php [duplicate]

I have a foreach loop and I want to see if there is a next element in the loop so I can compare the current element with the next. How can I do this? I've read about the current and next functions but I can't figure out how to use them.
A unique approach would be to reverse the array and then loop. This will work for non-numerically indexed arrays as well:
$items = array(
'one' => 'two',
'two' => 'two',
'three' => 'three'
);
$backwards = array_reverse($items);
$last_item = NULL;
foreach ($backwards as $current_item) {
if ($last_item === $current_item) {
// they match
}
$last_item = $current_item;
}
If you are still interested in using the current and next functions, you could do this:
$items = array('two', 'two', 'three');
$length = count($items);
for($i = 0; $i < $length - 1; ++$i) {
if (current($items) === next($items)) {
// they match
}
}
#2 is probably the best solution. Note, $i < $length - 1; will stop the loop after comparing the last two items in the array. I put this in the loop to be explicit with the example. You should probably just calculate $length = count($items) - 1;
You could probably use while loop instead of foreach:
while ($current = current($array) )
{
$next = next($array);
if (false !== $next && $next == $current)
{
//do something with $current
}
}
If the indexes are continuous:
foreach ($arr as $key => $val) {
if (isset($arr[$key+1])) {
echo $arr[$key+1]; // next element
} else {
// end of array reached
}
}
As php.net/foreach points out:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
In other words - it's not a very good idea to do what you're asking to do. Perhaps it would be a good idea to talk with someone about why you're trying to do this, see if there's a better solution? Feel free to ask us in ##PHP on irc.freenode.net if you don't have any other resources available.
You could get the keys/values and index
<?php
$a = array(
'key1'=>'value1',
'key2'=>'value2',
'key3'=>'value3',
'key4'=>'value4',
'key5'=>'value5'
);
$keys = array_keys($a);
foreach(array_keys($keys) as $index ){
$current_key = current($keys); // or $current_key = $keys[$index];
$current_value = $a[$current_key]; // or $current_value = $a[$keys[$index]];
$next_key = next($keys);
$next_value = $a[$next_key] ?? null; // for php version >= 7.0
echo "{$index}: current = ({$current_key} => {$current_value}); next = ({$next_key} => {$next_value})\n";
}
result:
0: current = (key1 => value1); next = (key2 => value2)
1: current = (key2 => value2); next = (key3 => value3)
2: current = (key3 => value3); next = (key4 => value4)
3: current = (key4 => value4); next = (key5 => value5)
4: current = (key5 => value5); next = ( => )
if its numerically indexed:
foreach ($foo as $key=>$var){
if($var==$foo[$key+1]){
echo 'current and next var are the same';
}
}
The general solution could be a caching iterator. A properly implemented caching iterator works with any Iterator, and saves memory. PHP SPL has a CachingIterator, but it is very odd, and has very limited functionality. However, you can write your own lookahead iterator like this:
<?php
class NeighborIterator implements Iterator
{
protected $oInnerIterator;
protected $hasPrevious = false;
protected $previous = null;
protected $previousKey = null;
protected $hasCurrent = false;
protected $current = null;
protected $currentKey = null;
protected $hasNext = false;
protected $next = null;
protected $nextKey = null;
public function __construct(Iterator $oInnerIterator)
{
$this->oInnerIterator = $oInnerIterator;
}
public function current()
{
return $this->current;
}
public function key()
{
return $this->currentKey;
}
public function next()
{
if ($this->hasCurrent) {
$this->hasPrevious = true;
$this->previous = $this->current;
$this->previousKey = $this->currentKey;
$this->hasCurrent = $this->hasNext;
$this->current = $this->next;
$this->currentKey = $this->nextKey;
if ($this->hasNext) {
$this->oInnerIterator->next();
$this->hasNext = $this->oInnerIterator->valid();
if ($this->hasNext) {
$this->next = $this->oInnerIterator->current();
$this->nextKey = $this->oInnerIterator->key();
} else {
$this->next = null;
$this->nextKey = null;
}
}
}
}
public function rewind()
{
$this->hasPrevious = false;
$this->previous = null;
$this->previousKey = null;
$this->oInnerIterator->rewind();
$this->hasCurrent = $this->oInnerIterator->valid();
if ($this->hasCurrent) {
$this->current = $this->oInnerIterator->current();
$this->currentKey = $this->oInnerIterator->key();
$this->oInnerIterator->next();
$this->hasNext = $this->oInnerIterator->valid();
if ($this->hasNext) {
$this->next = $this->oInnerIterator->current();
$this->nextKey = $this->oInnerIterator->key();
} else {
$this->next = null;
$this->nextKey = null;
}
} else {
$this->current = null;
$this->currentKey = null;
$this->hasNext = false;
$this->next = null;
$this->nextKey = null;
}
}
public function valid()
{
return $this->hasCurrent;
}
public function hasNext()
{
return $this->hasNext;
}
public function getNext()
{
return $this->next;
}
public function getNextKey()
{
return $this->nextKey;
}
public function hasPrevious()
{
return $this->hasPrevious;
}
public function getPrevious()
{
return $this->previous;
}
public function getPreviousKey()
{
return $this->previousKey;
}
}
header("Content-type: text/plain; charset=utf-8");
$arr = [
"a" => "alma",
"b" => "banan",
"c" => "cseresznye",
"d" => "dio",
"e" => "eper",
];
$oNeighborIterator = new NeighborIterator(new ArrayIterator($arr));
foreach ($oNeighborIterator as $key => $value) {
// you can get previous and next values:
if (!$oNeighborIterator->hasPrevious()) {
echo "{FIRST}\n";
}
echo $oNeighborIterator->getPreviousKey() . " => " . $oNeighborIterator->getPrevious() . " -----> ";
echo "[ " . $key . " => " . $value . " ] -----> ";
echo $oNeighborIterator->getNextKey() . " => " . $oNeighborIterator->getNext() . "\n";
if (!$oNeighborIterator->hasNext()) {
echo "{LAST}\n";
}
}
You could get the keys of the array before the foreach, then use a counter to check the next element, something like:
//$arr is the array you wish to cycle through
$keys = array_keys($arr);
$num_keys = count($keys);
$i = 1;
foreach ($arr as $a)
{
if ($i < $num_keys && $arr[$keys[$i]] == $a)
{
// we have a match
}
$i++;
}
This will work for both simple arrays, such as array(1,2,3), and keyed arrays such as array('first'=>1, 'second'=>2, 'thrid'=>3).
A foreach loop in php will iterate over a copy of the original array, making next() and prev() functions useless. If you have an associative array and need to fetch the next item, you could iterate over the array keys instead:
foreach (array_keys($items) as $index => $key) {
// first, get current item
$item = $items[$key];
// now get next item in array
$next = $items[array_keys($items)[$index + 1]];
}
Since the resulting array of keys has a continuous index itself, you can use that instead to access the original array.
Be aware that $next will be null for the last iteration, since there is no next item after the last. Accessing non existent array keys will throw a php notice. To avoid that, either:
Check for the last iteration before assigning values to $next
Check if the key with index + 1 exists with array_key_exists()
Using method 2 the complete foreach could look like this:
foreach (array_keys($items) as $index => $key) {
// first, get current item
$item = $items[$key];
// now get next item in array
$next = null;
if (array_key_exists($index + 1, array_keys($items))) {
$next = $items[array_keys($items)[$index + 1]];
}
}
$next_data = $data;
$prev_key = null;
$prev_value = null;
foreach($data as $key => $value)
{
array_shift($next_data);
$next_key = key($next_data);
$next_value = $next_data[$next_key] ?? null;
// Do something here...
$prev_key = $key;
$prev_value = $value;
}
or if the array is associative then you could use current() similar to Andrei Krasutski's solution and key()
$values = [];
array_push($values, ["XYZ"=>100]);
array_push($values, ["ABC"=>10]);
array_push($values, ["XYZ"=>130]);
array_push($values, ["DEF"=>4]);
array_push($values, ["XYZ"=>5]);
$count = count($values);
foreach ($values as $index => $currentValue) {
if ($index < $count - 1) {
$nextValue = $values[$index + 1];
echo key($currentValue) . "=" . current($currentValue) . " followed by " . key($nextValue) . "/" . current($nextValue) . "<br>\n";
} else {
echo key($currentValue) . "=" . current($currentValue);
}
}
See https://onlinephp.io/c/dc58d for a running example.
or if the array is using named pairs:
$values = [];
array_push($values, ["type"=>"XYZ", "value"=>100]);
array_push($values, ["type"=>"ABC", "value"=>10]);
array_push($values, ["type"=>"XYZ", "value"=>130]);
array_push($values, ["type"=>"DEF", "value"=>"Lorem"]);
array_push($values, ["type"=>"XYZ", "value"=>5]);
$count = count($values);
foreach ($values as $index => $currentValue) {
if ($index < $count - 1) {
$nextValue = $values[$index + 1];
echo $currentValue['type'] . "=" . $currentValue['value']
. " followed by " . $nextValue['type'] . "/" . $nextValue['value'] . "<br>\n";
} else {
echo $currentValue['type'] . "=" . $currentValue['value'];
}
}

Error when printing how many levels are visible in tree in PHP

I am receiving the error "Using $this when not in object context". I think I might be using the class node incorrectly. I cannot figure out where I am going wrong at this point.
I am trying to get the answer 4 in the case of a tree like the below. This is because there are 4 visible layers.
$root = new TreeNode(8);
$root->left = new TreeNode(3);
$root->right = new TreeNode(10);
$root->left->left = new TreeNode(1);
$root->left->right = new TreeNode(6);
$root->left->right->left = new TreeNode(4);
$root->left->right->right = new TreeNode(7);
$root->right->right = new TreeNode(14);
$root->right->right->left = new TreeNode(13);
class TreeNode{
public $val;
public $left;
public $right;
public function __construct($val=0) {
$this->val = $val;
$this->left = NULL;
$this->right = NULL;
}
}
function findLeft($root){
$queue = $root;
while(!empty($queue)){
$size = sizeof($queue);
$i = 0;
$answer = 0;
while($i<$size){
$i= $i+1;
//if first node print
if ($i == 1){
$answer += 1;
}
if($this->left){
array_push($queue, $this->left);
}
if($this->right){
array_push($queue, $this->right);
}
array_unshift($queue); //shift first item
}
} return $queue;
}
//calling function
function visibleNodes($root) {
// Write your code here
if(empty($root)){
return 0;
} else {
$answer = findLeft($root);
}
return $answer;
}

Get next element in foreach loop

I have a foreach loop and I want to see if there is a next element in the loop so I can compare the current element with the next. How can I do this? I've read about the current and next functions but I can't figure out how to use them.
A unique approach would be to reverse the array and then loop. This will work for non-numerically indexed arrays as well:
$items = array(
'one' => 'two',
'two' => 'two',
'three' => 'three'
);
$backwards = array_reverse($items);
$last_item = NULL;
foreach ($backwards as $current_item) {
if ($last_item === $current_item) {
// they match
}
$last_item = $current_item;
}
If you are still interested in using the current and next functions, you could do this:
$items = array('two', 'two', 'three');
$length = count($items);
for($i = 0; $i < $length - 1; ++$i) {
if (current($items) === next($items)) {
// they match
}
}
#2 is probably the best solution. Note, $i < $length - 1; will stop the loop after comparing the last two items in the array. I put this in the loop to be explicit with the example. You should probably just calculate $length = count($items) - 1;
You could probably use while loop instead of foreach:
while ($current = current($array) )
{
$next = next($array);
if (false !== $next && $next == $current)
{
//do something with $current
}
}
If the indexes are continuous:
foreach ($arr as $key => $val) {
if (isset($arr[$key+1])) {
echo $arr[$key+1]; // next element
} else {
// end of array reached
}
}
As php.net/foreach points out:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
In other words - it's not a very good idea to do what you're asking to do. Perhaps it would be a good idea to talk with someone about why you're trying to do this, see if there's a better solution? Feel free to ask us in ##PHP on irc.freenode.net if you don't have any other resources available.
You could get the keys/values and index
<?php
$a = array(
'key1'=>'value1',
'key2'=>'value2',
'key3'=>'value3',
'key4'=>'value4',
'key5'=>'value5'
);
$keys = array_keys($a);
foreach(array_keys($keys) as $index ){
$current_key = current($keys); // or $current_key = $keys[$index];
$current_value = $a[$current_key]; // or $current_value = $a[$keys[$index]];
$next_key = next($keys);
$next_value = $a[$next_key] ?? null; // for php version >= 7.0
echo "{$index}: current = ({$current_key} => {$current_value}); next = ({$next_key} => {$next_value})\n";
}
result:
0: current = (key1 => value1); next = (key2 => value2)
1: current = (key2 => value2); next = (key3 => value3)
2: current = (key3 => value3); next = (key4 => value4)
3: current = (key4 => value4); next = (key5 => value5)
4: current = (key5 => value5); next = ( => )
if its numerically indexed:
foreach ($foo as $key=>$var){
if($var==$foo[$key+1]){
echo 'current and next var are the same';
}
}
The general solution could be a caching iterator. A properly implemented caching iterator works with any Iterator, and saves memory. PHP SPL has a CachingIterator, but it is very odd, and has very limited functionality. However, you can write your own lookahead iterator like this:
<?php
class NeighborIterator implements Iterator
{
protected $oInnerIterator;
protected $hasPrevious = false;
protected $previous = null;
protected $previousKey = null;
protected $hasCurrent = false;
protected $current = null;
protected $currentKey = null;
protected $hasNext = false;
protected $next = null;
protected $nextKey = null;
public function __construct(Iterator $oInnerIterator)
{
$this->oInnerIterator = $oInnerIterator;
}
public function current()
{
return $this->current;
}
public function key()
{
return $this->currentKey;
}
public function next()
{
if ($this->hasCurrent) {
$this->hasPrevious = true;
$this->previous = $this->current;
$this->previousKey = $this->currentKey;
$this->hasCurrent = $this->hasNext;
$this->current = $this->next;
$this->currentKey = $this->nextKey;
if ($this->hasNext) {
$this->oInnerIterator->next();
$this->hasNext = $this->oInnerIterator->valid();
if ($this->hasNext) {
$this->next = $this->oInnerIterator->current();
$this->nextKey = $this->oInnerIterator->key();
} else {
$this->next = null;
$this->nextKey = null;
}
}
}
}
public function rewind()
{
$this->hasPrevious = false;
$this->previous = null;
$this->previousKey = null;
$this->oInnerIterator->rewind();
$this->hasCurrent = $this->oInnerIterator->valid();
if ($this->hasCurrent) {
$this->current = $this->oInnerIterator->current();
$this->currentKey = $this->oInnerIterator->key();
$this->oInnerIterator->next();
$this->hasNext = $this->oInnerIterator->valid();
if ($this->hasNext) {
$this->next = $this->oInnerIterator->current();
$this->nextKey = $this->oInnerIterator->key();
} else {
$this->next = null;
$this->nextKey = null;
}
} else {
$this->current = null;
$this->currentKey = null;
$this->hasNext = false;
$this->next = null;
$this->nextKey = null;
}
}
public function valid()
{
return $this->hasCurrent;
}
public function hasNext()
{
return $this->hasNext;
}
public function getNext()
{
return $this->next;
}
public function getNextKey()
{
return $this->nextKey;
}
public function hasPrevious()
{
return $this->hasPrevious;
}
public function getPrevious()
{
return $this->previous;
}
public function getPreviousKey()
{
return $this->previousKey;
}
}
header("Content-type: text/plain; charset=utf-8");
$arr = [
"a" => "alma",
"b" => "banan",
"c" => "cseresznye",
"d" => "dio",
"e" => "eper",
];
$oNeighborIterator = new NeighborIterator(new ArrayIterator($arr));
foreach ($oNeighborIterator as $key => $value) {
// you can get previous and next values:
if (!$oNeighborIterator->hasPrevious()) {
echo "{FIRST}\n";
}
echo $oNeighborIterator->getPreviousKey() . " => " . $oNeighborIterator->getPrevious() . " -----> ";
echo "[ " . $key . " => " . $value . " ] -----> ";
echo $oNeighborIterator->getNextKey() . " => " . $oNeighborIterator->getNext() . "\n";
if (!$oNeighborIterator->hasNext()) {
echo "{LAST}\n";
}
}
You could get the keys of the array before the foreach, then use a counter to check the next element, something like:
//$arr is the array you wish to cycle through
$keys = array_keys($arr);
$num_keys = count($keys);
$i = 1;
foreach ($arr as $a)
{
if ($i < $num_keys && $arr[$keys[$i]] == $a)
{
// we have a match
}
$i++;
}
This will work for both simple arrays, such as array(1,2,3), and keyed arrays such as array('first'=>1, 'second'=>2, 'thrid'=>3).
A foreach loop in php will iterate over a copy of the original array, making next() and prev() functions useless. If you have an associative array and need to fetch the next item, you could iterate over the array keys instead:
foreach (array_keys($items) as $index => $key) {
// first, get current item
$item = $items[$key];
// now get next item in array
$next = $items[array_keys($items)[$index + 1]];
}
Since the resulting array of keys has a continuous index itself, you can use that instead to access the original array.
Be aware that $next will be null for the last iteration, since there is no next item after the last. Accessing non existent array keys will throw a php notice. To avoid that, either:
Check for the last iteration before assigning values to $next
Check if the key with index + 1 exists with array_key_exists()
Using method 2 the complete foreach could look like this:
foreach (array_keys($items) as $index => $key) {
// first, get current item
$item = $items[$key];
// now get next item in array
$next = null;
if (array_key_exists($index + 1, array_keys($items))) {
$next = $items[array_keys($items)[$index + 1]];
}
}
$next_data = $data;
$prev_key = null;
$prev_value = null;
foreach($data as $key => $value)
{
array_shift($next_data);
$next_key = key($next_data);
$next_value = $next_data[$next_key] ?? null;
// Do something here...
$prev_key = $key;
$prev_value = $value;
}
or if the array is associative then you could use current() similar to Andrei Krasutski's solution and key()
$values = [];
array_push($values, ["XYZ"=>100]);
array_push($values, ["ABC"=>10]);
array_push($values, ["XYZ"=>130]);
array_push($values, ["DEF"=>4]);
array_push($values, ["XYZ"=>5]);
$count = count($values);
foreach ($values as $index => $currentValue) {
if ($index < $count - 1) {
$nextValue = $values[$index + 1];
echo key($currentValue) . "=" . current($currentValue) . " followed by " . key($nextValue) . "/" . current($nextValue) . "<br>\n";
} else {
echo key($currentValue) . "=" . current($currentValue);
}
}
See https://onlinephp.io/c/dc58d for a running example.
or if the array is using named pairs:
$values = [];
array_push($values, ["type"=>"XYZ", "value"=>100]);
array_push($values, ["type"=>"ABC", "value"=>10]);
array_push($values, ["type"=>"XYZ", "value"=>130]);
array_push($values, ["type"=>"DEF", "value"=>"Lorem"]);
array_push($values, ["type"=>"XYZ", "value"=>5]);
$count = count($values);
foreach ($values as $index => $currentValue) {
if ($index < $count - 1) {
$nextValue = $values[$index + 1];
echo $currentValue['type'] . "=" . $currentValue['value']
. " followed by " . $nextValue['type'] . "/" . $nextValue['value'] . "<br>\n";
} else {
echo $currentValue['type'] . "=" . $currentValue['value'];
}
}

Implement linked list in php

How should I implement a linked list in PHP? Is there a implementation built in into PHP?
I need to do a lot of insert and delete operations, and at same time I need to preserve order.
I'd like to use only PHP without any special extensions.
There is SplDoublyLinkedList. Is this okay, too?
Here is a linked list implementation in PHP pulled from: http://www.codediesel.com/php/linked-list-in-php/ which can add, delete, reverse and empty a linkedlist in PHP.
<?php
class ListNode
{
public $data;
public $next;
function __construct($data)
{
$this->data = $data;
$this->next = NULL;
}
function readNode()
{
return $this->data;
}
}
class LinkList
{
private $firstNode;
private $lastNode;
private $count;
function __construct()
{
$this->firstNode = NULL;
$this->lastNode = NULL;
$this->count = 0;
}
//insertion at the start of linklist
public function insertFirst($data)
{
$link = new ListNode($data);
$link->next = $this->firstNode;
$this->firstNode = &$link;
/* If this is the first node inserted in the list
then set the lastNode pointer to it.
*/
if($this->lastNode == NULL)
$this->lastNode = &$link;
$this->count++;
}
//displaying all nodes of linklist
public function readList()
{
$listData = array();
$current = $this->firstNode;
while($current != NULL)
{
array_push($listData, $current->readNode());
$current = $current->next;
}
foreach($listData as $v){
echo $v." ";
}
}
//reversing all nodes of linklist
public function reverseList()
{
if($this->firstNode != NULL)
{
if($this->firstNode->next != NULL)
{
$current = $this->firstNode;
$new = NULL;
while ($current != NULL)
{
$temp = $current->next;
$current->next = $new;
$new = $current;
$current = $temp;
}
$this->firstNode = $new;
}
}
}
//deleting a node from linklist $key is the value you want to delete
public function deleteNode($key)
{
$current = $this->firstNode;
$previous = $this->firstNode;
while($current->data != $key)
{
if($current->next == NULL)
return NULL;
else
{
$previous = $current;
$current = $current->next;
}
}
if($current == $this->firstNode)
{
if($this->count == 1)
{
$this->lastNode = $this->firstNode;
}
$this->firstNode = $this->firstNode->next;
}
else
{
if($this->lastNode == $current)
{
$this->lastNode = $previous;
}
$previous->next = $current->next;
}
$this->count--;
}
//empty linklist
public function emptyList()
{
$this->firstNode == NULL;
}
//insertion at index
public function insert($NewItem,$key){
if($key == 0){
$this->insertFirst($NewItem);
}
else{
$link = new ListNode($NewItem);
$current = $this->firstNode;
$previous = $this->firstNode;
for($i=0;$i<$key;$i++)
{
$previous = $current;
$current = $current->next;
}
$previous->next = $link;
$link->next = $current;
$this->count++;
}
}
}
$obj = new LinkList();
$obj->insertFirst($value);
$obj->insert($value,$key); // at any index
$obj->deleteNode($value);
$obj->readList();
Here is the code in php which will implement Linked List, only with the reference of head node i.e first node and then you add at first, last and delete a key, and also maintain the code of the keys in list.
<?php
/**
* Class Node
*/
class Node
{
public $data;
public $next;
public function __construct($item)
{
$this->data = $item;
$this->next = null;
}
}
/**
* Class LinkList
*/
class LinkList
{
public $head = null;
private static $count = 0;
/**
* #return int
*/
public function GetCount()
{
return self::$count;
}
/**
* #param mixed $item
*/
public function InsertAtFist($item) {
if ($this->head == null) {
$this->head = new Node($item);
} else {
$temp = new Node($item);
$temp->next = $this->head;
$this->head = $temp;
}
self::$count++;
}
/**
* #param mixed $item
*/
public function InsertAtLast($item) {
if ($this->head == null) {
$this->head = new Node($item);
} else {
/** #var Node $current */
$current = $this->head;
while ($current->next != null)
{
$current = $current->next;
}
$current->next = new Node($item);
}
self::$count++;
}
/**
* Delete the node which value matched with provided key
* #param $key
*/
public function Delete($key)
{
/** #var Node $current */
$current = $previous = $this->head;
while($current->data != $key) {
$previous = $current;
$current = $current->next;
}
// For the first node
if ($current == $previous) {
$this->head = $current->next;
}
$previous->next = $current->next;
self::$count--;
}
/**
* Print the link list as string like 1->3-> ...
*/
public function PrintAsList()
{
$items = [];
/** #var Node $current */
$current = $this->head;
while($current != null) {
array_push($items, $current->data);
$current = $current->next;
}
$str = '';
foreach($items as $item)
{
$str .= $item . '->';
}
echo $str;
echo PHP_EOL;
}
}
$ll = new LinkList();
$ll->InsertAtLast('KP');
$ll->InsertAtLast(45);
$ll->InsertAtFist(11);
$ll->InsertAtLast('FE');
$ll->InsertAtFist('LE');
$ll->InsertAtFist(100);
$ll->InsertAtFist(199);
$ll->InsertAtLast(500);
$ll->PrintAsList();
echo 'Total elements ' . $ll->GetCount();
echo PHP_EOL;
$ll->Delete(45);
$ll->PrintAsList();
echo 'Total elements ' . $ll->GetCount();
echo PHP_EOL;
$ll->Delete(500);
$ll->PrintAsList();
echo 'Total elements ' . $ll->GetCount();
echo PHP_EOL;
$ll->Delete(100);
$ll->PrintAsList();
echo 'Total elements ' . $ll->GetCount();
echo PHP_EOL;
Code out put as:
$ php LinkList.php
199->100->LE->11->KP->45->FE->500->
Total elements 8
199->100->LE->11->KP->FE->500->
Total elements 7
199->100->LE->11->KP->FE->
Total elements 6
199->LE->11->KP->FE->
Total elements 5
Here is another Linked list implementation using an array of elements. The add function keeps the elements sorted.
<?php
class LinkedList{
private $_head = null;
private $_list = array();
public function addNode($val) {
// add the first element
if(empty($this->_list)) {
$this->_head = $val;
$this->_list[$val] = null;
return;
}
$curr = $this->_head;
while ($curr != null || $curr === 0) {
// end of the list
if($this->_list[$curr] == null) {
$this->_list[$curr] = $val;
$this->_list[$val] = null;
return;
}
if($this->_list[$curr] < $val) {
$curr = $this->_list[$curr];
continue;
}
$this->_list[$val] = $this->_list[$curr];
$this->_list[$curr] = $val;
return;
}
}
public function deleteNode($val) {
if(empty($this->_list)) {
return;
}
$curr = $this->_head;
if($curr == $val) {
$this->_head = $this->_list[$curr];
unset($this->_list[$curr]);
return;
}
while($curr != null || $curr === 0) {
// end of the list
if($this->_list[$curr] == null) {
return;
}
if($this->_list[$curr] == $val) {
$this->_list[$curr] = $this->_list[$val];
unset($this->_list[$val]);
return;
}
$curr = $this->_list[$curr];
}
}
function showList(){
$curr = $this->_head;
while ($curr != null || $curr === 0) {
echo "-" . $curr;
$curr = $this->_list[$curr];
}
}
}
$list = new LinkedList();
$list->addNode(0);
$list->addNode(3);
$list->addNode(7);
$list->addNode(5);
$list->addNode(2);
$list->addNode(4);
$list->addNode(10);
$list->showList();
echo PHP_EOL;
$list->deleteNode(3);
$list->showList();
echo PHP_EOL;
$list->deleteNode(0);
$list->showList();
echo PHP_EOL;
The output is:
-0-2-3-4-5-7-10
-0-2-4-5-7-10
-2-4-5-7-10
I was also trying to write a program to create a linked list in PHP. Here is what I have written and it worked for me. I hope it helps to answer the question.
Created a php file. Name: LinkedList.php
{code}
<?php
require_once (__DIR__ . "/LinkedListNodeClass.php");
$node_1 = new Node();
Node::createNode($node_1, 5);
echo "\n Node 1 is created.";
$head = &$node_1;
echo "\n Head is intialized with Node 1.";
$node_2 = new Node();
Node::createNode($node_2, 1);
echo "\n Node 2 is created.";
Node::insertNodeInLinkedList($head, $node_2);
$node_3 = new Node();
Node::createNode($node_3, 11);
echo "\n Node 3 is created.";
Node::insertNodeInLinkedList($head, $node_3);
$node_4 = new Node();
Node::createNode($node_4, 51);
echo "\n Node 4 is created.";
Node::insertNodeInLinkedList($head, $node_4);
$node_5 = new Node();
Node::createNode($node_5, 78);
echo "\n Node 5 is created.";
Node::insertNodeInLinkedList($head, $node_5);
$node_6 = new Node();
Node::createNode($node_6, 34);
echo "\n Node 6 is created.";
Node::insertNodeInLinkedList($head, $node_6);
$node_7 = new Node();
Node::createNode($node_7, 99);
echo "\n Node 7 is created.";
Node::insertNodeInHeadOfLinkedList($head, $node_7);
$node_8 = new Node();
Node::createNode($node_8, 67);
echo "\n Node 8 is created.";
Node::insertNodeInHeadOfLinkedList($head, $node_8);
$node_9 = new Node();
Node::createNode($node_9, 101);
echo "\n Node 9 is created.";
Node::insertNodeAfterAPositionInLinkedList($head, 5, $node_9);
$node_10 = new Node();
Node::createNode($node_10, 25);
echo "\n Node 10 is created.";
Node::insertNodeAfterAPositionInLinkedList($head, 2, $node_10);
echo "\n Displaying the linked list: \n";
Node::displayLinkedList($head);
?>
{code}
This file is calling a class to create, insert and display nodes in linked list. Name: LinkedListNodeClass.php
{code}
<?php
class Node {
private $data;
private $next;
public function __construct() {
//does nothing...
}
//Creates a node
public function createNode($obj, $value) {
$obj->data = $value;
$obj->next = NULL;
}
//Inserts a created node in the end of a linked list
public function insertNodeInLinkedList($head, &$newNode) {
$node = $head;
while($node->next != NULL){
$node = $node->next;
}
$node->next = $newNode;
}
//Inserts a created node in the start of a linked list
public function insertNodeInHeadOfLinkedList(&$head, &$newNode) {
$top = $head;
$newNode->next = $top;
$head = $newNode;
}
//Inserts a created node after a position of a linked list
public function insertNodeAfterAPositionInLinkedList($head, $position, &$newNode) {
$node = $head;
$counter = 1;
while ($counter < $position){
$node = $node->next;
$counter++;
}
$newNode->next = $node->next;
$node->next = $newNode;
}
//Displays the Linked List
public function displayLinkedList($head) {
$node = $head;
print($node->data); echo "\t";
while($node->next != NULL){
$node = $node->next;
print($node->data); echo "\t";
}
}
}
?>
{code}
If don't think most people understand what linked lists are. The basic idea is you want to keep data organised is such a way that you can access the previous and next node using the current node. The other features like add, delete, insert, head etc are sugar, though necessary. I think the SPL package does cover a lot. Problem is I need a PHP 5.2.9 class. Guess I've to implement it myself.
Just to clarify, implementing linked list in PHP using PHP arrays probably is not a good idea, because PHP array is hash-table under the hood (not simple low-level arrays). Simultaneously, you don't get advantages of pointers.
Instead, you can implement data structures like linked list for PHP using extensions, that means you are implementing a data structure in C to PHP.
Spl data structures are an example, another example is php-ds extension, specially in case of linked lists, you can use this: https://www.php.net/manual/en/class.ds-sequence.php
Sequence ADT is the unification of List ADT and Vector ADT, so you can use Sequence ADT implemented data structures as lists.
Hope this could help someone choose wisely.
// Here's a basic implementation of SplDoublyLinkedList using PHP.
$splDoubleLinkedList = new SplDoublyLinkedList();
$splDoubleLinkedList->push('a');
$splDoubleLinkedList->push('3');
$splDoubleLinkedList->push('v');
$splDoubleLinkedList->push('1');
$splDoubleLinkedList->push('p');
// $splDoubleLinkedList->unshift('10');
// $splDoubleLinkedList->pop();
$splDoubleLinkedList->add(3, 3.0);
// First of all, we need to rewind list.
$splDoubleLinkedList->rewind();
// Use while, check if the list has valid node.
while($splDoubleLinkedList->valid()){
// Print current node's value.
echo $splDoubleLinkedList->current()."\n";
// Turn the cursor to next node.
$splDoubleLinkedList->next();
}

Optimizing Trie implementation

For no reason other than fun I implemented a Trie today. At the moment it supports add() and search(), remove() should also be implemented but I think that's fairly straight forward.
It is fully functional, but filling the Trie with data takes a little too much for my taste. I'm using this list as datasource: http://www.isc.ro/lists/twl06.zip (found somewhere else on SO). It takes ~11s to load. My initial implementation took ~15s so I already gave it a nice performance boost, but I'm still not satisfied :)
My question is: what else could give me a (substantial) performance boost? I'm not bound by this design, a complete overhaul is acceptable.
class Trie
{
private $trie;
public function __construct(TrieNode $trie = null)
{
if($trie !== null) $this->trie = $trie;
else $this->trie = new TrieNode();
$this->counter = 0;
}
public function add($value, $val = null)
{
$str = '';
$trie_ref = $this->trie;
foreach(str_split($value) as $char)
{
$str .= $char;
$trie_ref = $trie_ref->addNode($str);
}
$trie_ref->value = $val;
return true;
}
public function search($value, $only_words = false)
{
if($value === '') return $this->trie;
$trie_ref = $this->trie;
$str = '';
foreach(str_split($value) as $char)
{
$str .= $char;
if($trie_ref = $trie_ref->getNode($str))
{
if($str === $value) return ($only_words ? $this->extractWords($trie_ref) : new self($trie_ref));
continue;
}
return false;
}
return false;
}
public function extractWords(TrieNode $trie)
{
$res = array();
foreach($trie->getChildren() as $child)
{
if($child->value !== null) $res[] = $child->value;
if($child->hasChildren()) $res = array_merge($res, $this->extractWords($child));
}
return $res;
}
}
class TrieNode
{
public $value;
protected $children = array();
public function addNode($index)
{
if(isset($this->children[$index])) return $this->children[$index];
return $this->children[$index] = new self();
}
public function getNode($index)
{
return (isset($this->children[$index]) ? $this->children[$index] : false);
}
public function getChildren()
{
return $this->children;
}
public function hasChildren()
{
return count($this->children)>0;
}
}
Don't know php but,
in the following methods:
public function add($value, $val = null)
{
$str = '';
$trie_ref = $this->trie;
foreach(str_split($value) as $char)
{
$str .= $char;
$trie_ref = $trie_ref->addNode($str);
}
$trie_ref->value = $val;
return true;
}
public function search($value, $only_words = false)
{
if($value === '') return $this->trie;
$trie_ref = $this->trie;
$str = '';
foreach(str_split($value) as $char)
{
$str .= $char;
if($trie_ref = $trie_ref->getNode($str))
{
if($str === $value) return ($only_words ? $this->extractWords($trie_ref) : new self($trie_ref));
continue;
}
return false;
}
return false;
}
Why do you even need the $str .= $char (which I suppose is append)? This itself changes your O(n) time addition/searching to Omega(n^2) (n is length of $value) instead of O(n).
In a trie, you usually walk the trie while walking the string i.e you find the next node based on the current character, rather than the current prefix.
I suppose this implementation is for a Key|value type of insertion and lookup? Here is one that handles [English] words.
class Trie {
static function insert_word(Node $root, $text)
{
$v = $root;
foreach(str_split($text) as $char) {
$next = $v->children[$char];
if ($next === null)
{
$v->children[$char] = $next = new Node();
}
$v = $next;
}
$v->leaf = true;
}
static function get_words_sorted(Node $node, $text)
{
$res = array();
for($ch = 0; $ch < 128; $ch++) {
$child = $node->children[chr($ch)];
if ($child !== null)
{
$res = array_merge($res, Trie::get_words_sorted($child, $text . chr($ch)));
}
}
if ($node->leaf === true)
{
$res[] = $text;
}
return $res;
}
static function search(Node $root, $text)
{
$v = $root;
while($v !== null)
{
foreach(str_split($text) as $char) {
$next = $v->children[$char];
if ($next === null)
{
return false;
}
else
{
$v = $next;
}
}
if($v->leaf === true)
{
return true;
}
else
{
return false;
}
}
return false;
}
}
class Node {
public $children;
public $leaf;
function __construct()
{
$children = Array();
}
}
Example usage
$root = new Node();
$words = Array("an", "ant", "all", "allot", "alloy", "aloe", "are", "ate", "be");
for ($i = 0; $i < sizeof($words); $i++)
{
Trie::insert_word($root, $words[$i]);
}
$search_words = array("alloy", "ant", "bee", "aren't", "allot");
foreach($search_words as $word)
{
if(Trie::search($root, $word) === true)
{
echo $word . " IS in my dictionary<br/>";
}
else
{
echo $word . " is NOT in my dictionary <br/>";
}
}

Categories