SplDoublyLinkedList源码
<?php
/**
 * PS:关于预定义接口Iterator, ArrayAccess, Countable的文章已经介绍过了,不认识的可以往前翻翻
 */
class SplDoublyLinkedList implements Iterator, ArrayAccess, Countable
{
    /** 
     * @var _llist 定义一个数组用于存放数据
     */
    protected $_llist   = array();
 
    /** 
     * @var _it_mode 链表的迭代模式
     */
    protected $_it_mode = 0;
 
    /** 
     * @var _it_pos 链表指针
     */
    protected $_it_pos  = 0;
    /** 
     * 迭代模式
     * @see setIteratorMode
     */
    const IT_MODE_LIFO     = 0x00000002;
    const IT_MODE_FIFO     = 0x00000000;
    const IT_MODE_KEEP     = 0x00000000;
    const IT_MODE_DELETE   = 0x00000001;
 
    /** 
     * @return 返回被移出尾部节点元素
     * @throw RuntimeException 如果链表为空则抛出异常
     */
    public function pop()
    {
        if (count($this->_llist) == 0) {
            throw new RuntimeException("Can't pop from an empty datastructure");
        }
        return array_pop($this->_llist);
    }
 
    /** 
     * @return 返回被移出头部节点元素
     * @throw RuntimeException 如果链表为空则抛出异常
     */
    public function shift()
    {
        if (count($this->_llist) == 0) {
            throw new RuntimeException("Can't shift from an empty datastructure");
        }
        return array_shift($this->_llist);
    }
 
    /** 
     * 往链表尾部添加一个节点元素
     * @param $data 要添加的节点元素
     */
    public function push($data)
    {
        array_push($this->_llist, $data);
        return true;
    }
 
    /** 
     * 往链表头部添加一个节点元素
     * @param $data 要添加的节点元素
     */
    public function unshift($data)
    {
        array_unshift($this->_llist, $data);
        return true;
    }
 
    /** 
     * @return 返回尾部节点元素,并把指针指向尾部节点元素
     */
    public function top()
    {
        return end($this->_llist);
    }
 
    /** 
     * @return 返回头部节点元素,并把指针指向头部节点元素
     */
    public function bottom()
    {
        return reset($this->_llist);
    }
 
    /** 
     * @return 返回链表节点数
     */
    public function count()
    {
        return count($this->_llist);
    }
 
    /** 
     * @return 判断链表是否为空
     */
    public function isEmpty()
    {
        return ($this->count() == 0);
    }
    /** 
     * 设置迭代模式
     * - 迭代的顺序 (先进先出、后进先出)
     *  - SplDoublyLnkedList::IT_MODE_LIFO (堆栈)
     *  - SplDoublyLnkedList::IT_MODE_FIFO (队列)
     *
     * - 迭代过程中迭代器的行为
     *  - SplDoublyLnkedList::IT_MODE_DELETE (删除已迭代的节点元素)
     *  - SplDoublyLnkedList::IT_MODE_KEEP   (保留已迭代的节点元素)
     *
     * 默认的模式是 0 : SplDoublyLnkedList::IT_MODE_FIFO | SplDoublyLnkedList::IT_MODE_KEEP
     *
     * @param $mode 新的迭代模式
     */
    public function setIteratorMode($mode)
    {
        $this->_it_mode = $mode;
    }
 
    /** 
     * @return 返回当前的迭代模式
     * @see setIteratorMode
     */
    public function getIteratorMode()
    {
        return $this->_it_mode;
    }
 
    /** 
     * 重置节点指针
     */
    public function rewind()
    {
        if ($this->_it_mode & self::IT_MODE_LIFO) {
            $this->_it_pos = count($this->_llist)-1;
        } else {
            $this->_it_pos = 0;
        }
    }
 
    /** 
     * @return 判断指针对应的节点元素是否存在
     */
    public function valid()
    {
        return array_key_exists($this->_it_pos, $this->_llist);
    }
 
    /** 
     * @return 返回当前指针的偏移位置
     */
    public function key()
    {
        return $this->_it_pos;
    }
 
    /** 
     * @return 返回当前指针对应的节点元素
     */
    public function current()
    {
        return $this->_llist[$this->_it_pos];
    }
 
    /** 
     * 将指针向前移动一个偏移位置
     */
    public function next()
    {
        if ($this->_it_mode & self::IT_MODE_LIFO) {
            if ($this->_it_mode & self::IT_MODE_DELETE) {
                $this->pop();
            }
            $this->_it_pos--;
        } else {
            if ($this->_it_mode & self::IT_MODE_DELETE) {
                $this->shift();
            } else {
                $this->_it_pos++;
            }
        }
    }
    /** 
     * @return 偏移位置是否存在
     *
     * @param $offset             偏移位置
     * @throw OutOfRangeException 如果偏移位置超出范围或者无效则抛出异常
     */
    public function offsetExists($offset)
    {
        if (!is_numeric($offset)) {
            throw new OutOfRangeException("Offset invalid or out of range");
        } else {
            return array_key_exists($offset, $this->_llist);
        }
    }
 
