<?
/*
Double-Ended Linked-List PHP class.
Scott Hurring (scott@furt.com)
This code is public domain, but i do hope that if you use
portions of it you give me some credit. Thanks.
I felt like learning about PHP References, so i wrote
this little implementation of a Linked List for PHP.
... PHP supports all this stuff natively, so this code
really doesn't serve much purpose, other than being a
good tool to help me learn a bit more about references.
In PHP, if you have an array of "nodes", see:
array_push(), array_unshift(), array_pop(), and array_shift();
The "node" structure ($this->node) can be *any* kind of array you want.
// Functions provided by this class
push($node) Adds the node to the END of the list
pop() Removes a node from the END of the list
unshift($node) Adds the node to the BEGINNING of the list
shift() Removes a node from the BEGINNING of the list
// How the code works
// Get a fresh node to populate
$node = $list->node();
// Populate it
$node['field'] = "Some data";
// Put it onto the list
$list->push($node);
$list->unshift($node);
// You get the idea...
*/
class LinkedList
{
/*
Define node structure here
(don't touch 'next', it points to the next node)
*/
var $_node = array(
// Contains reference to next node
'next' => NULL,
// Define your node structure below:
// Process ID
'pid' => 0,
// Time of process start
'start' => 0,
// Duration of process
'duration' => 0,
);
// Head is a reference to first node
// (which should always be an empty 'dummy' head node)
var $head = NULL;
// Number of nodes in the linked list
// (not including the 'dummy' head node)
var $count = 0;
// Set $dbg=1 to print some debugging info
var $dbg = 0;
// Constructor
function LinkedList()
{
// Create and insert 'dummy' head node at beginning of list
$dummy_head = $this->_node;
$this->head = &$dummy_head;
$this->debug("[LinkedList]: Constructor, creating dumy head");
}
/*
Put $node onto BOTTOM of list
*/
function unshift(&$node)
{
// Get pointer to first node
$first =& $this->first();
// $node is now the first item
$node['next'] = $first;
// point the dummy head at $node
$this->head['next'] = $node;
$this->count++;
return 1;
}
/*
Remove (and return) BOTTOM element from the list
Returns NULL if list is empty
*/
function shift()
{
// Get copy of first node
$first = $this->first();
// There is no first item
if ($first == NULL)
return NULL;
// Point the 'dummy' head at the node after the removed node ($first)
$this->head['next'] = $first['next'];
// Clear pointers for the removed node
$first['next'] = NULL;
$first['prev'] = NULL;
$this->count--;
return $first;
}
/*
Put $node onto the TOP of the list
*/
function push(&$node)
{
// Get pointer to last node
$last =& $this->last();
$this->debug("[push]: current last = {$last['pid']} new last = {$node['pid']}");
// Insert $node after the current last element
$last['next'] = $node;
// $node is now the end of the list
$node['next'] = NULL;
$this->count++;
return 1;
}
/*
Remove (and return) TOP node from the list
Returns NULL if list is empty
*/
function pop()
{
$last = $this->last();
$next_to_last =& $this->next_to_last();
// If the last item is the head, then it's an empty list
if ($last == $this->head)
return NULL;
$this->debug("[pop]: last = {$last['pid']} next_to_last = {$next_to_last['pid']}");
// next_to_last is now the end
$next_to_last['next'] = NULL;
$this->count--;
return $last;
}
/*
Return the BOTTOM node without modifying the list.
Returns NULL if list is empty
$node =& $this->first() returns pointer to actual node
$node = $this->first() returns copy of node data
*/
function &first()
{
// Pointer to the first 'non-dummy' element
$curr =& $this->head['next'];
// List is empty
if ($curr == NULL)
return NULL;
return $curr;
}
/*
Return the TOP node without modifying the list.
Returns NULL if list is empty
$node =& $this->last() returns pointer to actual node
$node = $this->last() returns copy of node data
*/
function &last()
{
// Get pointer to the 'dummy' head node
$curr =& $this->head;
// Iterate through list BOTTOM->TOP, until reaching the TOP node
while($curr['next'] != NULL)
$curr = &$curr['next'];
return $curr;
}
/*
Return the next-to-last node
either return a copy or a ref depending on how it's called
*/
function &next_to_last()
{
// Pointer to 'dummy' head node
$curr =& $this->head;
// Iterate through the list BOTTOM->TOP, until reaching TOP-1 node
while($curr['next']['next'] != NULL)
$curr = &$curr['next'];
return $curr;
}
/*
Update the contents of an existing node
*/
function update($index, &$node)
{
// Pointer to the node that's being updated
$curr =& $this->search($index);
$this->debug("[update]: (index=$index), (pid={$curr['pid']})");
// Set the pointer correctly in the new node, then
// replace the current node with the new data
$node['next'] = $curr['next'];
$curr = $node;
return 1;
}
/*
Return a specific node
*/
function &search($index)
{
// Pointer to first data node
$curr =& $this->first();
$i = 0;
while ($i++ < ($index-1)) {
if ($curr == NULL)
return NULL;
$curr = &$curr['next'];
}
return $curr;
}
/*
Return an empty node struct to popuate and 'push' or 'unshift' onto the list
*/
function new_node()
{
return $_node;
}
/*
Show all items in the list BOTTOM->TOP
*/
function show()
{
print "\nShowing list (count==". $this->count .")\n";
// Copy of BOTTOM node
$curr = $this->first();
if ($curr == NULL)
print "\tNOTHING TO SHOW\n";
while($curr != NULL) {
print "\tPID=". $curr['pid'];
print " (next: ". $curr['next']['pid'] .")";
print " (time: ". $curr['time'] .")";
print "\n";
$curr = $curr['next'];
}
print "\n";
return 1;
}
/*
Print debugging output, if ($this->dbg)
*/
function debug($text)
{
if ($this->dbg == 1)
print $text ."\n";
return 1;
}
} // End LinkedList class
?>
|