正文
数据结构
线性表 顺序存储
线性表是⼀个有限序列,表中各个元素是相继排列的,且每两个相邻元素之间都有直接前驱和直接后继的逻辑关系。
线性表有 顺序表、 单链表、 循环链表、 双向链表 等。
定义:线性表(Linear List) :是由n(n≧0)个数据元素(结点) [a1,a2, …an]
组成的有限序列。数据元素是一个抽象的符号,其具体含义在不同的情况下一般不同。
该序列中的所有结点具有相同的数据类型。其中数据元素的个数n称为线性表的长度。
当n=0时,称为空表。
当n>0时,将非空的线性表记作: (a1,a2,…an) a1称为线性表的第一个(首)结点,an称为线性表的最后一个(尾)结点。
基本说明:线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。 注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储) 但是把最后一个数据元素的尾指针指向了首位结点)。
基本特点:
- 存在一个唯一的被称为
第一个
的数据元素 - 存在一个唯一的被称为
最后一个
的数据元素 - 除第一个元素外,每个元素均有唯一一个直接前驱
- 除最后一个元素外,每个元素均有唯一一个直接后继
<?php
/**
* LinearList 线性表
*
* -------------------------------------------------------------
* [线性表顺序存储]
* =======
* 把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里,用这种方法存储的线性表简称线性表。
* -------------------------------------------------------------
* [顺序存储的线性表的特点]
* =======
* - 线性表的逻辑顺序与物理顺序一致;
* - 数据元素之间的关系是以元素在计算机内“物理位置相邻”来体现。
* -------------------------------------------------------------
* @param array
*/
class LinearOrder extends ArrayObject
{
const PRECURSOR_KEY = 0;
const PRECURSOR_VALUE = 1;
const SUBSEQUENT_KEY = 0;
const SUBSEQUENT_VALUE = 1;
const ASSIGN_KEY = 0;
const DEFAULT_KEY = 1;
const DELETE_KEY = 0;
const DELETE_VALUE = 1;
/**
* @var array|mixed 线性表
*/
public $oll;
/**
* LinearList constructor. 线性表初始化
*
* @param array $oll
*/
public function __construct($oll = array ())
{
echo '---------------------------'.PHP_EOL;
echo var_export($oll).PHP_EOL;
echo '---------------------------'.PHP_EOL;
parent::__construct($oll);
$this->oll = $this->getIterator();
}
/**
* @return void 清空线性表
*/
public function __destruct()
{
unset($this->oll);
}
/**
* 调试用请无视
*
* @param $name
* @param $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
$this->preDispatch(); // 调试用,请无视
return call_user_func_array(array($this, $name), $arguments);
}
/**
* 判断线性表是否为空
*
* @return boolean 为空返回true,否则返回false
*/
protected function isEmpty()
{
return $this->getLength() > 0 ? false : true;
}
/**
* 返回线性表的长度
*
* @return int
*/
protected function getLength()
{
return $this->oll->count();
}
/**
* 返回线性表中下标为$key的元素
*
* @param mixed $key 线性表元素的下标
* @return mixed
*/
protected function getElement($key)
{
return $this->oll->offsetGet($key);
}
/**
* 返回线性表中某个元素的位置
*
* @param mixed $value 线性表中某个元素的值
* @return int 从1开始,如果返回-1表示不存在该元素
*/
protected function getElementPosition($value)
{
$i = 0;
$this->oll->rewind();
while ($this->oll->valid()) {
$i++;
if (strcmp($value, $this->oll->current()) === 0) {
return $i;
}
$this->oll-> next();
}
return -1;
}
/**
* 返回线性表中某个元素的直接前驱元素
*
* @param string $value 线性表中某个元素的值
* @param int $tag 如果$value为下标则为1, 如果$value为元素值则为0
* @return array|bool array('value'=>...)直接前驱元素值,array('key'=>...)直接前驱元素下标
*/
protected function getElementPrecursor($value, $tag = self::PRECURSOR_VALUE)
{
$i = 0;
$prev = null;
$this->oll->rewind();
while ($this->oll->valid()) {
$key = $this->oll->key();
$current = $this->oll->current();
if (strcmp($key, $value) === 0) {
if ($i == 1) {
return false;
}
return array ('value' => $this->getElement($prev), 'key' => $prev);
}
if ($tag == self::PRECURSOR_VALUE) {
if (strcmp($current, $value) === 0) {
if ($i == 1) {
return false;
}
return array ('value' => $this->getElement($prev), 'key' => $prev);
}
}
$i++;
$prev = $this->oll->key();
$this->oll->next();
}
}
/**
* 返回某个元素的直接后继元素
*
* @param string $value $value线性表中某个元素的值
* @param int $tag 如果$value为下标则为1,如果$value为元素值则为0
* @return array|bool array('value'=>...)直接后继元素值,array('key'=>...)直接后继元素下标
*/
protected function getElementSubsequent($value, $tag = self::SUBSEQUENT_KEY)
{
$i = 0;
$len = $this->getLength();
$this->oll->rewind();
while ($this->oll->valid()) {
$key = $this->oll->key();
$current = $this->oll->current();
if ($tag == self::SUBSEQUENT_KEY) {
if (strcmp($key, $value) == 0) {
if ($i == $len) {
return false;
}
$this->oll->next();
return array ('value' => $this->oll->current(), 'key' => $this->oll->key());
}
}
if ($tag == self::SUBSEQUENT_VALUE) {
if (strcmp($current, $value) == 0) {
if ($i == $len) {
return false;
}
$this->oll->next();
return array ('value' => $this->oll->current(), 'key' => $this->oll->key());
}
}
$i++;
$this->oll->next();
}
return false;
}
/**
* 在指定位置插入一个新的结点
*
* @param string $p 新结点插入位置,从0开始
* @param string $value 线性表新结点的值
* @param null $key 线性表新结点的下标
* @param int $tag 是否指定新结点的下标,1表示默认下标,0表示指定下标
* @return bool 插入成功返回true,失败返回false
*/
protected function getInsertElement($p, $value, $key = null, $tag = self::DEFAULT_KEY)
{
$p = (int)$p;
$i = 0;
if ($p > $this->getLength() || $p < 1) {
return false;
}
$this->oll->rewind();
while ($this->oll->valid()) {
if ($i != $p) {
$i++;
$this->oll->next();
}
switch ($tag){
case self::DEFAULT_KEY:
$this->oll->append($value);
break 2;
case self::ASSIGN_KEY:
$this->oll->offsetSet($key, $value);
break 2;
}
}
return true;
}
/**
* 根据元素位置返回线性表中的某个元素
*
* @param mixed $position 元素位置从1开始
* @return array|bool array('value'=>...)元素值,array('key'=>...)元素下标
*/
protected function getElemForPos($position)
{
$i = 0;
$len = $this->getLength();
$position = (int)$position;
if ($position > $len || $position < 1) {
return false;
}
$this->oll->rewind();
while ($this->oll->valid()) {
if ($i == $position) {
return array ('value' => $this->oll->current(), 'key' => $this->oll->key());
}
$i++;
$this->oll->next();
}
}
/**
* 根据下标或者元素值删除线性表中的某个元素
*
* @param mixed $value 元素下标或者值
* @param int $tag 0表示$value为下标,1表示$value为元素值
* @return bool 成功返回true,失败返回false
*/
protected function getDeleteElement($value, $tag = self::DELETE_KEY)
{
$this->oll->rewind();
while ($this->oll->valid())
{
$key = $this->oll->key();
$current = $this->oll->current();
if ($tag == self::DELETE_KEY) {
if (strcmp($key, $value) === 0) {
$this->oll->offsetUnset($key);
}
}
if ($tag == self::DELETE_VALUE) {
if (strcmp($current, $value) === 0) {
$this->oll->offsetUnset($key);
}
}
$this->oll->next();
}
return true;
}
/**
* 根据元素位置删除线性表中的某个元素
*
* @param int $position 元素位置从1开始
* @return bool 成功返回true,失败返回false
*/
protected function getDeleteEleForPos($position)
{
$len = $this->getLength();
$i = 0;
$position = (int)$position;
if ($position > $len || $position < 1) {
return false;
}
$this->oll->rewind();
while ($this->oll->valid()) {
$key = $this->oll->key();
if ($i == $position) {
$this->oll->offsetUnset($key);
}
$i++;
$this->oll->next();
}
return true;
}
/**
* 调试用
*
* @param bool $isDebug
* @return bool
*/
protected function preDispatch($isDebug = true)
{
if (!$isDebug) {
return false;
}
$debug = debug_backtrace()[1];
$reflection = new ReflectionMethod($this, $debug['args'][0]);
$args = '';
if(isset($debug['args'][1])){
foreach ($debug['args'][1] as &$value){
if( is_array($value )){
$args .= json_encode($debug['args'][1]).', ';
}else{
$args .= $value.', ';
}
}
}
$args = trim($args,', ');
echo "\t".$reflection->getDocComment() . PHP_EOL;
echo "\t{$debug['args'][0]}({$args})\n" . PHP_EOL;
}
}
$echo = function ($str, $action) {
echo $str . "\t->\t" . var_export($action, true) . PHP_EOL;
echo "--------------------------- " . PHP_EOL;
};
$oll = new LinearOrder(array ('name' => 'Jack', 10, "age", 'msg' => 10, 666));
$echo('判断线性表是否为空', $oll->isEmpty());
$echo('返回线性表的长度', $oll->getLength());
$echo('根据下标返回线性表中的某个元素', $oll->getElement(1));
$echo('返回线性表中某个元素的位置', $oll->getElementPosition(666));
$echo('返回线性表中某个元素的直接前驱元素', $oll->getElementPrecursor(666, LinearOrder::PRECURSOR_VALUE));
$echo('返回线性表中某个元素的直接后继元素', $oll->getElementSubsequent(0, LinearOrder::SUBSEQUENT_KEY));
$echo('根据元素位置返回线性表中的某个元素', $oll->getElemForPos(2));
$echo('根据下标或者元素值删除线性表中的某个元素', $oll->getDeleteElement('name', LinearOrder::DELETE_KEY));
$echo('在指定位置插入一个新的结点', $oll->getInsertElement(3, "插入新节点", "qzone", LinearOrder::ASSIGN_KEY));
$echo('$oll->oll的内容 ', $oll->oll);
线性表顺序存储用到了Iterator:
/**
* Interface for external iterators or objects that can be iterated
* themselves internally.
* @link https://php.net/manual/en/class.iterator.php
*/
interface Iterator extends Traversable {
/**
* Return the current element
* @link https://php.net/manual/en/iterator.current.php
* @return mixed Can return any type.
*/
public function current();
/**
* Move forward to next element
* @link https://php.net/manual/en/iterator.next.php
* @return void Any returned value is ignored.
*/
public function next();
/**
* Return the key of the current element
* @link https://php.net/manual/en/iterator.key.php
* @return string|float|int|bool|null scalar on success, or null on failure.
*/
public function key();
/**
* Checks if current position is valid
* @link https://php.net/manual/en/iterator.valid.php
* @return bool The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*/
public function valid();
/**
* Rewind the Iterator to the first element
* @link https://php.net/manual/en/iterator.rewind.php
* @return void Any returned value is ignored.
*/
public function rewind();
}
继承的ArrayObject类:
/**
* This class allows objects to work as arrays.
* @link https://php.net/manual/en/class.arrayobject.php
*/
class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable {
/**
* Properties of the object have their normal functionality when accessed as list (var_dump, foreach, etc.).
*/
const STD_PROP_LIST = 1;
/**
* Entries can be accessed as properties (read and write).
*/
const ARRAY_AS_PROPS = 2;
/**
* Construct a new array object
* @link https://php.net/manual/en/arrayobject.construct.php
* @param array|object $array The input parameter accepts an array or an Object.
* @param int $flags Flags to control the behaviour of the ArrayObject object.
* @param string $iteratorClass Specify the class that will be used for iteration of the ArrayObject object. ArrayIterator is the default class used.
*
*/
public function __construct($array = array(), $flags = 0, $iteratorClass = "ArrayIterator") { }
/**
* Returns whether the requested index exists
* @link https://php.net/manual/en/arrayobject.offsetexists.php
* @param mixed $key <p>
* The index being checked.
* </p>
* @return bool true if the requested index exists, otherwise false
*/
public function offsetExists($key) { }
/**
* Returns the value at the specified index
* @link https://php.net/manual/en/arrayobject.offsetget.php
* @param mixed $key <p>
* The index with the value.
* </p>
* @return mixed|false The value at the specified index or false.
*/
public function offsetGet($key) { }
/**
* Sets the value at the specified index to newval
* @link https://php.net/manual/en/arrayobject.offsetset.php
* @param mixed $key <p>
* The index being set.
* </p>
* @param mixed $value <p>
* The new value for the <i>index</i>.
* </p>
* @return void
*/
public function offsetSet($key, $value) { }
/**
* Unsets the value at the specified index
* @link https://php.net/manual/en/arrayobject.offsetunset.php
* @param mixed $key <p>
* The index being unset.
* </p>
* @return void
*/
public function offsetUnset($key) { }
/**
* Appends the value
* @link https://php.net/manual/en/arrayobject.append.php
* @param mixed $value <p>
* The value being appended.
* </p>
* @return void
*/
public function append($value) { }
/**
* Creates a copy of the ArrayObject.
* @link https://php.net/manual/en/arrayobject.getarraycopy.php
* @return array a copy of the array. When the <b>ArrayObject</b> refers to an object
* an array of the public properties of that object will be returned.
*/
public function getArrayCopy() { }
/**
* Get the number of public properties in the ArrayObject
* When the <b>ArrayObject</b> is constructed from an array all properties are public.
* @link https://php.net/manual/en/arrayobject.count.php
* @return int The number of public properties in the ArrayObject.
*/
public function count() { }
/**
* Gets the behavior flags.
* @link https://php.net/manual/en/arrayobject.getflags.php
* @return int the behavior flags of the ArrayObject.
*/
public function getFlags() { }
/**
* Sets the behavior flags.
* @link https://php.net/manual/en/arrayobject.setflags.php
* @param int $flags <p>
* The new ArrayObject behavior.
* It takes on either a bitmask, or named constants. Using named
* constants is strongly encouraged to ensure compatibility for future
* versions.
* </p>
* <p>
* The available behavior flags are listed below. The actual
* meanings of these flags are described in the
* predefined constants.
* <table>
* ArrayObject behavior flags
* <tr valign="top">
* <td>value</td>
* <td>constant</td>
* </tr>
* <tr valign="top">
* <td>1</td>
* <td>
* ArrayObject::STD_PROP_LIST
* </td>
* </tr>
* <tr valign="top">
* <td>2</td>
* <td>
* ArrayObject::ARRAY_AS_PROPS
* </td>
* </tr>
* </table>
* </p>
* @return void
*/
public function setFlags($flags) { }
/**
* Sort the entries by value
* @link https://php.net/manual/en/arrayobject.asort.php
* @param int $flags [optional]
* @return void
*/
public function asort($flags = SORT_REGULAR) { }
/**
* Sort the entries by key
* @link https://php.net/manual/en/arrayobject.ksort.php
* @param int $flags [optional]
* @return void
*/
public function ksort($flags = SORT_REGULAR) { }
/**
* Sort the entries with a user-defined comparison function and maintain key association
* @link https://php.net/manual/en/arrayobject.uasort.php
* @param callback $callback <p>
* Function <i>cmp_function</i> should accept two
* parameters which will be filled by pairs of entries.
* The comparison function must return an integer less than, equal
* to, or greater than zero if the first argument is considered to
* be respectively less than, equal to, or greater than the
* second.
* </p>
* @return void
*/
public function uasort($callback) { }
/**
* Sort the entries by keys using a user-defined comparison function
* @link https://php.net/manual/en/arrayobject.uksort.php
* @param callback $callback <p>
* The callback comparison function.
* </p>
* <p>
* Function <i>cmp_function</i> should accept two
* parameters which will be filled by pairs of entry keys.
* The comparison function must return an integer less than, equal
* to, or greater than zero if the first argument is considered to
* be respectively less than, equal to, or greater than the
* second.
* </p>
* @return void
*/
public function uksort($callback) { }
/**
* Sort entries using a "natural order" algorithm
* @link https://php.net/manual/en/arrayobject.natsort.php
* @return void
*/
public function natsort() { }
/**
* Sort an array using a case insensitive "natural order" algorithm
* @link https://php.net/manual/en/arrayobject.natcasesort.php
* @return void
*/
public function natcasesort() { }
/**
* Unserialize an ArrayObject
* @link https://php.net/manual/en/arrayobject.unserialize.php
* @param string $data <p>
* The serialized <b>ArrayObject</b>.
* </p>
* @return void The unserialized <b>ArrayObject</b>.
*/
public function unserialize($data) { }
/**
* Serialize an ArrayObject
* @link https://php.net/manual/en/arrayobject.serialize.php
* @return string The serialized representation of the <b>ArrayObject</b>.
*/
public function serialize() { }
/**
* @return array
* @since 7.4
*/
public function __debugInfo(){}
/**
* @return array
* @since 7.4
*/
public function __serialize(): array {}
/**
* @param array $data
* @since 7.4
*/
public function __unserialize(array $data): void {}
/**
* Create a new iterator from an ArrayObject instance
* @link https://php.net/manual/en/arrayobject.getiterator.php
* @return ArrayIterator An iterator from an <b>ArrayObject</b>.
*/
public function getIterator() { }
/**
* Exchange the array for another one.
* @link https://php.net/manual/en/arrayobject.exchangearray.php
* @param mixed $array <p>
* The new array or object to exchange with the current array.
* </p>
* @return array the old array.
*/
public function exchangeArray($array) { }
/**
* Sets the iterator classname for the ArrayObject.
* @link https://php.net/manual/en/arrayobject.setiteratorclass.php
* @param string $iteratorClass <p>
* The classname of the array iterator to use when iterating over this object.
* </p>
* @return void
*/
public function setIteratorClass($iteratorClass) { }
/**
* Gets the iterator classname for the ArrayObject.
* @link https://php.net/manual/en/arrayobject.getiteratorclass.php
* @return string the iterator class name that is used to iterate over this object.
*/
public function getIteratorClass() { }
}
线性表 单链存储
<?php
/**
* LinearChain 线性表 - 单链表存储
* [线性表单链存储]
* =======
* 用一组任意的存储单元存储线性表中的数据元素,用这种方法存储的线性表简称线性链表。
* -------------------------------------------------------------
* [单链存储的线性表的特点]
* =======
* - 存储链表中结点的一组任意的存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上
* - 链表中结点的逻辑顺序和物理顺序不一定相同
* -------------------------------------------------------------
*/
class LinearChain
{
/**
* @var string 头结点指针
*/
public $next;
/**
* @var string 结点数据
*/
public $elem;
/**
* @var int 链表长度
*/
public $length;
/**
* LinearChain constructor. 线性表初始化
*/
public function __construct()
{
$this->next = $this->elem = $this->length = null;
}
/**
* 清空单链表
*
* @return mixed
*/
public function clearChain()
{
if ($this->length <= 0) {
return false;
}
while ($this->next != null) {
$q = $this->next->next;
$this->next = null;
unset($this->next);
$this->next = $q;
}
$this->length = 0;
}
/**
* 返回单链表长度
*
* @return mixed
*/
public function getLength()
{
return $this->length;
}
/**
* 判断单链表是否为空
*
* @return bool 为空返回true,不为空返回false
*/
public function getIsEmpty()
{
return $this->length == 0 && $this->next == null;
}
/**
* 头插入法建表
*
* @param array $arr 建立单链表的数据
* @return mixed
*/
protected function getHeadCreateChain(array $arr)
{
$this->clearChain();
$iterator = $this->generator($arr);
$iterator->rewind();
while ($iterator->valid()) {
$node = new stdClass();
$node->elem = $iterator->current();
$node->next = $this->next;
$this->next = $node;
$this->length++;
$iterator->next();
}
return $this->next;
}
/**
* 尾插入法建表
*
* @param array $arr 建立单链表的数据
* @return mixed
*/
protected function getTailCreateChain(array $arr)
{
$this->clearChain();
$pre_node = $this; // 上个节点指向头节点
$iterator = $this->generator($arr);
$iterator->rewind();
while ($iterator->valid()) {
$node = new stdClass();
$node->elem = $iterator->current();
$node->next = $pre_node->next; // $pre_node->next 指向null
$pre_node->next = $node; // $pre_node->next 上个节点的 下个节点 指向 这个节点
$pre_node = $node; // $pre_node 换为 这个节点
$iterator->next();
$this->length++;
}
return $this->next;
}
/**
* 返回第$i个元素,头插法实现
*
* @param int $i 元素位序,从1开始
* @return mixed
*/
protected function getElemForPos($i)
{
$i = (int)$i;
if ($i > $this->length || $i < 1) {
return null;
}
$mark = 1;
$self = $this->next;
while ($mark < $i) {
$box = $self->next;
$self = $box;
$mark++;
}
return $self;
}
/**
* 查找单链表中是否存在某个值的元素
* 如果有,返回该元素结点,否则返回null
*
* @param mixed $value 查找的值
* @return mixed
*/
protected function getElemIsExist($value)
{
$self = $this;
while ($self->next != null && strcmp($self->elem, $value) !== 0) {
$self = $self->next;
}
if (strcmp($self->elem, $value) === 0) {
return $self;
}
return null;
}
/**
* 查找单链表中是否存在某个值的元素
* 如果有,返回该元素位序,否则返回-1
*
* @param mixed $value 查找的值
* @return mixed
*/
protected function getElemPosition($value)
{
$self = $this;
$mark = 0;
while ($self->next != null && strcmp($self->elem, $value) !== 0) {
$self = $self->next;
$mark++;
}
if (strcmp($self->elem, $value) === 0) {
return $mark;
}
return -1;
}
/**
* 单链表的插入操作
*
* @param int $key 插入元素的位序,即在什么位置插入新的元素,从1开始
* @param mixed $value 插入的新的元素值
* @return boolean 插入成功返回true,失败返回false
*/
protected function getInsertElem($key, $value)
{
if ($key > $this->length || $key < 1) {
return false;
}
$mark = 1;
$self = $this;
while ($self->next != null && $mark < $key) {
$self = $self->next;
$mark++;
}
$node = new stdClass();
$node->elem = $value;
$node->next = $self->next;
$self->next = $node;
$this->length++;
return true;
}
/**
* 遍历单链表中的所有元素
*
* @return array 包括单链中的所有元素
*/
protected function getAllElem()
{
$result = array ();
if ($this->getIsEmpty()) {
return $result;
}
$self = $this->next;
while ($self->next != null) {
array_push($result, $self->elem);
$self = $self->next;
}
array_push($result, $self->elem);
return $result;
}
/**
* 根据Key 删除单链中的元素
*
* @param int $key 元素位序
* @return boolean 删除成功返回true,失败返回false
*/
protected function getDeleteElem($key)
{
$key = (int)$key;
if ($key > $this->length || $key < 1) {
return false;
}
$self = $this;
$mark = 1;
while ($mark < $key) {
$self = $self->next;
$mark++;
}
$node = $self->next;
$self->next = $node->next;
$this->length--;
return true;
}
/**
* 删除单链表中值为$value的前 $i($i>=1) 个结点
*
* @param mixed mixed 待查找的值
* @param $i mixed 删除的次数,即删除查找到的前$i个
* @return mixed
*/
protected function getDeleteElemForValue($value, $i = 1)
{
if ($i > 1) {
$this->getDeleteElemForValue($value, $i - 1);
}
$vp = $this->getElemPosition($value);
$this->getDeleteElem($vp);
return $this->getAllElem();
}
/**
* 删除单链表所有重复的值
*
* @return mixed
*/
protected function getElemUnique()
{
if ($this->getIsEmpty()) {
return $this->getAllElem();
}
$self = $this;
while ($self->next != null) {
$node = $self->next;
$ptr = $self;
while ($node->next != null) {
if (strcmp($self->elem, $node->elem) === 0) {
$ptr->next = $node->next;
unset($node->next);
$node = $ptr->next;
$this->length--;
} else {
$ptr = $node;
$node = $node->next;
}
}
$self = $self->next;
}
return $this->getAllElem();
}
/**
* 迭代器生产
*
* @param array $info
* @return \ArrayIterator
*/
protected function generator(array $info)
{
return (new ArrayObject($info))->getIterator();
}
/**
* 调试用请无视
*
* @param $name
* @param $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
$this->preDispatch(); // 调试用,请无视
return call_user_func_array(array ($this, $name), $arguments);
}
/**
* 调试用请无视!
*
* @param bool $isDebug
* @return bool
*/
protected function preDispatch($isDebug = true)
{
if (!$isDebug) {
return false;
}
$debug = debug_backtrace()[1];
$reflection = new ReflectionMethod($this, $debug['args'][0]);
$args = '';
if (isset($debug['args'][1])) {
foreach ($debug['args'][1] as &$value) {
if (is_array($value)) {
$args .= json_encode($debug['args'][1]) . ', ';
} else {
$args .= $value . ', ';
}
}
}
$args = trim($args, ', ');
echo "\t" . $reflection->getDocComment() . PHP_EOL;
echo "\t{$debug['args'][0]}({$args})\n" . PHP_EOL;
}
}
$echo = function ($str, $action) {
echo $str . "\t->\t" . var_export($action, true) . PHP_EOL;
echo "--------------------------- " . PHP_EOL;
};
$personal = array (
"One",
"Two",
"Three",
"Four",
"Five",
);
$oll = new LinearChain();
$echo('头插入链表数据', $oll->getHeadCreateChain($personal));
$echo('尾插入链表数据', $oll->getTailCreateChain($personal));
$echo('返回第二个数据', $oll->getElemForPos(2));
$echo('是否存在Tow呢?', $oll->getElemIsExist("Two"));
$echo('One 的下标示是', $oll->getElemPosition("One"));
$echo('从2号位插入一个Four', $oll->getInsertElem(2, "Four"));
$echo('遍历整个单链表', $oll->getAllElem());
$echo('删除第一个元素', $oll->getDeleteElem(1));
$echo('删除Three 前一个', $oll->getDeleteElemForValue("Three", 1));
$echo('去重链表中重复值', $oll->getElemUnique());
堆栈
栈(Stack):是限制在表的一端进行插入和删除操作的线性表。又称为后进先出LIFO (Last In First Out)或先进后出FILO (First In Last Out)线性表。
<?php
/**
* -------------------------------------------------------------
* [栈的定义]
* =======
* 栈(Stack):是限制在表的一端进行插入和删除操作的线性表。又称为后进先出LIFO (Last In First Out)或先进后出FILO (First In Last Out)线性表。
* 栈顶(Top):允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。
* 栈底(Bottom):是固定端,又称为表头。
* 空栈:当表中没有元素时称为空栈。
* [栈的实现方式]
* =======
* - 硬堆栈:利用CPU中的某些寄存器组或类似的硬件或使用内存的特殊区域来实现。这类堆栈容量有限,但速度很快;
* - 软堆栈:这类堆栈主要在内存中实现。堆栈容量可以达到很大。在实现方式上,又有动态方式和静态方式两种
* -------------------------------------------------------------
* [定义]
* =======
* 线性表(Linear List) :是由n(n≧0)个数据元素(结点) [a1,a2, …an] 组成的有限序列。数据元素是一个抽象的符号,其具体含义在不同的情况下一般不同。
* 该序列中的所有结点具有相同的数据类型。其中数据元素的个数n称为线性表的长度。
* 当n=0时,称为空表。
* 当n>0时,将非空的线性表记作: (a1,a2,…an) a1称为线性表的第一个(首)结点,an称为线性表的最后一个(尾)结点。
* -------------------------------------------------------------
* [线性表顺序存储]
* =======
* 把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里,用这种方法存储的线性表简称线性表。
* -------------------------------------------------------------
* [顺序存储的线性表的特点]
* =======
* - 线性表的逻辑顺序与物理顺序一致;
* - 数据元素之间的关系是以元素在计算机内“物理位置相邻”来体现。
* -------------------------------------------------------------
* @param array
*/
class StackExample
{
/**
* @var null 栈元素
*/
protected $elem;
/**
* @var null 下一个节点
*/
protected $next;
/**
* @var int 栈长度
*/
protected $length;
/**
* 初始化栈
* StackExample constructor.
*/
public function __construct()
{
$this->elem = $this->next = null;
$this->length = 0;
}
/**
* 判断栈是否空栈
*
* @return boolean 如果为空栈返回true,否则返回false
*/
protected function getIsEmpty()
{
return $this->elem ? false : true;
}
/**
* 将所有元素出栈
*
* @return array 返回所有栈内元素
*/
protected function getAllPopStack()
{
$result = array ();
if ($this->getIsEmpty()) {
return $result;
}
while ($this->elem != null) {
$result[] = $this->elem->elem;
$this->elem = $this->elem->next;
}
$this->length = 0;
return $result;
}
/**
* 返回栈内元素个数
*
* @return int
*/
protected function getLength()
{
return $this->length;
}
/**
* 元素进栈
*
* @param mixed $element 进栈元素值
* @return void
**/
protected function setPushStack($element)
{
$stack = new stdClass();
$stack->elem = $element;
$stack->next = $this->elem;
$this->elem = &$stack;
$this->length++;
}
/**
* 元素出栈
*
* @return boolean 出栈成功返回true,否则返回false
**/
protected function getPopStack()
{
if ($this->getIsEmpty()) {
return false;
}
$node = $this->elem;
$this->elem = $node->next;
$this->length--;
return $node;
}
/**
* 仅返回栈内所有元素
*
* @return array 栈内所有元素组成的一个数组
*/
protected function getAllElem()
{
$result = array ();
if ($this->getIsEmpty()) {
return $result;
}
$node = $this->elem;
while ($node != null) {
$result[] = $node->elem;
$node = $node->next;
}
return $result;
}
/**
* 返回栈内某个元素的个数
*
* @param mixed $elem 待查找的元素的值
* @return int
**/
protected function getCountForElem($elem)
{
$result = $this->getAllElem();
$count = 0;
foreach ($result as $value) {
if ($elem === $value) {
$count++;
}
}
return $count;
}
/**
* 调试用请无视
*
* @param $name
* @param $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
$this->preDispatch(); // 调试用,请无视
return call_user_func_array(array ($this, $name), $arguments);
}
/**
* 调试用
*
* @param bool $isDebug
* @return bool
*/
protected function preDispatch($isDebug = true)
{
if (!$isDebug) {
return false;
}
$debug = debug_backtrace()[1];
$reflection = new ReflectionMethod($this, $debug['args'][0]);
$args = '';
if (isset($debug['args'][1])) {
foreach ($debug['args'][1] as &$value) {
if (is_array($value)) {
$args .= json_encode($debug['args'][1]) . ', ';
} else {
$args .= $value . ', ';
}
}
}
$args = trim($args, ', ');
echo "\t" . $reflection->getDocComment() . PHP_EOL;
echo "\t{$debug['args'][0]}({$args})\n" . PHP_EOL;
}
}
$echo = function ($str, $action) {
echo $str . "\t->\t" . var_export($action, true) . PHP_EOL;
echo "--------------------------- " . PHP_EOL;
};
调用:
$stack = new StackExample();
$stack->setPushStack('First');
$stack->setPushStack('Second');
$echo('返回栈内所有元素', $stack->getAllElem());
$stack->setPushStack('Third');
$echo('返回栈内所有元素', $stack->getAllElem());
$stack->getPopStack();
$echo('返回栈内所有元素', $stack->getAllElem());
输出:
返回栈内所有元素 -> array (
0 => 'Second',
1 => 'First',
)
---------------------------
返回栈内所有元素 -> array (
0 => 'Third',
1 => 'Second',
2 => 'First',
)
---------------------------
返回栈内所有元素 -> array (
0 => 'Second',
1 => 'First',
)
---------------------------
我们也可以使用php的Spl标准库的SplStack类实现栈。
SplStack类通过使用一个双向链表(SplDoublyLinkedList)来提供栈的主要功能。
<?php
//SplStack Mode is LIFO (Last In First Out)
$q = new SplStack();
$q[] = 1;
$q[] = 2;
$q[] = 3;
$q->push(4);
$q->add(4,5);
$q->rewind();
while($q->valid()){
echo $q->current(),"\n";
$q->next();
}
?>
输出:
5
4
3
2
1
<?php
/**
* KitchenQueue
* -------------------------------------------------------------
* [游戏说明]
* 假设你要为饭店创建一个接受顾客点菜单点应用程序,这个应用程序存储一系列点菜服务,服务员添加菜单,
* 而厨师取出菜单并制作菜肴
* -------------------------------------------------------------
*
* @license MIT
*/
class KitchenQueue
{
/**
* @var \stdClass $cooking
*/
protected $cooking;
/**
* 服务员
*
* @param $dishes
*/
public function waiter($dishes)
{
$node = new \stdClass();
$node->element = $dishes;
$node->next = $this->cooking;
$this->cooking = $node;
}
/**
* 厨师
*
* @return \stdClass
*/
public function kitchen()
{
return $this->cooking;
}
}
$kitchen = new KitchenQueue();
$kitchen->waiter("Qin Jiao Rou Si");
$kitchen->waiter("Ma Po Dou Fu");
$kitchen->waiter("Fu Qi Fei Pian");
$kitchen->waiter("Kou Shui Ji");
var_dump($kitchen->kitchen());
参考资料
PHP 手册 函数参考 变量与类型相关扩展 数组 数组 函数 https://www.php.net/manual/zh/ref.array.php
用 PHP 的方式实现的各类算法合集 https://github.com/m9rco/algorithm-php
PHP实现八大算法 https://www.cnblogs.com/zixuanfy/p/7617451.html
PHP的基本算法合集 https://www.php.cn/php-weizijiaocheng-394062.html
PHP算法 https://www.jianshu.com/p/cb2ad99029c8
php数据结构和算法 https://www.csdn.net/gather_21/MtTacg3sMzkxNy1ibG9n.html
七大常用PHP算法 http://www.sohu.com/a/118661179_468191
堆排序算法与PHP实现 https://www.cnblogs.com/iampeter/p/3223487.html
PHP实现排序算法—-堆排序(Heap Sort) https://blog.csdn.net/baidu_30000217/article/details/53087079
PHP实现堆排序 https://www.cnblogs.com/zhenbianshu/p/5273995.html
哪本《数据结构与算法》最好? https://www.zhihu.com/question/21628833/answer/54623559
数据结构与算法必备的 50 个代码实现 https://zhuanlan.zhihu.com/p/67490380
常见数据结构与算法整理总结(上) https://www.cnblogs.com/xkzhangsanx/p/10888179.html
PHP实现各种经典算法 http://www.cnblogs.com/hellohell/p/5718175.html
php面试题之二——数据结构和算法(高级部分) https://blog.csdn.net/s1070/article/details/51174725
阮一峰 字符串匹配的KMP算法 http://www.ruanyifeng.com/blog/2013/05/Knuth–Morris–Pratt_algorithm.html
从头到尾彻底理解 KMP https://wiki.jikexueyuan.com/project/kmp-algorithm/
KMP算法—终于全部弄懂了 https://blog.csdn.net/dark_cy/article/details/88698736
PHP 手册 函数参考 其它基本扩展 SPL 数据结构 The SplStack class https://www.php.net/manual/zh/class.splstack.php