    /** 
     * @return 获取偏移位置对应的值
     *
     * @param $offset             偏移位置
     * @throw OutOfRangeException 如果偏移位置超出范围或者无效则抛出异常
     */
    public function offsetGet($offset)
    {
        if ($this->_it_mode & self::IT_MODE_LIFO) {
            $realOffset = count($this->_llist)-$offset;
        } else {
            $realOffset = $offset;
        }
        if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) {
            throw new OutOfRangeException("Offset invalid or out of range");
        } else {
            return $this->_llist[$realOffset];
        }
    }
 
    /** 
     * @return 设置偏移位置对应的值
     *
     * @param $offset             偏移位置
     * @throw OutOfRangeException 如果偏移位置超出范围或者无效则抛出异常
     */
    public function offsetSet($offset, $value)
    {
        if ($offset === null) {
            return $this->push($value);
        }
        if ($this->_it_mode & self::IT_MODE_LIFO) {
            $realOffset = count($this->_llist)-$offset;
        } else {
            $realOffset = $offset;
        }
        if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) {
            throw new OutOfRangeException("Offset invalid or out of range");
        } else {
            $this->_llist[$realOffset] = $value;
        }
    }
 
    /** 
     * @return 删除偏移位置对应的值
     *
     * @param $offset             偏移位置
     * @throw OutOfRangeException 如果偏移位置超出范围或者无效则抛出异常
     */
    public function offsetUnset($offset)
    {
        if ($this->_it_mode & self::IT_MODE_LIFO) {
            $realOffset = count($this->_llist)-$offset;
        } else {
            $realOffset = $offset;
        }
        if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) {
            throw new OutOfRangeException("Offset invalid or out of range");
        } else {
            array_splice($this->_llist, $realOffset, 1);
        }
    }
}
?>

  示例:

<?php

/**
 * Spl php标准库
 * 双向链 
 * @author Yel
 * @date 2021-4-14
 */

 //创建一个 SplDoulyLinkedList 对象
 $SplDoulyLinkedList = new SplDoublyLinkedList();

 //查看对象内容
 var_dump( $SplDoulyLinkedList);
 //输出
//  object(SplDoublyLinkedList)#1 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(0) {
//     }
//   }
  

 // 向对象中添加 A B 两个 数据  add:  (PHP 5 >= 5.5.0, PHP 7)
 $SplDoulyLinkedList->add(0,'A');  //在指定的索引处添加/插入新值   超出范围报错  默认从 0 开始
 $SplDoulyLinkedList->add(1,'B');
 $SplDoulyLinkedList->add(2,'C');
//查看对象内容
var_dump( $SplDoulyLinkedList);
//输出
// object(SplDoublyLinkedList)#1 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(3) {
//       [0]=>
//       string(1) "A"
//       [1]=>
//       string(1) "B"
//       [2]=>
//       string(1) "C"
//     }
//   }

//遍历该对象
foreach ($SplDoulyLinkedList as $key => $value) {
    var_dump("$key  => $value"); 
}
//输出
// string(7) "0  => A"
// string(7) "1  => B"
// string(7) "2  => C"

//查看
echo "<br>" . $SplDoulyLinkedList->bottom(); //查看 SplDoulyLinkedList 对象 开头节点的值      只是查看   输出  A
echo "<br>" . $SplDoulyLinkedList->top();    //查看 SplDoulyLinkedList 对象 最末节点的值      只是查看   输出  C
echo "<br>" . $SplDoulyLinkedList->count();  //查看 SplDoulyLinkedList 对象 当前元素数量      只是查看   输出  3

echo "<br>current:" . $SplDoulyLinkedList->current();//查看 SplDoulyLinkedList 对象 当前节点元素      输出NULL   必须使用 $SplDoulyLinkedList->rewind()把迭代器放到起点
echo "<br>" . $SplDoulyLinkedList->rewind(); // 将 SplDoulyLinkedList 对象迭代器倒回开始 
echo "<br>" . $SplDoulyLinkedList->current();// 输出 A 
echo "<br>" . $SplDoulyLinkedList->next();  // 将 节点移向下一个元素  无输出
echo "<br>" . $SplDoulyLinkedList->current();//  输出 B 
echo "<br>" . $SplDoulyLinkedList->rewind(); // 重置节点
echo "<br>" . $SplDoulyLinkedList->current();// 输出 A
echo "<br>" . $SplDoulyLinkedList->next();  // 将 节点移向下一个元素  无输出
echo "<br>" . $SplDoulyLinkedList->prev();  // 将 节点移向上一个元素  无输出
echo "<br>" . $SplDoulyLinkedList->current();// 输出 A

echo "<br>" . $SplDoulyLinkedList->key();// 输出SplDoulyLinkedList 对象 当前节点  输出 0


//检测
echo "<br>" ;
var_dump($SplDoulyLinkedList->isEmpty());  //检测 SplDoulyLinkedList 对象 是否为空 输出 false
var_dump($SplDoulyLinkedList->valid());    //检测 SplDoulyLinkedList 对象 当前节点是否有效 输出 true

//输出  SplDoulyLinkedList对象所有元素 
echo '<br>输出 所有元素 :';
$SplDoulyLinkedList->rewind(); //先把节点调回第一位
while(1){
    //检测为空 或者 节点无效时退出
    if($SplDoulyLinkedList->isEmpty() || !$SplDoulyLinkedList->valid()){
        break;
    }
    //输出当前节点 与 对应 元素
    echo "<br>" . $SplDoulyLinkedList->key() . " => " . $SplDoulyLinkedList->current() ;
    $SplDoulyLinkedList->next();
}
// 输出 所有元素 :
// 0 => A
// 1 => B
// 2 => C

//查看对象内容
echo "<br>" ;
var_dump( $SplDoulyLinkedList);
//输出
// object(SplDoublyLinkedList)#1 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(3) {
//       [0]=>
//       string(1) "A"
//       [1]=>
//       string(1) "B"
//       [2]=>
//       string(1) "C"
//     }
//   }


// 在对象中弹出一个元素
echo "<br>" . $SplDoulyLinkedList->shift();  //从双链表的开头移出一个节点     输出 A 
echo "<br>" . $SplDoulyLinkedList->pop();    //从双链表的末尾移出一个节点     输出 C

echo "<br>" . $SplDoulyLinkedList->unshift("D");  //从双链表的开头插入一个节点  输出 true
echo "<br>" . $SplDoulyLinkedList->unshift("E");  //从双链表的开头插入一个节点  输出 true

echo "<br>" . $SplDoulyLinkedList->push("F");  //从双链表的末尾添加一个节点    输出 true
echo "<br>" . $SplDoulyLinkedList->push("G");  //从双链表的末尾添加一个节点    输出 true

//查看对象内容
echo "<br>" ;
var_dump( $SplDoulyLinkedList);
//输出
// object(SplDoublyLinkedList)#1 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(5) {
//       [0]=>
//       string(1) "E"
//       [1]=>
//       string(1) "D"
//       [2]=>
//       string(1) "B"
//       [3]=>
//       string(1) "F"
//       [4]=>
//       string(1) "G"
//     }
//   }


//自带 序列化 与反序列化

//序列化 
$SplDoulyLinkedList_serialize = $SplDoulyLinkedList->serialize();
var_dump($SplDoulyLinkedList_serialize); //string(49) "i:0;:s:1:"E";:s:1:"D";:s:1:"B";:s:1:"F";:s:1:"G";"
//反序列化
$List = new SplDoublyLinkedList();
$List->unserialize($SplDoulyLinkedList_serialize);
var_dump($List); 
//输出
// object(SplDoublyLinkedList)#2 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(5) {
//       [0]=>
//       string(1) "E"
//       [1]=>
//       string(1) "D"
//       [2]=>
//       string(1) "B"
//       [3]=>
//       string(1) "F"
//       [4]=>
//       string(1) "G"
//     }
//   }

echo "<br>" ;
echo "<br>" ;

// 序列化函数
$serialize = serialize($SplDoulyLinkedList);
var_dump($serialize);  //string(81) "C:19:"SplDoublyLinkedList":49:{i:0;:s:1:"E";:s:1:"D";:s:1:"B";:s:1:"F";:s:1:"G";}"
$List = unserialize($serialize);
var_dump($List); 
//输出
// object(SplDoublyLinkedList)#3 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(5) {
//       [0]=>
//       string(1) "E"
//       [1]=>
//       string(1) "D"
//       [2]=>
//       string(1) "B"
//       [3]=>
//       string(1) "F"
//       [4]=>
//       string(1) "G"
//     }
//   }


echo "<br>" ;
echo "<br>" ;

echo "<br>" . $List->offsetGet(2);  // 获取 指定节点的元素
echo "<br>" . $List->offsetSet(2, "Z");  // 将指定节点 的元素 替换 位 特定值  无输出
echo "<br>" . $List->offsetSet(3, "Z");  //  将指定节点 的元素 替换 位 特定值 无输出
var_dump($List); 
//输出
// object(SplDoublyLinkedList)#3 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(5) {
//       [0]=>
//       string(1) "E"
//       [1]=>
//       string(1) "D"
//       [2]=>
//       string(1) "Z"
//       [3]=>
//       string(1) "Z"
//       [4]=>
//       string(1) "G"
//     }
//   }

echo "<br>" . $List->offsetUnset(1);  //删除指定节点元素 ,并且重新制定节点键值
echo "<br>" ;
var_dump($List); 
//输出
// object(SplDoublyLinkedList)#3 (2) {
//     ["flags":"SplDoublyLinkedList":private]=>
//     int(0)
//     ["dllist":"SplDoublyLinkedList":private]=>
//     array(4) {
//       [0]=>
//       string(1) "E"
//       [1]=>
//       string(1) "Z"
//       [2]=>
//       string(1) "Z"
//       [3]=>
//       string(1) "G"
//     }
//   }


//(PHP 5> = 5.3.0,PHP 7)
echo "<br>" . $List->offsetExists(7);  // 检测指定 节点是否存在  输出  false
echo "<br>" ;
var_dump($List); 

  

posted on 2021-04-14 10:07  narwhalYel  阅读(101)  评论(0)    收藏  举报